diff --git a/src/components/stock-orders/quick-draft-modal.test.tsx b/src/components/stock-orders/quick-draft-modal.test.tsx index 6299784..2a2fe13 100644 --- a/src/components/stock-orders/quick-draft-modal.test.tsx +++ b/src/components/stock-orders/quick-draft-modal.test.tsx @@ -291,4 +291,48 @@ describe("QuickDraftModal — add & next", () => { // Search region is hidden in new-SKU mode. expect(screen.queryByTestId("quick-draft-search")).not.toBeInTheDocument(); }); + + it("new-SKU path POSTs newStockItem and no stockItemId", async () => { + render( {}} />); + fireEvent.change(screen.getByTestId("quick-draft-search"), { + target: { value: "cutting" }, + }); + await act(async () => { + await vi.advanceTimersByTimeAsync(250); + }); + fireEvent.click(screen.getByText(/115mm Cutting Disc/)); + await act(async () => { + await vi.advanceTimersByTimeAsync(0); + }); + fireEvent.click(screen.getByTestId("quick-draft-toggle-new-sku")); + fireEvent.change(screen.getByTestId("quick-draft-new-sku-name"), { + target: { value: "115mm Cutting Disc" }, + }); + fireEvent.change(screen.getByTestId("quick-draft-new-sku-sku"), { + target: { value: "STK-CD-115" }, + }); + fireEvent.click(screen.getByLabelText(/Steel & Pipe Co/)); + fireEvent.change(screen.getByTestId("quick-draft-qty"), { + target: { value: "50" }, + }); + fireEvent.change(screen.getByTestId("quick-draft-cost"), { + target: { value: "20" }, + }); + fireEvent.click(screen.getByTestId("quick-draft-add")); + await act(async () => { + await vi.advanceTimersByTimeAsync(0); + }); + + const addCalls = (global.fetch as ReturnType).mock.calls.filter( + (c) => typeof c[0] === "string" && c[0].includes("/add-line"), + ); + expect(addCalls.length).toBeGreaterThan(0); + const [, init] = addCalls[0]; + const body = JSON.parse(init.body); + expect(body.newStockItem).toEqual({ name: "115mm Cutting Disc", sku: "STK-CD-115" }); + expect(body.stockItemId).toBeUndefined(); + expect(body.supplierId).toBe("sup-1"); + expect(body.quantity).toBe(50); + expect(body.costPrice).toBe(20); + }); }); diff --git a/src/components/stock-orders/quick-draft-modal.tsx b/src/components/stock-orders/quick-draft-modal.tsx index 6478688..534f077 100644 --- a/src/components/stock-orders/quick-draft-modal.tsx +++ b/src/components/stock-orders/quick-draft-modal.tsx @@ -15,9 +15,7 @@ import type { * Quick-Draft Modal — item-first stock-order entry on /stock-orders. * * See docs/superpowers/specs/2026-07-30-stock-quick-draft-design.md - * for the full design. This file is the modal in its entirety; the - * three regions (search, cards, footer) live in sub-components - * further down so the test surface stays manageable. + * for the full design. * * Data flow: * - search & history hit /api/v1/stock-quick-draft/{search,supplier-history} @@ -57,6 +55,7 @@ export function QuickDraftModal({ open, onOpenChange }: QuickDraftModalProps) { const [supplierChoice, setSupplierChoice] = useState(null); const [qty, setQty] = useState(""); const [cost, setCost] = useState(""); + // New-SKU toggle state (named for readability; plan uses isNewSku/newName/newSku) const [newSkuMode, setNewSkuMode] = useState(false); const [newSkuName, setNewSkuName] = useState(""); const [newSkuSku, setNewSkuSku] = useState(""); @@ -147,6 +146,7 @@ export function QuickDraftModal({ open, onOpenChange }: QuickDraftModalProps) { }; const onAddAndNext = async () => { + if (submitting) return; // closure-time guard against double-click races if (!canSubmit) return; setSubmitting(true); try { @@ -317,7 +317,7 @@ export function QuickDraftModal({ open, onOpenChange }: QuickDraftModalProps) { + New SKU not in stock yet ) : ( -
+
setNewSkuSku(e.target.value)} />
+ {historyLoading && ( +
+ Loading supplier history… +
+ )} + {!historyLoading && history.length > 0 && ( +
+ {history.map((entry) => ( + + ))} +
+ )} + {!historyLoading && history.length === 0 && ( +
+ Pick a supplier — Task 10 will add a full supplier dropdown + when there's no history. +
+ )}