fix(ui): guard delete on paid invoices / ordered-or-locked offers; add guarded delete to issued orders
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -540,6 +540,8 @@ export default function IssuedOrderDetail() {
|
||||
status: string | null;
|
||||
}>({ show: false, status: null });
|
||||
const [pdfLoading, setPdfLoading] = useState(false);
|
||||
const [deleteConfirm, setDeleteConfirm] = useState(false);
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
|
||||
// ─── Queries ───
|
||||
const customersQuery = useQuery(offerCustomersOptions());
|
||||
@@ -654,6 +656,12 @@ export default function IssuedOrderDetail() {
|
||||
invalidate: ["issued-orders"],
|
||||
});
|
||||
|
||||
const deleteMutation = useApiMutation<void, unknown>({
|
||||
url: () => `${API_BASE}/issued-orders/${id}`,
|
||||
method: () => "DELETE",
|
||||
invalidate: ["issued-orders"],
|
||||
});
|
||||
|
||||
// ─── Item handlers ───
|
||||
const updateItem = (
|
||||
index: number,
|
||||
@@ -768,6 +776,21 @@ export default function IssuedOrderDetail() {
|
||||
}
|
||||
};
|
||||
|
||||
// ─── Delete ───
|
||||
const handleDelete = async () => {
|
||||
setDeleting(true);
|
||||
try {
|
||||
await deleteMutation.mutateAsync(undefined);
|
||||
alert.success("Objednávka byla smazána");
|
||||
navigate("/orders?tab=vydane");
|
||||
} catch (err) {
|
||||
alert.error(err instanceof Error ? err.message : "Chyba připojení");
|
||||
} finally {
|
||||
setDeleting(false);
|
||||
setDeleteConfirm(false);
|
||||
}
|
||||
};
|
||||
|
||||
// ─── PDF export ───
|
||||
const handleViewPdf = async () => {
|
||||
const newWindow = window.open("", "_blank");
|
||||
@@ -901,6 +924,21 @@ export default function IssuedOrderDetail() {
|
||||
)}
|
||||
</Button>
|
||||
))}
|
||||
{/* A completed order is terminal/finalized — never deletable from the
|
||||
UI. draft/sent/confirmed/cancelled may be deleted. (Backend
|
||||
rejection of deleting an order is a separate hardening, out of
|
||||
scope here.) */}
|
||||
{isEdit &&
|
||||
hasPermission("orders.delete") &&
|
||||
form.status !== "completed" && (
|
||||
<Button
|
||||
onClick={() => setDeleteConfirm(true)}
|
||||
variant="outlined"
|
||||
color="error"
|
||||
>
|
||||
Smazat
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -1280,6 +1318,21 @@ export default function IssuedOrderDetail() {
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Delete confirm */}
|
||||
{isEdit && (
|
||||
<ConfirmDialog
|
||||
isOpen={deleteConfirm}
|
||||
onClose={() => setDeleteConfirm(false)}
|
||||
onConfirm={handleDelete}
|
||||
title="Smazat objednávku?"
|
||||
message={`Opravdu chcete smazat objednávku "${poNumber}"? Tato akce je nevratná.`}
|
||||
confirmText="Smazat"
|
||||
cancelText="Zrušit"
|
||||
confirmVariant="danger"
|
||||
loading={deleting}
|
||||
/>
|
||||
)}
|
||||
</PageEnter>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user