mirror of
https://github.com/temetro/temetro.git
synced 2026-08-27 19:06:52 +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,11 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { Trash2 } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Sheet,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetPanel,
|
||||
SheetPopup,
|
||||
@@ -30,10 +33,14 @@ export function PrescriptionDetailSheet({
|
||||
rx,
|
||||
open,
|
||||
onOpenChange,
|
||||
onDelete,
|
||||
}: {
|
||||
rx: Prescription | null;
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
// Optional: only the Prescriptions page (full clinician) passes this, so the
|
||||
// shared sheet stays read-only when opened from Pharmacy.
|
||||
onDelete?: () => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
@@ -135,6 +142,14 @@ export function PrescriptionDetailSheet({
|
||||
</div>
|
||||
)}
|
||||
</SheetPanel>
|
||||
{rx && onDelete && (
|
||||
<SheetFooter>
|
||||
<Button onClick={onDelete} type="button" variant="destructive">
|
||||
<Trash2 className="size-4" />
|
||||
{t("prescriptions.detail.delete")}
|
||||
</Button>
|
||||
</SheetFooter>
|
||||
)}
|
||||
</SheetPopup>
|
||||
</Sheet>
|
||||
);
|
||||
|
||||
@@ -14,11 +14,13 @@ import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { ConfirmDialog } from "@/components/ui/confirm-dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
type Prescription,
|
||||
type RxStatus,
|
||||
createPrescription,
|
||||
deletePrescription,
|
||||
formatPrescribedAt,
|
||||
listPrescriptions,
|
||||
} from "@/lib/prescriptions";
|
||||
@@ -130,6 +132,7 @@ export function PrescriptionsView() {
|
||||
const [list, setList] = useState<Prescription[]>([]);
|
||||
const [selected, setSelected] = useState<Prescription | null>(null);
|
||||
const [sheetOpen, setSheetOpen] = useState(false);
|
||||
const [confirmOpen, setConfirmOpen] = useState(false);
|
||||
const [query, setQuery] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
@@ -151,6 +154,24 @@ export function PrescriptionsView() {
|
||||
setSheetOpen(true);
|
||||
};
|
||||
|
||||
const removeRx = async () => {
|
||||
if (!selected) return;
|
||||
const id = selected.id;
|
||||
try {
|
||||
await deletePrescription(id);
|
||||
setList((prev) => prev.filter((r) => r.id !== id));
|
||||
setSheetOpen(false);
|
||||
notify.success(t("prescriptions.delete.doneTitle"), selected.medication);
|
||||
} catch {
|
||||
notify.error(
|
||||
t("prescriptions.delete.failedTitle"),
|
||||
t("prescriptions.delete.failedBody"),
|
||||
);
|
||||
} finally {
|
||||
setConfirmOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Persist a new prescription, then add the saved record to the top of the list.
|
||||
const addPrescription = async (rx: NewPrescription) => {
|
||||
try {
|
||||
@@ -273,10 +294,28 @@ export function PrescriptionsView() {
|
||||
/>
|
||||
|
||||
<PrescriptionDetailSheet
|
||||
onDelete={() => setConfirmOpen(true)}
|
||||
onOpenChange={setSheetOpen}
|
||||
open={sheetOpen}
|
||||
rx={selected}
|
||||
/>
|
||||
|
||||
<ConfirmDialog
|
||||
cancelLabel={t("prescriptions.delete.cancel")}
|
||||
confirmLabel={t("prescriptions.delete.confirm")}
|
||||
description={
|
||||
selected
|
||||
? t("prescriptions.delete.body", {
|
||||
medication: selected.medication,
|
||||
name: selected.name,
|
||||
})
|
||||
: undefined
|
||||
}
|
||||
onConfirm={removeRx}
|
||||
onOpenChange={setConfirmOpen}
|
||||
open={confirmOpen}
|
||||
title={t("prescriptions.delete.title")}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user