"use client"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { Plus } from "lucide-react"; import { BrandProductPicker } from "@/components/product-profile/brand-product-picker"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { InlineAlert } from "@/components/ui/inline-alert"; import type { ActionFeedback } from "@/lib/use-action-feedback"; import type { TopicGoal } from "@/lib/types/topic-goal"; import { parseFetchJson } from "@/lib/utils"; interface TopicFormDialogProps { open: boolean; onOpenChange: (open: boolean) => void; defaultGoal: TopicGoal; onCreated?: () => void; } export function TopicFormDialog({ open, onOpenChange, defaultGoal, onCreated, }: TopicFormDialogProps) { const router = useRouter(); const [label, setLabel] = useState(""); const [query, setQuery] = useState(""); const [brief, setBrief] = useState(""); const topicGoal = defaultGoal; const [brandProfileId, setBrandProfileId] = useState(null); const [productProfileId, setProductProfileId] = useState(null); const [productContext, setProductContext] = useState(""); const [submitting, setSubmitting] = useState(false); const [formFeedback, setFormFeedback] = useState(null); useEffect(() => { if (!open) return; setLabel(""); setQuery(""); setBrief(""); setBrandProfileId(null); setProductProfileId(null); setProductContext(""); setFormFeedback(null); }, [open, defaultGoal]); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); if (!label.trim() || !query.trim()) { setFormFeedback({ type: "warning", message: "請填寫主題名稱與種子關鍵字。" }); return; } if (topicGoal === "placement" && !brandProfileId) { setFormFeedback({ type: "warning", title: "請選擇品牌", message: "置入模式需先選擇品牌。" }); return; } setFormFeedback(null); setSubmitting(true); const res = await fetch("/api/topics", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ label: label.trim(), query: query.trim(), brief: brief.trim() || undefined, topicGoal, brandProfileId: topicGoal === "placement" ? brandProfileId : undefined, productProfileId: topicGoal === "placement" ? productProfileId : undefined, productContext: topicGoal === "placement" ? productContext : undefined, }), }); let data: { error?: string; topic?: { id: string } } = {}; try { data = await parseFetchJson(res); } catch (err) { setSubmitting(false); setFormFeedback({ type: "error", title: "建立失敗", message: err instanceof Error ? err.message : "伺服器回應異常", }); return; } if (!res.ok) { setSubmitting(false); setFormFeedback({ type: "error", title: "建立失敗", message: data.error ?? "無法建立主題", }); return; } const topicId = data.topic?.id; if (!topicId) { setSubmitting(false); setFormFeedback({ type: "error", title: "建立失敗", message: "未取得主題編號" }); return; } const analyzeRes = await fetch("/api/analyze-topic", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ topicId, brief: brief.trim() || undefined }), }); setSubmitting(false); onCreated?.(); onOpenChange(false); if (analyzeRes.ok) window.dispatchEvent(new Event("haixun:jobs-updated")); router.push(`/scans/${topicId}?mode=${topicGoal}`); } return ( {topicGoal === "placement" ? "新增找 TA 任務" : "新增拷貝忍者任務"} 建立後會自動開始 AI 分析;完成後確認標籤,就能直接海巡。
{formFeedback && ( setFormFeedback(null)} /> )}
setLabel(e.target.value)} placeholder="居家狗狗洗澡" autoFocus />
setQuery(e.target.value)} placeholder="狗狗洗澡" />