import { useEffect, useState, type FormEvent } from 'react' import { useNavigate } from 'react-router-dom' import { catalog, inventory, production } from '@/api/client' import type { Item, Location } from '@/types/api' import { PageHeader } from '@/components/PageHeader' import { ErrorBox } from '@/components/ErrorBox' interface BomLine { itemCode: string; quantityPerUnit: string; sourceLocationCode: string } interface OpLine { operationCode: string; workCenter: string; standardMinutes: string } export function CreateWorkOrderPage() { const navigate = useNavigate() const [code, setCode] = useState('') const [outputItemCode, setOutputItemCode] = useState('') const [outputQuantity, setOutputQuantity] = useState('') const [dueDate, setDueDate] = useState('') const [bom, setBom] = useState([]) const [ops, setOps] = useState([]) const [items, setItems] = useState([]) const [locations, setLocations] = useState([]) const [submitting, setSubmitting] = useState(false) const [error, setError] = useState(null) useEffect(() => { Promise.all([catalog.listItems(), inventory.listLocations()]).then(([i, l]) => { setItems(i) setLocations(l.filter((x) => x.active)) }) }, []) const addBom = () => setBom([...bom, { itemCode: '', quantityPerUnit: '1', sourceLocationCode: locations[0]?.code ?? '' }]) const removeBom = (i: number) => setBom(bom.filter((_, idx) => idx !== i)) const updateBom = (i: number, f: keyof BomLine, v: string) => { const next = [...bom]; next[i] = { ...next[i], [f]: v }; setBom(next) } const addOp = () => setOps([...ops, { operationCode: '', workCenter: '', standardMinutes: '30' }]) const removeOp = (i: number) => setOps(ops.filter((_, idx) => idx !== i)) const updateOp = (i: number, f: keyof OpLine, v: string) => { const next = [...ops]; next[i] = { ...next[i], [f]: v }; setOps(next) } const onSubmit = async (e: FormEvent) => { e.preventDefault() setError(null) setSubmitting(true) try { const created = await production.createWorkOrder({ code, outputItemCode, outputQuantity: Number(outputQuantity), dueDate: dueDate || null, inputs: bom.map((b, i) => ({ lineNo: i + 1, itemCode: b.itemCode, quantityPerUnit: Number(b.quantityPerUnit), sourceLocationCode: b.sourceLocationCode, })), operations: ops.map((o, i) => ({ lineNo: i + 1, operationCode: o.operationCode, workCenter: o.workCenter, standardMinutes: Number(o.standardMinutes), })), }) navigate(`/work-orders/${created.id}`) } catch (err: unknown) { setError(err instanceof Error ? err : new Error(String(err))) } finally { setSubmitting(false) } } return (
navigate('/work-orders')}>Cancel} />
setCode(e.target.value)} placeholder="WO-PRINT-0002" className="mt-1 w-full rounded-md border border-slate-300 px-3 py-2 text-sm" />
setOutputQuantity(e.target.value)} className="mt-1 w-full rounded-md border border-slate-300 px-3 py-2 text-sm text-right" />
setDueDate(e.target.value)} className="mt-1 max-w-xs rounded-md border border-slate-300 px-3 py-2 text-sm" />
{/* ─── BOM inputs ─────────────────────────────────────── */}
{bom.length === 0 &&

No BOM lines. Output will be produced without consuming materials.

}
{bom.map((b, idx) => (
{idx + 1} updateBom(idx, 'quantityPerUnit', e.target.value)} className="w-24 rounded-md border border-slate-300 px-2 py-1.5 text-sm text-right" />
))}
{/* ─── Routing operations ─────────────────────────────── */}
{ops.length === 0 &&

No routing. Work order completes in one step.

}
{ops.map((o, idx) => (
{idx + 1} updateOp(idx, 'operationCode', e.target.value)} className="w-28 rounded-md border border-slate-300 px-2 py-1.5 text-sm" /> updateOp(idx, 'workCenter', e.target.value)} className="flex-1 rounded-md border border-slate-300 px-2 py-1.5 text-sm" /> updateOp(idx, 'standardMinutes', e.target.value)} className="w-20 rounded-md border border-slate-300 px-2 py-1.5 text-sm text-right" />
))}
{error && }
) }