From a4c9810de78506ffff1227e1e3bd2e11df61258e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Veikko=20Lintuj=C3=A4rvi?= Date: Wed, 11 Mar 2026 20:28:19 +0200 Subject: [PATCH] Deletion verification modal --- api/Database/klapi.db | Bin 53248 -> 53248 bytes ui/src/components/ConfirmDialog.tsx | 83 ++++++++++++++++++++++++++++ ui/src/components/OpenHoursForm.tsx | 34 +++++++++++- ui/src/i18n.ts | 13 +++++ 4 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 ui/src/components/ConfirmDialog.tsx diff --git a/api/Database/klapi.db b/api/Database/klapi.db index 322d07f7fb296774c11614b882bfdbcefb14c5c2..167565f88d655f089dc201d9eb945db0b0de5cc2 100644 GIT binary patch delta 343 zcmZvWJx;?w5JuNHA&J3Rs1OPgMrpB`S^urKLPDv6L}Ln4u@Wv!j0CI=WpV@%7YGs; zAeOj5j=}{H6&-8}3M59KrWwt9-*je9XXZoC7(VVC8N=7}XKK?YvO+nboX)9LZ*F{b zC$MUf{gy?x+XH(!QeEgUV37;HiEXE+=;pnVkk-hey-?wdln5o6fSXL_k z`+H4nx~g&zT!!N;FUv{3cynYm&K+d>ObFT4O?t~FH}@Gb z|Cb9viqUaXt2=`Ot+rEH+~xnNBf-F9z&WybsV<~u3jmGRTiaDtTxMli+1ge&oDaI* k>KNvhajLRgwKj)uYBcAE@04x77Ol(6%`BJHKvY->RMACfo9 zL!McSL>7w8wkjJ0;t3o7&WWEK d)DKP4sV~W+?($tq`*TufKpLG void; + onCancel: () => void; +}; + +export default function ConfirmDialog({ + open, + title, + description, + contextText, + confirmLabel, + cancelLabel, + busy = false, + busyLabel, + onConfirm, + onCancel, +}: ConfirmDialogProps) { + useEffect(() => { + if (!open) return; + + const onKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape" && !busy) { + onCancel(); + } + }; + + window.addEventListener("keydown", onKeyDown); + return () => { + window.removeEventListener("keydown", onKeyDown); + }; + }, [open, busy, onCancel]); + + if (!open) return null; + + return ( +
{ + if (!busy) onCancel(); + }} + > +
event.stopPropagation()} + > +

{title}

+ {description &&

{description}

} + {contextText &&

{contextText}

} + +
+ + +
+
+
+ ); +} \ No newline at end of file diff --git a/ui/src/components/OpenHoursForm.tsx b/ui/src/components/OpenHoursForm.tsx index 16dc9b2..fc4ff43 100644 --- a/ui/src/components/OpenHoursForm.tsx +++ b/ui/src/components/OpenHoursForm.tsx @@ -8,6 +8,7 @@ import { updateLokOpenHours, type LokOpenHours, } from "~/api"; +import ConfirmDialog from "~/components/ConfirmDialog"; import { useT } from "~/i18n"; import { openHoursAtom, toastsAtom, type Toast } from "~/state/appState"; @@ -38,6 +39,7 @@ export default function OpenHoursForm() { const [isEditing, setIsEditing] = useState(false); const [editingVersionId, setEditingVersionId] = useState(""); const [deletingId, setDeletingId] = useState(""); + const [confirmDeleteVersion, setConfirmDeleteVersion] = useState(null); const [activatingId, setActivatingId] = useState(""); const [saving, setSaving] = useState(false); const [form, setForm] = useState(EMPTY_FORM); @@ -217,6 +219,21 @@ export default function OpenHoursForm() { } }; + const askDeleteConfirmation = (version: LokOpenHours) => { + setConfirmDeleteVersion(version); + }; + + const cancelDeleteConfirmation = () => { + if (deletingId) return; + setConfirmDeleteVersion(null); + }; + + const confirmDelete = async () => { + if (!confirmDeleteVersion) return; + await onDelete(confirmDeleteVersion); + setConfirmDeleteVersion(null); + }; + const onSetActive = async (version: LokOpenHours) => { if (version.isActive) return; @@ -328,7 +345,7 @@ export default function OpenHoursForm() { disabled={active || deleting} onClick={(event) => { event.stopPropagation(); - void onDelete(version); + askDeleteConfirmation(version); }} className={`rounded-md border border-[#8E4F24] bg-[#EED5B8] px-3 py-1.5 text-sm text-[#70421E] disabled:cursor-not-allowed disabled:opacity-50 ${!active ? "hover:bg-[#E3A977]" : "" }`} @@ -416,6 +433,21 @@ export default function OpenHoursForm() { + + { + void confirmDelete(); + }} + /> ); } diff --git a/ui/src/i18n.ts b/ui/src/i18n.ts index a721bb9..8332e8a 100644 --- a/ui/src/i18n.ts +++ b/ui/src/i18n.ts @@ -44,6 +44,10 @@ const translations = { "home.openHours.saved": "New version saved", "home.openHours.updated": "Version updated", "home.openHours.deleted": "Version deleted", + "home.openHours.deleting": "Deleting...", + "home.openHours.deleteConfirmTitle": "Delete version?", + "home.openHours.deleteConfirmMessage": "This action cannot be undone.", + "home.openHours.deleteConfirmAction": "Delete version", "about.title": "About", "about.description": "Livonsaaren Tietokonepaja is a local project providing IT services for our dear archipelago.", @@ -125,6 +129,10 @@ const translations = { "home.openHours.saved": "Uusi versio tallennettu", "home.openHours.updated": "Versio päivitetty", "home.openHours.deleted": "Versio poistettu", + "home.openHours.deleting": "Poistetaan...", + "home.openHours.deleteConfirmTitle": "Poistetaanko versio?", + "home.openHours.deleteConfirmMessage": "Tätä toimintoa ei voi perua.", + "home.openHours.deleteConfirmAction": "Poista versio", "about.title": "Tietoja", "about.description": "Livonsaaren Tietokonepaja on paikallisprojekti, joka tuottaa IT-palveluita rakkaalle lähisaaristollemme.", @@ -207,6 +215,11 @@ const translations = { "home.openHours.saved": "Nová verzia uložená", "home.openHours.updated": "Verzia bola aktualizovaná", "home.openHours.deleted": "Verzia bola odstránená", + "home.openHours.deleting": "Odstraňuje sa...", + "home.openHours.deleteConfirmTitle": "Odstrániť verziu?", + "home.openHours.deleteConfirmMessage": + "Túto akciu nie je možné vrátiť späť.", + "home.openHours.deleteConfirmAction": "Odstrániť verziu", "about.title": "O aplikácii", "about.description": "Livonsaaren Tietokonepaja je lokálny projekt poskytujúci IT služby pre naše milované súostrovie.",