From c270cb22e9caeab56c323c2be6ac74eddb0cf537 Mon Sep 17 00:00:00 2001 From: BOHA Date: Tue, 9 Jun 2026 20:36:55 +0200 Subject: [PATCH] fix(issued-orders): correct status display after create-redirect + per-button loading state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug 1: creating an issued order as 'sent' redirected to the detail which showed 'Koncept' until a refresh — the component is reused across create→edit, so the one-shot hydration (gated by dataReady) never reloaded the real status. Now the just-saved status is reflected into local form state on every save with a target. Bug 2: both edit-draft buttons shared one 'saving' flag, so pressing 'Uložit koncept' made 'Odeslat' show 'Ukládání...'. Track which action is in flight so only the clicked button spins (all stay disabled to block double-submit). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/admin/pages/IssuedOrderDetail.tsx | 28 ++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/admin/pages/IssuedOrderDetail.tsx b/src/admin/pages/IssuedOrderDetail.tsx index 4f35275..8e73ab6 100644 --- a/src/admin/pages/IssuedOrderDetail.tsx +++ b/src/admin/pages/IssuedOrderDetail.tsx @@ -534,6 +534,10 @@ export default function IssuedOrderDetail() { ]); const [errors, setErrors] = useState>({}); const [saving, setSaving] = useState(false); + // Which save action is in flight ("draft" | the live status | "save"), so + // only the clicked button shows its spinner — `saving` still disables all of + // them to prevent a concurrent double-submit. + const [savingAction, setSavingAction] = useState(null); const [dataReady, setDataReady] = useState(false); const [poNumber, setPoNumber] = useState(""); @@ -733,6 +737,7 @@ export default function IssuedOrderDetail() { if (Object.keys(newErrors).length > 0) return; setSaving(true); + setSavingAction(targetStatus ?? "save"); try { const payload: Record = { customer_id: form.customer_id, @@ -770,10 +775,14 @@ export default function IssuedOrderDetail() { alert.success( isEdit ? "Objednávka byla uložena" : "Objednávka byla vytvořena", ); - // Finalizing a draft (draft → sent) assigns the PO number server-side; - // reflect the new status locally so the form switches out of the draft - // button branch (the invalidated query refetch repopulates the number). - if (isEdit && targetStatus && targetStatus !== "draft") { + // Reflect the just-saved status locally. On CREATE the component is reused + // for the redirect to the new order's detail and the one-shot edit-mode + // hydration won't re-run (dataReady stays true), so without this the page + // would show the stale create-mode status ("draft") even though the order + // was created as "sent" — until a manual refresh. On finalize (edit + // draft→live) it flips the form out of the draft button branch. The PO + // number is repopulated by the detail-query sync effect. + if (targetStatus) { setForm((prev) => ({ ...prev, status: targetStatus })); } if (!isEdit) navigate(`/orders/issued/${data.id}`); @@ -787,6 +796,7 @@ export default function IssuedOrderDetail() { ); } finally { setSaving(false); + setSavingAction(null); } }; @@ -946,7 +956,7 @@ export default function IssuedOrderDetail() { onClick={() => handleSubmit("draft")} disabled={saving} > - {saving ? ( + {savingAction === "draft" ? ( ) : ( "Uložit koncept" @@ -956,7 +966,7 @@ export default function IssuedOrderDetail() { onClick={() => handleSubmit(LIVE_STATUS)} disabled={saving} > - {saving ? ( + {savingAction === LIVE_STATUS ? ( <> handleSubmit("draft")} disabled={saving} > - {saving ? ( + {savingAction === "draft" ? ( ) : ( "Uložit koncept" @@ -995,7 +1005,7 @@ export default function IssuedOrderDetail() { onClick={() => handleSubmit(LIVE_STATUS)} disabled={saving} > - {saving ? ( + {savingAction === LIVE_STATUS ? ( <> {editable && (