建立檔案

This commit is contained in:
2025-08-05 08:22:44 +08:00
commit 042d03aff7
122 changed files with 34763 additions and 0 deletions

View File

@@ -0,0 +1,477 @@
"use client"
import { useState } from "react"
import { useAuth } from "@/contexts/auth-context"
import { useCompetition } from "@/contexts/competition-context"
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Textarea } from "@/components/ui/textarea"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Checkbox } from "@/components/ui/checkbox"
import { Badge } from "@/components/ui/badge"
import { Progress } from "@/components/ui/progress"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Separator } from "@/components/ui/separator"
import { ChevronLeft, ChevronRight, Trophy, Users, FileText, CheckCircle, Target, Award, Loader2 } from "lucide-react"
interface RegistrationDialogProps {
open: boolean
onOpenChange: (open: boolean) => void
}
interface RegistrationData {
// 應用資訊
appName: string
appDescription: string
appType: string
techStack: string
mainFeatures: string
// 團隊資訊
teamName: string
teamSize: string
contactName: string
contactEmail: string
contactPhone: string
department: string
// 參賽動機
motivation: string
expectedOutcome: string
agreeTerms: boolean
}
export function RegistrationDialog({ open, onOpenChange }: RegistrationDialogProps) {
const { user } = useAuth()
const { currentCompetition } = useCompetition()
const [currentStep, setCurrentStep] = useState(1)
const [isSubmitting, setIsSubmitting] = useState(false)
const [isSubmitted, setIsSubmitted] = useState(false)
const [applicationId, setApplicationId] = useState("")
const [formData, setFormData] = useState<RegistrationData>({
appName: "",
appDescription: "",
appType: "",
techStack: "",
mainFeatures: "",
teamName: "",
teamSize: "1",
contactName: user?.name || "",
contactEmail: user?.email || "",
contactPhone: "",
department: "",
motivation: "",
expectedOutcome: "",
agreeTerms: false,
})
const totalSteps = 3
const progress = (currentStep / totalSteps) * 100
const handleInputChange = (field: keyof RegistrationData, value: string | boolean) => {
setFormData((prev) => ({ ...prev, [field]: value }))
}
const validateStep = (step: number): boolean => {
switch (step) {
case 1:
return !!(formData.appName && formData.appDescription && formData.appType && formData.techStack)
case 2:
return !!(formData.teamName && formData.contactName && formData.contactEmail && formData.department)
case 3:
return !!(formData.motivation && formData.agreeTerms)
default:
return false
}
}
const handleNext = () => {
if (validateStep(currentStep) && currentStep < totalSteps) {
setCurrentStep((prev) => prev + 1)
}
}
const handlePrevious = () => {
if (currentStep > 1) {
setCurrentStep((prev) => prev - 1)
}
}
const handleSubmit = async () => {
if (!validateStep(3)) return
setIsSubmitting(true)
// 模擬提交過程
await new Promise((resolve) => setTimeout(resolve, 2000))
// 生成申請編號
const id = `REG${Date.now().toString().slice(-6)}`
setApplicationId(id)
setIsSubmitted(true)
setIsSubmitting(false)
}
const handleClose = () => {
if (isSubmitted) {
// 重置表單
setCurrentStep(1)
setIsSubmitted(false)
setApplicationId("")
setFormData({
appName: "",
appDescription: "",
appType: "",
techStack: "",
mainFeatures: "",
teamName: "",
teamSize: "1",
contactName: user?.name || "",
contactEmail: user?.email || "",
contactPhone: "",
department: "",
motivation: "",
expectedOutcome: "",
agreeTerms: false,
})
}
onOpenChange(false)
}
const renderStepContent = () => {
if (isSubmitted) {
return (
<div className="text-center py-8">
<div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
<CheckCircle className="w-8 h-8 text-green-600" />
</div>
<h3 className="text-xl font-semibold text-gray-900 mb-2"></h3>
<p className="text-gray-600 mb-4"></p>
<div className="bg-gray-50 rounded-lg p-4 mb-6">
<p className="text-sm text-gray-600 mb-1"></p>
<p className="text-lg font-mono font-semibold text-gray-900">{applicationId}</p>
</div>
<div className="text-sm text-gray-500 space-y-1">
<p> 3-5 </p>
<p> </p>
<p> </p>
</div>
</div>
)
}
switch (currentStep) {
case 1:
return (
<div className="space-y-6">
<div className="text-center mb-6">
<FileText className="w-12 h-12 text-blue-600 mx-auto mb-3" />
<h3 className="text-lg font-semibold"></h3>
<p className="text-sm text-gray-600"> AI </p>
</div>
<div className="space-y-4">
<div>
<Label htmlFor="appName"> *</Label>
<Input
id="appName"
value={formData.appName}
onChange={(e) => handleInputChange("appName", e.target.value)}
placeholder="請輸入應用名稱"
/>
</div>
<div>
<Label htmlFor="appDescription"> *</Label>
<Textarea
id="appDescription"
value={formData.appDescription}
onChange={(e) => handleInputChange("appDescription", e.target.value)}
placeholder="請簡要描述您的應用功能和特色"
rows={3}
/>
</div>
<div>
<Label htmlFor="appType"> *</Label>
<Select value={formData.appType} onValueChange={(value) => handleInputChange("appType", value)}>
<SelectTrigger>
<SelectValue placeholder="選擇應用類型" />
</SelectTrigger>
<SelectContent>
<SelectItem value="文字處理"></SelectItem>
<SelectItem value="圖像生成"></SelectItem>
<SelectItem value="語音辨識"></SelectItem>
<SelectItem value="推薦系統"></SelectItem>
<SelectItem value="數據分析"></SelectItem>
<SelectItem value="自動化工具"></SelectItem>
<SelectItem value="其他"></SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="techStack"> *</Label>
<Input
id="techStack"
value={formData.techStack}
onChange={(e) => handleInputChange("techStack", e.target.value)}
placeholder="例如Python, TensorFlow, React, Node.js"
/>
</div>
<div>
<Label htmlFor="mainFeatures"></Label>
<Textarea
id="mainFeatures"
value={formData.mainFeatures}
onChange={(e) => handleInputChange("mainFeatures", e.target.value)}
placeholder="請列出應用的主要功能特色"
rows={2}
/>
</div>
</div>
</div>
)
case 2:
return (
<div className="space-y-6">
<div className="text-center mb-6">
<Users className="w-12 h-12 text-green-600 mx-auto mb-3" />
<h3 className="text-lg font-semibold"></h3>
<p className="text-sm text-gray-600"></p>
</div>
<div className="space-y-4">
<div>
<Label htmlFor="teamName"> *</Label>
<Input
id="teamName"
value={formData.teamName}
onChange={(e) => handleInputChange("teamName", e.target.value)}
placeholder="請輸入團隊名稱"
/>
</div>
<div>
<Label htmlFor="teamSize"></Label>
<Select value={formData.teamSize} onValueChange={(value) => handleInputChange("teamSize", value)}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">1 </SelectItem>
<SelectItem value="2">2 </SelectItem>
<SelectItem value="3">3 </SelectItem>
<SelectItem value="4">4 </SelectItem>
<SelectItem value="5+">5 </SelectItem>
</SelectContent>
</Select>
</div>
<Separator />
<div>
<Label htmlFor="contactName"> *</Label>
<Input
id="contactName"
value={formData.contactName}
onChange={(e) => handleInputChange("contactName", e.target.value)}
placeholder="請輸入聯絡人姓名"
/>
</div>
<div>
<Label htmlFor="contactEmail"> *</Label>
<Input
id="contactEmail"
type="email"
value={formData.contactEmail}
onChange={(e) => handleInputChange("contactEmail", e.target.value)}
placeholder="請輸入聯絡人信箱"
/>
</div>
<div>
<Label htmlFor="contactPhone"></Label>
<Input
id="contactPhone"
value={formData.contactPhone}
onChange={(e) => handleInputChange("contactPhone", e.target.value)}
placeholder="請輸入聯絡電話"
/>
</div>
<div>
<Label htmlFor="department"> *</Label>
<Select value={formData.department} onValueChange={(value) => handleInputChange("department", value)}>
<SelectTrigger>
<SelectValue placeholder="選擇所屬部門" />
</SelectTrigger>
<SelectContent>
<SelectItem value="HQBU">HQBU</SelectItem>
<SelectItem value="ITBU">ITBU</SelectItem>
<SelectItem value="MBU1">MBU1</SelectItem>
<SelectItem value="SBU">SBU</SelectItem>
<SelectItem value="其他"></SelectItem>
</SelectContent>
</Select>
</div>
</div>
</div>
)
case 3:
return (
<div className="space-y-6">
<div className="text-center mb-6">
<Target className="w-12 h-12 text-purple-600 mx-auto mb-3" />
<h3 className="text-lg font-semibold"></h3>
<p className="text-sm text-gray-600"></p>
</div>
<div className="space-y-4">
<div>
<Label htmlFor="motivation"> *</Label>
<Textarea
id="motivation"
value={formData.motivation}
onChange={(e) => handleInputChange("motivation", e.target.value)}
placeholder="請分享您參加此次競賽的動機和期望"
rows={3}
/>
</div>
<div>
<Label htmlFor="expectedOutcome"></Label>
<Textarea
id="expectedOutcome"
value={formData.expectedOutcome}
onChange={(e) => handleInputChange("expectedOutcome", e.target.value)}
placeholder="您希望通過此次競賽達成什麼目標?"
rows={2}
/>
</div>
{/* 競賽資訊確認 */}
<Card>
<CardHeader className="pb-3">
<CardTitle className="text-base flex items-center space-x-2">
<Trophy className="w-4 h-4 text-yellow-600" />
<span></span>
</CardTitle>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex justify-between items-center">
<span className="text-sm text-gray-600"></span>
<span className="text-sm font-medium">{currentCompetition?.name}</span>
</div>
<div className="flex justify-between items-center">
<span className="text-sm text-gray-600"></span>
<span className="text-sm font-medium">
{currentCompetition?.year}{currentCompetition?.month}
</span>
</div>
<div className="flex justify-between items-center">
<span className="text-sm text-gray-600"></span>
<Badge variant="secondary" className="bg-green-100 text-green-800">
{currentCompetition?.status === "active" ? "進行中" : "即將開始"}
</Badge>
</div>
</CardContent>
</Card>
{/* 條款同意 */}
<div className="flex items-start space-x-2">
<Checkbox
id="agreeTerms"
checked={formData.agreeTerms}
onCheckedChange={(checked) => handleInputChange("agreeTerms", checked as boolean)}
/>
<Label htmlFor="agreeTerms" className="text-sm leading-relaxed">
使
</Label>
</div>
</div>
</div>
)
default:
return null
}
}
return (
<Dialog open={open} onOpenChange={handleClose}>
<DialogContent className="sm:max-w-2xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle className="flex items-center space-x-2">
<Trophy className="w-5 h-5 text-yellow-600" />
<span></span>
</DialogTitle>
<DialogDescription>{currentCompetition?.name}</DialogDescription>
</DialogHeader>
{!isSubmitted && (
<div className="mb-6">
<div className="flex items-center justify-between mb-2">
<span className="text-sm text-gray-600">
{currentStep} / {totalSteps}
</span>
<span className="text-sm text-gray-600">{Math.round(progress)}%</span>
</div>
<Progress value={progress} className="h-2" />
</div>
)}
<div className="min-h-[400px]">{renderStepContent()}</div>
{!isSubmitted && (
<div className="flex justify-between pt-6 border-t">
<Button variant="outline" onClick={handlePrevious} disabled={currentStep === 1}>
<ChevronLeft className="w-4 h-4 mr-2" />
</Button>
{currentStep < totalSteps ? (
<Button onClick={handleNext} disabled={!validateStep(currentStep)}>
<ChevronRight className="w-4 h-4 ml-2" />
</Button>
) : (
<Button
onClick={handleSubmit}
disabled={!validateStep(3) || isSubmitting}
className="bg-gradient-to-r from-orange-600 to-yellow-600 hover:from-orange-700 hover:to-yellow-700"
>
{isSubmitting ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
...
</>
) : (
<>
<Award className="w-4 h-4 mr-2" />
</>
)}
</Button>
)}
</div>
)}
{isSubmitted && (
<div className="flex justify-center pt-6 border-t">
<Button onClick={handleClose} className="w-full">
</Button>
</div>
)}
</DialogContent>
</Dialog>
)
}