haixunMaster/components/product-profile/brand-form-dialog.tsx

151 lines
4.4 KiB
TypeScript
Raw Normal View History

2026-06-21 12:50:31 +00:00
"use client";
import { useEffect, useState } from "react";
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 { parseFetchJson } from "@/lib/utils";
export interface BrandRow {
id: string;
name: string;
notes: string | null;
}
interface BrandFormDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
brand?: BrandRow | null;
onSaved?: (brand: BrandRow) => void;
}
export function BrandFormDialog({ open, onOpenChange, brand, onSaved }: BrandFormDialogProps) {
const [name, setName] = useState("");
const [notes, setNotes] = useState("");
const [submitting, setSubmitting] = useState(false);
const [formFeedback, setFormFeedback] = useState<ActionFeedback | null>(null);
useEffect(() => {
if (!open) return;
setName(brand?.name ?? "");
setNotes(brand?.notes ?? "");
setFormFeedback(null);
}, [open, brand]);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
if (!name.trim()) {
setFormFeedback({ type: "warning", title: "請填寫品牌名稱", message: "品牌名稱為必填。" });
return;
}
setFormFeedback(null);
setSubmitting(true);
const res = await fetch("/api/brands", {
method: brand ? "PATCH" : "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(
brand
? { id: brand.id, name: name.trim(), notes: notes.trim() || null }
: { name: name.trim(), notes: notes.trim() || undefined }
),
});
let data: { error?: string; brand?: { id: string; name: string; notes: string | null } } = {};
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) {
setFormFeedback({
type: "error",
title: "儲存失敗",
message: data.error ?? "無法儲存品牌",
});
return;
}
const saved = brand
? { id: brand.id, name: name.trim(), notes: notes.trim() || null }
: data.brand
? {
id: data.brand.id,
name: data.brand.name,
notes: data.brand.notes ?? null,
}
: null;
if (!saved) {
setFormFeedback({
type: "error",
title: "儲存失敗",
message: "伺服器未回傳品牌資料",
});
return;
}
onSaved?.(saved);
onOpenChange(false);
}
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent>
<DialogHeader>
<DialogTitle>{brand ? "編輯品牌" : "新增品牌"}</DialogTitle>
<DialogDescription> AI </DialogDescription>
</DialogHeader>
<form onSubmit={handleSubmit} className="space-y-4">
{formFeedback && (
<InlineAlert
type={formFeedback.type}
title={formFeedback.title}
message={formFeedback.message}
onDismiss={() => setFormFeedback(null)}
/>
)}
<div className="space-y-1.5">
<Label></Label>
<Input value={name} onChange={(e) => setName(e.target.value)} placeholder="kahu" autoFocus />
</div>
<div className="space-y-1.5">
<Label></Label>
<Textarea
value={notes}
onChange={(e) => setNotes(e.target.value)}
rows={2}
placeholder="例:寵物清潔用品、溫和無添加"
/>
</div>
<DialogFooter>
<Button type="button" variant="ghost" onClick={() => onOpenChange(false)}>
</Button>
<Button type="submit" disabled={submitting}>
{submitting ? "儲存中…" : "儲存"}
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
);
}