Files
ai-showcase-platform/components/competition/registration-dialog.tsx
2025-09-09 18:18:02 +08:00

484 lines
18 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"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>
<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>
)
}