fix(labs): confirm destructive deletes on lab results and Vorsorge reminders

The single-row delete on lab results and on preventive-care reminders
fired immediately on click, unlike the measurement and mood lists which
gate the same action behind a confirm dialog. Route both through the
shared DeleteButton so a stray tap can no longer drop a reading or a
reminder, and add the per-surface confirm copy across all locales.
This commit is contained in:
Marc-André Bombeck committed 2026-06-16 00:45:19 +02:00
1 parent 7c8d82f565
commit ba7a72f484
8 files changed
+44 -22

No files matched your search

+4
View File
@@ -6437,6 +6437,8 @@
"addButton": "Erinnerung hinzufügen",
"markDone": "Erledigt",
"delete": "Löschen",
"deleteConfirmTitle": "Erinnerung löschen?",
"deleteConfirmDescription": "Diese Vorsorge-Erinnerung wird dauerhaft gelöscht.",
"disabledBadge": "Aus",
"nextDue": {
"none": "Nicht geplant",
@@ -6493,6 +6495,8 @@
"referenceLabel": "Referenz",
"readingsCount": "{count} Werte",
"deleteLatest": "Letzten Wert löschen",
"deleteConfirmTitle": "Laborwert löschen?",
"deleteConfirmDescription": "Dieser Laborwert wird dauerhaft gelöscht.",
"deletedToast": "Wert gelöscht",
"deleteError": "Wert konnte nicht gelöscht werden",
"loadError": "Laborwerte konnten nicht geladen werden",
+4
View File
@@ -6437,6 +6437,8 @@
"addButton": "Add reminder",
"markDone": "Done",
"delete": "Delete",
"deleteConfirmTitle": "Delete reminder?",
"deleteConfirmDescription": "This preventive-care reminder will be permanently deleted.",
"disabledBadge": "Off",
"nextDue": {
"none": "Not scheduled",
@@ -6493,6 +6495,8 @@
"referenceLabel": "Reference",
"readingsCount": "{count} readings",
"deleteLatest": "Delete latest reading",
"deleteConfirmTitle": "Delete lab result?",
"deleteConfirmDescription": "This lab result will be permanently deleted.",
"deletedToast": "Result deleted",
"deleteError": "Could not delete the result",
"loadError": "Could not load lab results",
+4
View File
@@ -6437,6 +6437,8 @@
"addButton": "Añadir recordatorio",
"markDone": "Hecho",
"delete": "Eliminar",
"deleteConfirmTitle": "¿Eliminar recordatorio?",
"deleteConfirmDescription": "Este recordatorio de prevención se eliminará de forma permanente.",
"disabledBadge": "Apagado",
"nextDue": {
"none": "Sin programar",
@@ -6493,6 +6495,8 @@
"referenceLabel": "Referencia",
"readingsCount": "{count} valores",
"deleteLatest": "Eliminar el último valor",
"deleteConfirmTitle": "¿Eliminar resultado de laboratorio?",
"deleteConfirmDescription": "Este resultado de laboratorio se eliminará de forma permanente.",
"deletedToast": "Resultado eliminado",
"deleteError": "No se pudo eliminar el resultado",
"loadError": "No se pudieron cargar los resultados",
+4
View File
@@ -6437,6 +6437,8 @@
"addButton": "Ajouter un rappel",
"markDone": "Terminé",
"delete": "Supprimer",
"deleteConfirmTitle": "Supprimer le rappel ?",
"deleteConfirmDescription": "Ce rappel de prévention sera définitivement supprimé.",
"disabledBadge": "Désactivé",
"nextDue": {
"none": "Non planifié",
@@ -6493,6 +6495,8 @@
"referenceLabel": "Référence",
"readingsCount": "{count} valeurs",
"deleteLatest": "Supprimer la dernière valeur",
"deleteConfirmTitle": "Supprimer le résultat d'analyse ?",
"deleteConfirmDescription": "Ce résultat d'analyse sera définitivement supprimé.",
"deletedToast": "Résultat supprimé",
"deleteError": "Impossible de supprimer le résultat",
"loadError": "Impossible de charger les résultats",
+4
View File
@@ -6437,6 +6437,8 @@
"addButton": "Aggiungi promemoria",
"markDone": "Fatto",
"delete": "Elimina",
"deleteConfirmTitle": "Eliminare il promemoria?",
"deleteConfirmDescription": "Questo promemoria di prevenzione verrà eliminato definitivamente.",
"disabledBadge": "Disattivato",
"nextDue": {
"none": "Non pianificato",
@@ -6493,6 +6495,8 @@
"referenceLabel": "Riferimento",
"readingsCount": "{count} valori",
"deleteLatest": "Elimina l'ultimo valore",
"deleteConfirmTitle": "Eliminare il risultato di laboratorio?",
"deleteConfirmDescription": "Questo risultato di laboratorio verrà eliminato definitivamente.",
"deletedToast": "Risultato eliminato",
"deleteError": "Impossibile eliminare il risultato",
"loadError": "Impossibile caricare i risultati",
+4
View File
@@ -6437,6 +6437,8 @@
"addButton": "Dodaj przypomnienie",
"markDone": "Gotowe",
"delete": "Usuń",
"deleteConfirmTitle": "Usunąć przypomnienie?",
"deleteConfirmDescription": "To przypomnienie profilaktyczne zostanie trwale usunięte.",
"disabledBadge": "Wył.",
"nextDue": {
"none": "Niezaplanowane",
@@ -6493,6 +6495,8 @@
"referenceLabel": "Norma",
"readingsCount": "{count} wyników",
"deleteLatest": "Usuń ostatni wynik",
"deleteConfirmTitle": "Usunąć wynik laboratoryjny?",
"deleteConfirmDescription": "Ten wynik laboratoryjny zostanie trwale usunięty.",
"deletedToast": "Wynik usunięty",
"deleteError": "Nie udało się usunąć wyniku",
"loadError": "Nie udało się wczytać wyników",
+10 -11
View File
@@ -2,9 +2,10 @@
import { useMemo } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { FlaskConical, Trash2 } from "lucide-react";
import { FlaskConical } from "lucide-react";
import { toast } from "sonner";
import { DeleteButton } from "@/components/data-list";
import { Button } from "@/components/ui/button";
import {
Card,
@@ -166,16 +167,14 @@ export function LabList({ onAddFirst }: { onAddFirst?: () => void } = {}) {
</CardTitle>
<CardAction className="flex items-center gap-3">
<LabTrendSparkline values={group.readings.map((r) => r.value)} />
<Button
variant="ghost"
size="icon"
className="text-muted-foreground hover:text-destructive"
aria-label={t("labs.deleteLatest")}
disabled={deleteMutation.isPending}
onClick={() => deleteMutation.mutate(group.latest.id)}
>
<Trash2 className="h-4 w-4" />
</Button>
<DeleteButton
onConfirm={() => deleteMutation.mutate(group.latest.id)}
title={t("labs.deleteConfirmTitle")}
description={t("labs.deleteConfirmDescription")}
confirmLabel={t("labs.deleteLatest")}
className="size-9"
iconClassName="h-4 w-4"
/>
</CardAction>
</CardHeader>
<CardContent>
@@ -13,9 +13,10 @@
* relative to "now" but never recomputes the cadence.
*/
import { useState } from "react";
import { CheckCircle2, Plus, Trash2 } from "lucide-react";
import { CheckCircle2, Plus } from "lucide-react";
import { useTranslations } from "@/lib/i18n/context";
import { DeleteButton } from "@/components/data-list";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
@@ -365,16 +366,14 @@ function VorsorgeCard({
<CheckCircle2 className="mr-1 h-4 w-4" />
{t("measurementReminders.markDone")}
</Button>
<Button
type="button"
size="sm"
variant="ghost"
onClick={onRemove}
disabled={busy}
aria-label={t("measurementReminders.delete")}
>
<Trash2 className="h-4 w-4" />
</Button>
<DeleteButton
onConfirm={onRemove}
title={t("measurementReminders.deleteConfirmTitle")}
description={t("measurementReminders.deleteConfirmDescription")}
confirmLabel={t("measurementReminders.delete")}
className="size-9"
iconClassName="h-4 w-4"
/>
</CardAction>
</CardHeader>
<CardContent className="space-y-1">