"use client"; import { useState } from "react"; import { Plus } from "lucide-react"; import { Button } from "@/components/ui/Button"; import { Field } from "@/components/ui/Field"; import { TextArea } from "@/components/ui/TextArea"; import { TextInput } from "@/components/ui/TextInput"; import { cardClass } from "@/lib/ui/variants"; import type { RegisterInput } from "@/lib/foreshadow/board"; interface RegisterFormProps { projectId: string; busy: boolean; onRegister: (input: RegisterInput) => Promise; open?: boolean; onOpenChange?: (open: boolean) => void; } const EMPTY = { code: "", title: "", plantedAt: "", content: "", expectedCloseFrom: "", expectedCloseTo: "", importance: "", }; // 登记新伏笔(UX §6.8)。受控表单 → 组装 RegisterInput;成功后清空。 export function RegisterForm({ projectId, busy, onRegister, open: controlledOpen, onOpenChange, }: RegisterFormProps) { const [localOpen, setLocalOpen] = useState(false); const [form, setForm] = useState({ ...EMPTY }); const open = controlledOpen ?? localOpen; const setOpen = (next: boolean): void => { if (controlledOpen === undefined) setLocalOpen(next); onOpenChange?.(next); }; const set = (key: keyof typeof EMPTY, value: string): void => setForm((prev) => ({ ...prev, [key]: value })); const submit = async (): Promise => { const ok = await onRegister({ projectId, code: form.code, title: form.title, plantedAt: toInt(form.plantedAt), content: form.content || null, expectedCloseFrom: toInt(form.expectedCloseFrom), expectedCloseTo: toInt(form.expectedCloseTo), importance: form.importance || null, }); if (ok) { setForm({ ...EMPTY }); setOpen(false); } }; if (!open) { return ( ); } const missingRequired = form.code.trim().length === 0 || form.title.trim().length === 0; const canSubmit = !missingRequired && !busy; return (
{ e.preventDefault(); void submit(); }} className={cardClass("p-4")} >
set("code", e.target.value)} /> set("title", e.target.value)} /> set("plantedAt", e.target.value)} /> set("expectedCloseFrom", e.target.value)} /> set("expectedCloseTo", e.target.value)} /> set("importance", e.target.value)} placeholder="主线/支线" />