From 792efc07ce16cc40f290053b8e2f93e8e10e0ea0 Mon Sep 17 00:00:00 2001 From: NW Date: Mon, 10 Aug 2026 08:44:12 +0100 Subject: [PATCH] =?UTF-8?q?feat(admin):=20issue=20#145=20=E2=80=94=20delet?= =?UTF-8?q?e-blocked=20hint=20+=20Deactivate/Edit=20alternative?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - categories dialog: red hint with count + Deactivate button when products>0 - locations dialog: red hint + Deactivate button when categories/products>0 - catalog dialog: deleteError shown on 400/409; Deactivate for category/subcategory/location, Edit for product - Deactivate calls existing PATCH toggle, closes dialog, reloads - tsc clean --- .../src/components/catalog/catalog-page.tsx | 46 +++++++++++++++++-- .../components/categories/categories-page.tsx | 13 +++++- .../components/locations/locations-page.tsx | 13 +++++- 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/admin-next/src/components/catalog/catalog-page.tsx b/admin-next/src/components/catalog/catalog-page.tsx index 97ee317..285afc8 100755 --- a/admin-next/src/components/catalog/catalog-page.tsx +++ b/admin-next/src/components/catalog/catalog-page.tsx @@ -211,6 +211,7 @@ export function CatalogPage() { id: number; name: string; } | null>(null); + const [deleteError, setDeleteError] = useState(null); // Inline rename state const [renamingId, setRenamingId] = useState(null); @@ -353,14 +354,38 @@ export function CatalogPage() { const res = await fetch(`/api/${typePath}/${deleteTarget.id}`, { method: "DELETE" }); if (!res.ok) { const data = await res.json(); - throw new Error(data.error || "Failed to delete"); + const msg = data.error || "Failed to delete"; + setDeleteError(msg); + toast.error(msg); + return; } toast.success(`${deleteTarget.type} deleted`); setDeleteTarget(null); + setDeleteError(null); fetchTree(); fetchProducts(); } catch (e) { - toast.error(e instanceof Error ? e.message : "Failed to delete"); + const msg = e instanceof Error ? e.message : "Failed to delete"; + setDeleteError(msg); + toast.error(msg); + } + }; + + const handleDeactivateFromCatalog = () => { + if (!deleteTarget) return; + handleToggleActive(deleteTarget.type, deleteTarget.id); + setDeleteTarget(null); + setDeleteError(null); + }; + + const handleEditFromCatalog = () => { + if (!deleteTarget || deleteTarget.type !== "product") return; + // Find the product in the current products list + const product = products.find((p) => p.id === deleteTarget.id); + setDeleteTarget(null); + setDeleteError(null); + if (product) { + openProductModal(product); } }; @@ -1488,17 +1513,32 @@ export function CatalogPage() { {/* ─── Delete Confirmation ─── */} - !open && setDeleteTarget(null)}> + { if (!open) { setDeleteTarget(null); setDeleteError(null); } }}> Delete {deleteTarget?.type}? Are you sure you want to delete "{deleteTarget?.name}"? This action cannot be undone. + {deleteError && ( + + {deleteError} + + )} Cancel + {deleteError && deleteTarget && deleteTarget.type !== "product" && ( + + )} + {deleteError && deleteTarget && deleteTarget.type === "product" && ( + + )} { + if (!deleteTarget) return; + handleToggle(deleteTarget); + setDeleteTarget(null); + }; + // Group locations by country > city > district const groupedLocations = locations.reduce>>>( (acc, loc) => { @@ -469,13 +475,18 @@ export function CategoriesPage() { Are you sure you want to delete "{deleteTarget?.name}"? This action cannot be undone. {deleteTarget && deleteTarget._count.products > 0 && ( - This category has {deleteTarget._count.products} product(s) and cannot be deleted. + This category has {deleteTarget._count.products} product(s) and cannot be deleted. You can deactivate it instead. )} Cancel + {deleteTarget && deleteTarget._count.products > 0 && ( + + )} 0 : true)} diff --git a/admin-next/src/components/locations/locations-page.tsx b/admin-next/src/components/locations/locations-page.tsx index 64798da..cd6c70b 100755 --- a/admin-next/src/components/locations/locations-page.tsx +++ b/admin-next/src/components/locations/locations-page.tsx @@ -201,6 +201,12 @@ export function LocationsPage() { } }; + const handleDeactivate = () => { + if (!deleteTarget) return; + handleToggle(deleteTarget); + setDeleteTarget(null); + }; + return (
@@ -344,13 +350,18 @@ export function LocationsPage() { {deleteTarget && (deleteTarget._count.categories > 0 || deleteTarget._count.products > 0) && ( This location has {deleteTarget._count.categories} categor{deleteTarget._count.categories === 1 ? "y" : "ies"} - and {deleteTarget._count.products} product(s) and cannot be deleted. + {" "}and {deleteTarget._count.products} product(s) and cannot be deleted. You can deactivate it instead. )} Cancel + {deleteTarget && (deleteTarget._count.categories > 0 || deleteTarget._count.products > 0) && ( + + )} 0 || deleteTarget._count.products > 0) : true)}