"use client"; import { useEffect, useState } from "react"; import { ProductContextForm } from "@/components/product-context-form"; 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 { InlineAlert } from "@/components/ui/inline-alert"; import type { ActionFeedback } from "@/lib/use-action-feedback"; import { parseFetchJson } from "@/lib/utils"; import { formatMatchTagsInput, parseMatchTagsInput } from "@/lib/types/product-match"; import { hasProductContext, parseProductContext, serializeProductContext } from "@/lib/types/product-context"; export interface ProductItemRow { id: string; label: string; context: string; matchTags: string[]; } interface ProductItemFormDialogProps { open: boolean; onOpenChange: (open: boolean) => void; brandId: string; brandName: string; product?: ProductItemRow | null; onSaved?: (product: ProductItemRow) => void; } export function ProductItemFormDialog({ open, onOpenChange, brandId, brandName, product, onSaved, }: ProductItemFormDialogProps) { const [label, setLabel] = useState(""); const [context, setContext] = useState(""); const [matchTagsInput, setMatchTagsInput] = useState(""); const [submitting, setSubmitting] = useState(false); const [formFeedback, setFormFeedback] = useState(null); useEffect(() => { if (!open) return; setLabel(product?.label ?? ""); setContext(product?.context ?? ""); setMatchTagsInput(product ? formatMatchTagsInput(product.matchTags) : ""); setFormFeedback(null); }, [open, product]); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); if (!label.trim()) { setFormFeedback({ type: "warning", title: "請填寫產品名稱", message: "產品名稱為必填。" }); return; } const fields = parseProductContext(context); const merged = serializeProductContext({ ...fields, brand: brandName, product: fields.product?.trim() || label.trim(), }); if (!hasProductContext(merged)) { setFormFeedback({ type: "warning", title: "請填寫產品特色", message: "至少需填寫一項產品特色。" }); return; } const matchTags = parseMatchTagsInput(matchTagsInput); setFormFeedback(null); setSubmitting(true); const res = await fetch("/api/brands/products", { method: product ? "PATCH" : "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify( product ? { id: product.id, label: label.trim(), context: merged, matchTags } : { brandId, label: label.trim(), context: merged, matchTags } ), }); let data: { error?: string; product?: { id: string; label: string; context: string; matchTags?: string[] }; } = {}; try { data = await parseFetchJson(res); } catch (err) { setSubmitting(false); setFormFeedback({ type: "error", title: "儲存失敗", message: err instanceof Error ? err.message : "伺服器回應異常", }); return; } setSubmitting(false); if (!res.ok || !data.product) { setFormFeedback({ type: "error", title: "儲存失敗", message: data.error ?? "伺服器未回傳產品資料", }); return; } const saved: ProductItemRow = { id: data.product.id, label: data.product.label, context: data.product.context, matchTags: data.product.matchTags ?? matchTags, }; onSaved?.(saved); onOpenChange(false); } return ( {product ? "編輯產品" : "新增產品"} 品牌:{brandName} · 填寫適用標籤後,海巡生成回覆時會自動推薦對應產品。
{formFeedback && ( setFormFeedback(null)} /> )}
setLabel(e.target.value)} placeholder="溫和洗毛精" autoFocus />
setMatchTagsInput(e.target.value)} placeholder="洗毛精、敏感肌、狗洗澡(頓號或逗號分隔)" />

與海巡標籤越接近,越優先推薦此產品置入。

); }