新增資料庫架構

This commit is contained in:
2025-07-19 02:12:37 +08:00
parent e3832acfa8
commit 924f03c3d7
45 changed files with 12858 additions and 324 deletions

View File

@@ -11,10 +11,15 @@ import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Textarea } from "@/components/ui/textarea"
import { Checkbox } from "@/components/ui/checkbox"
import { Sparkles, ArrowLeft, Send, BarChart3, Eye, EyeOff, Shield, Info } from "lucide-react"
import { Sparkles, ArrowLeft, Send, BarChart3, Eye, EyeOff, Shield, Info, Mail, ImageIcon } from "lucide-react"
import { useToast } from "@/hooks/use-toast"
import { soundManager } from "@/lib/sound-effects"
import HeaderMusicControl from "@/components/header-music-control"
import { moderateWishForm, type ModerationResult } from "@/lib/content-moderation"
import ContentModerationFeedback from "@/components/content-moderation-feedback"
import ImageUpload from "@/components/image-upload"
import type { ImageFile } from "@/lib/image-utils"
import { WishService } from "@/lib/supabase-service"
export default function SubmitPage() {
const [formData, setFormData] = useState({
@@ -22,11 +27,15 @@ export default function SubmitPage() {
currentPain: "",
expectedSolution: "",
expectedEffect: "",
isPublic: true, // 預設為公開
isPublic: true,
email: "",
})
const [images, setImages] = useState<ImageFile[]>([])
const [isSubmitting, setIsSubmitting] = useState(false)
const { toast } = useToast()
const router = useRouter()
const [moderationResult, setModerationResult] = useState<ModerationResult | null>(null)
const [showModerationFeedback, setShowModerationFeedback] = useState(false)
// 初始化音效系統
useEffect(() => {
@@ -43,31 +52,64 @@ export default function SubmitPage() {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
// 先進行內容審核
const moderation = moderateWishForm(formData)
setModerationResult(moderation)
if (!moderation.isAppropriate) {
setShowModerationFeedback(true)
await soundManager.play("click") // 播放提示音效
toast({
title: "內容需要修改",
description: "請根據建議修改內容後再次提交",
variant: "destructive",
})
return
}
setIsSubmitting(true)
setShowModerationFeedback(false)
// 播放提交音效
await soundManager.play("submit")
await new Promise((resolve) => setTimeout(resolve, 1500))
try {
// 創建困擾案例到 Supabase 數據庫
await WishService.createWish({
title: formData.title,
currentPain: formData.currentPain,
expectedSolution: formData.expectedSolution,
expectedEffect: formData.expectedEffect,
isPublic: formData.isPublic,
email: formData.email,
images: images, // 直接傳遞 ImageFile 數組
})
const wishes = JSON.parse(localStorage.getItem("wishes") || "[]")
const newWish = {
id: Date.now(),
...formData,
createdAt: new Date().toISOString(),
// 播放成功音效
await soundManager.play("success")
toast({
title: "你的困擾已成功提交",
description: formData.isPublic
? "正在為你準備專業的回饋,其他人也能看到你的分享..."
: "正在為你準備專業的回饋,你的分享將保持私密...",
})
} catch (error) {
console.error("提交困擾失敗:", error)
// 播放錯誤音效
await soundManager.play("click")
toast({
title: "提交失敗",
description: "請稍後再試或檢查網路連接",
variant: "destructive",
})
setIsSubmitting(false)
return
}
wishes.push(newWish)
localStorage.setItem("wishes", JSON.stringify(wishes))
// 播放成功音效
await soundManager.play("success")
toast({
title: "你的困擾已成功提交",
description: formData.isPublic
? "正在為你準備專業的回饋,其他人也能看到你的分享..."
: "正在為你準備專業的回饋,你的分享將保持私密...",
})
setFormData({
title: "",
@@ -75,8 +117,11 @@ export default function SubmitPage() {
expectedSolution: "",
expectedEffect: "",
isPublic: true,
email: "",
})
setImages([])
setIsSubmitting(false)
setModerationResult(null)
// 跳轉到感謝頁面
setTimeout(() => {
@@ -354,6 +399,70 @@ export default function SubmitPage() {
/>
</div>
{/* 圖片上傳區域 */}
<div className="space-y-2">
<Label className="text-blue-100 font-semibold text-sm md:text-base flex items-center gap-2">
<ImageIcon className="w-4 h-4" />
()
</Label>
<div className="text-xs md:text-sm text-slate-400 mb-3">
</div>
<ImageUpload images={images} onImagesChange={setImages} disabled={isSubmitting} />
</div>
{/* Email 聯絡資訊 - 可選 */}
<div className="space-y-2">
<Label
htmlFor="email"
className="text-blue-100 font-semibold text-sm md:text-base flex items-center gap-2"
>
<Mail className="w-4 h-4" />
()
</Label>
<Input
id="email"
type="email"
placeholder="your.email@example.com"
value={formData.email}
onChange={(e) => handleChange("email", e.target.value)}
className="bg-slate-700/50 border-blue-600/50 text-white placeholder:text-blue-300 focus:border-cyan-400 text-sm md:text-base"
/>
<div className="text-xs md:text-sm text-slate-400 leading-relaxed">
<div className="flex items-start gap-2 mb-2">
<Shield className="w-3 h-3 text-blue-400 mt-0.5 flex-shrink-0" />
<div>
<p className="font-medium text-blue-300 mb-1"></p>
<ul className="space-y-1 text-slate-400">
<li> </li>
<li> Email </li>
<li> </li>
<li> Email </li>
</ul>
</div>
</div>
</div>
</div>
{/* 內容審核回饋 */}
{showModerationFeedback && moderationResult && (
<ContentModerationFeedback
result={moderationResult}
onRetry={() => {
const newModeration = moderateWishForm(formData)
setModerationResult(newModeration)
if (newModeration.isAppropriate) {
setShowModerationFeedback(false)
toast({
title: "內容檢查通過",
description: "現在可以提交你的困擾了!",
})
}
}}
className="animate-in slide-in-from-top-2 duration-300"
/>
)}
{/* 隱私設定區塊 */}
<div className="space-y-4 p-4 md:p-5 bg-gradient-to-r from-slate-700/30 to-slate-800/30 rounded-lg border border-slate-600/50">
<div className="flex items-center gap-3">
@@ -391,12 +500,12 @@ export default function SubmitPage() {
<div className="text-xs md:text-sm text-slate-300 leading-relaxed">
{formData.isPublic ? (
<span>
<br />
</span>
) : (
<span>
🔒
🔒
<br />
</span>
)}
@@ -413,6 +522,7 @@ export default function SubmitPage() {
<ul className="space-y-1 text-slate-400">
<li> </li>
<li> </li>
<li> </li>
<li> </li>
<li> </li>
</ul>
@@ -437,6 +547,7 @@ export default function SubmitPage() {
<>
<Send className="w-4 h-4 mr-2" />
{formData.isPublic ? "公開提交困擾" : "私密提交困擾"}
{images.length > 0 && <span className="ml-1 text-xs opacity-75">({images.length} )</span>}
</>
)}
</Button>