mirror of
https://github.com/temetro/temetro.git
synced 2026-08-24 08:46:27 +00:00
feat: delete controls across add-pages (lab, dispense, rx, inventory, tasks)
Backend: - DELETE /api/patients/:fileNumber/labs (remove one lab result, lab:write) - DELETE /api/dispenses/:id (void a ledger entry, inventory:write) Frontend (all guarded by ConfirmDialog): - lab "Recent results" rows: delete result - pharmacy "Recently dispensed" rows: delete record - prescriptions/tasks detail sheets + inventory detail dialog gain a delete action (prescription delete stays off the shared Pharmacy sheet) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { Check, ChevronDown, FlaskConical, Plus, Search } from "lucide-react";
|
||||
import {
|
||||
Check,
|
||||
ChevronDown,
|
||||
FlaskConical,
|
||||
Plus,
|
||||
Search,
|
||||
Trash2,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
type FormEvent,
|
||||
type KeyboardEvent,
|
||||
@@ -19,6 +26,7 @@ import {
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible";
|
||||
import { ConfirmDialog } from "@/components/ui/confirm-dialog";
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
@@ -37,6 +45,7 @@ import {
|
||||
type LabFlag,
|
||||
type Patient,
|
||||
appendLabs,
|
||||
deleteLab,
|
||||
listPatients,
|
||||
} from "@/lib/patients";
|
||||
import { type Priority, type Task, listTasks, updateTask } from "@/lib/tasks";
|
||||
@@ -454,6 +463,8 @@ export function LabView() {
|
||||
const [patients, setPatients] = useState<Patient[]>([]);
|
||||
const [recent, setRecent] = useState<RecentResult[]>([]);
|
||||
const [addOpen, setAddOpen] = useState(false);
|
||||
// The result staged for deletion (drives the confirm dialog).
|
||||
const [toDelete, setToDelete] = useState<RecentResult | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
@@ -497,6 +508,37 @@ export function LabView() {
|
||||
});
|
||||
};
|
||||
|
||||
// Remove a result from the feed + the patient's record.
|
||||
const confirmDelete = async () => {
|
||||
if (!toDelete) return;
|
||||
const { patient, lab } = toDelete;
|
||||
try {
|
||||
await deleteLab(patient.fileNumber, lab);
|
||||
setRecent((prev) =>
|
||||
prev.filter(
|
||||
(r) =>
|
||||
!(
|
||||
r.patient.fileNumber === patient.fileNumber &&
|
||||
r.lab.name === lab.name &&
|
||||
r.lab.value === lab.value &&
|
||||
r.lab.takenAt === lab.takenAt
|
||||
),
|
||||
),
|
||||
);
|
||||
notify.success(
|
||||
t("lab.recent.deletedTitle"),
|
||||
t("lab.recent.deletedBody", { test: lab.name, name: patient.name }),
|
||||
);
|
||||
} catch {
|
||||
notify.error(
|
||||
t("lab.recent.deleteFailedTitle"),
|
||||
t("lab.recent.deleteFailedBody"),
|
||||
);
|
||||
} finally {
|
||||
setToDelete(null);
|
||||
}
|
||||
};
|
||||
|
||||
// Optimistically flip done, then persist; roll back on failure.
|
||||
const toggle = async (id: string) => {
|
||||
const current = tasks.find((task) => task.id === id);
|
||||
@@ -669,6 +711,14 @@ export function LabView() {
|
||||
<Badge className="shrink-0" variant={flagVariant[lab.flag]}>
|
||||
{t(`patientCard.labFlag.${lab.flag}`)}
|
||||
</Badge>
|
||||
<button
|
||||
aria-label={t("lab.recent.delete")}
|
||||
className="shrink-0 rounded-md p-1 text-muted-foreground transition-colors hover:bg-accent hover:text-destructive-foreground"
|
||||
onClick={() => setToDelete({ patient, lab })}
|
||||
type="button"
|
||||
>
|
||||
<Trash2 className="size-4" />
|
||||
</button>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
@@ -681,6 +731,25 @@ export function LabView() {
|
||||
open={addOpen}
|
||||
patients={patients}
|
||||
/>
|
||||
|
||||
<ConfirmDialog
|
||||
cancelLabel={t("lab.recent.deleteCancel")}
|
||||
confirmLabel={t("lab.recent.deleteConfirm")}
|
||||
description={
|
||||
toDelete
|
||||
? t("lab.recent.deleteBody", {
|
||||
test: toDelete.lab.name,
|
||||
name: toDelete.patient.name,
|
||||
})
|
||||
: undefined
|
||||
}
|
||||
onConfirm={confirmDelete}
|
||||
onOpenChange={(o) => {
|
||||
if (!o) setToDelete(null);
|
||||
}}
|
||||
open={toDelete !== null}
|
||||
title={t("lab.recent.deleteTitle")}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user