From 20b57ce2bb86a17f6e32fad18ef630ee87dcde49 Mon Sep 17 00:00:00 2001 From: SJCoetz Date: Thu, 30 Jul 2026 14:54:02 +0200 Subject: [PATCH] feat(sprint-modal): show markup + order desc hint + explicit Show/Hide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three small additions to the process modal: - Markup cell added to the pricing grid (4 cols now: PO Qty, Cost, Selling, Markup). Read-only and dashed like Selling — derived from selling/cost so the operator sees the margin they're pricing at. Green when selling ≥ cost, destructive when selling < cost. - Above the PO description textarea, the order's original item description is now shown as a read-only reference hint. Lets the operator see what the customer asked for vs what they're sending to the supplier without having to scroll back to the modal header. - AI Insights toggle now has an explicit "Show" / "Hide" label next to the chevron so the affordance is obvious. The chevron direction was the only signal before; the label makes the toggle self-documenting. Co-authored-by: Orca --- .../order-sprint-process-modal.test.tsx | 25 ++++++++ src/components/order-sprint-process-modal.tsx | 61 +++++++++++++++++-- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/components/order-sprint-process-modal.test.tsx b/src/components/order-sprint-process-modal.test.tsx index c02a80a..8f1b497 100644 --- a/src/components/order-sprint-process-modal.test.tsx +++ b/src/components/order-sprint-process-modal.test.tsx @@ -282,6 +282,31 @@ describe("OrderSprintProcessModal", () => { }); }); + it("shows the computed markup percentage next to the locked selling", () => { + // baseItem.selling_price = 50; cost starts at 0 → markup shows '—'. + renderModal(); + expect(screen.getByLabelText(/markup/i).textContent).toMatch(/—/); + // Set cost → markup should turn into "100.0%". + return setField("Cost (ZAR)", "25").then(() => { + expect(screen.getByLabelText(/markup/i).textContent).toMatch(/100\.0%/); + }); + }); + + it("shows the order description as a read-only hint above the PO description", () => { + renderModal(); + // Order description should render above the textarea (read-only). + expect( + screen.getByLabelText(/order description \(read-only\)/i), + ).toBeInTheDocument(); + expect( + screen.getByLabelText(/order description \(read-only\)/i), + ).toHaveTextContent("HSS drill bit"); + // The PO description textarea is still editable below it. + expect( + screen.getByPlaceholderText("Description the supplier sees on the PO"), + ).toBeInTheDocument(); + }); + describe("'Use AI suggestion' button", () => { it("is disabled when ai_item_insights has no top_historical_matches", () => { renderModal({ item: { ...baseItem, ai_item_insights: { procurement_summary: "hi" } } }); diff --git a/src/components/order-sprint-process-modal.tsx b/src/components/order-sprint-process-modal.tsx index 73810e3..274cb41 100644 --- a/src/components/order-sprint-process-modal.tsx +++ b/src/components/order-sprint-process-modal.tsx @@ -334,7 +334,7 @@ export function OrderSprintProcessModal({ item, suppliers, open, onClose, onProc type="button" onClick={() => setAiInsightsExpanded(v => !v)} aria-expanded={aiInsightsExpanded} - className="flex items-center gap-2 text-left" + className="flex items-center gap-2 text-left group/ai-toggle" > {aiInsightsExpanded ? ( @@ -350,6 +350,9 @@ export function OrderSprintProcessModal({ item, suppliers, open, onClose, onProc suggestion available )} + + {aiInsightsExpanded ? "Hide" : "Show"} + )} + {item.description && ( +
+ + Order description + +
+ {item.description} +
+
+ )}