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:
Khalid Abdi
2026-06-17 19:23:41 +03:00
parent 96bda1b902
commit d37a4e9425
15 changed files with 467 additions and 10 deletions
+4
View File
@@ -44,3 +44,7 @@ export function createDispense(input: DispenseInput): Promise<Dispense> {
body: JSON.stringify(input),
});
}
export function deleteDispense(id: string): Promise<void> {
return apiFetch<void>(`/api/dispenses/${id}`, { method: "DELETE" });
}
+52 -5
View File
@@ -405,7 +405,17 @@
"date": "Date",
"status": "Status",
"notes": "Notes",
"courseDates": "Course"
"courseDates": "Course",
"delete": "Delete prescription"
},
"delete": {
"title": "Delete prescription?",
"body": "Permanently delete the {{medication}} prescription for {{name}}. This cannot be undone.",
"confirm": "Delete",
"cancel": "Cancel",
"doneTitle": "Prescription deleted",
"failedTitle": "Couldn't delete prescription",
"failedBody": "Please try again."
},
"dialog": {
"title": "New prescription",
@@ -472,7 +482,15 @@
"dispensed": {
"title": "Recently dispensed",
"description": "Medications handed to patients at the pharmacy.",
"empty": "Nothing dispensed yet."
"empty": "Nothing dispensed yet.",
"delete": "Delete record",
"deleteTitle": "Delete dispense record?",
"deleteBody": "Remove the {{medication}} dispense record for {{name}}. This only corrects the ledger.",
"deleteConfirm": "Delete",
"deleteCancel": "Cancel",
"deletedTitle": "Dispense record deleted",
"deleteFailedTitle": "Couldn't delete record",
"deleteFailedBody": "Please try again."
}
},
"inventory": {
@@ -526,7 +544,17 @@
"detail": {
"description": "Stock item",
"notes": "Notes",
"close": "Close"
"close": "Close",
"delete": "Delete item"
},
"delete": {
"title": "Delete inventory item?",
"body": "Permanently delete {{name}} from inventory. This cannot be undone.",
"confirm": "Delete",
"cancel": "Cancel",
"doneTitle": "Item deleted",
"failedTitle": "Couldn't delete item",
"failedBody": "Please try again."
}
},
"lab": {
@@ -577,7 +605,16 @@
"recent": {
"title": "Recent results",
"description": "Analyses recorded on patient records, newest first.",
"empty": "No results recorded yet."
"empty": "No results recorded yet.",
"delete": "Delete result",
"deleteTitle": "Delete lab result?",
"deleteBody": "Remove the {{test}} result from {{name}}'s record. This cannot be undone.",
"deleteConfirm": "Delete",
"deleteCancel": "Cancel",
"deletedTitle": "Result deleted",
"deletedBody": "Removed {{test}} from {{name}}'s record.",
"deleteFailedTitle": "Couldn't delete result",
"deleteFailedBody": "Please try again."
},
"toast": {
"updateFailedTitle": "Couldn't update the task",
@@ -650,7 +687,17 @@
"details": "Details",
"reopen": "Reopen task",
"complete": "Mark complete",
"moveTo": "Move to"
"moveTo": "Move to",
"delete": "Delete task"
},
"delete": {
"title": "Delete task?",
"body": "Permanently delete \"{{title}}\". This cannot be undone.",
"confirm": "Delete",
"cancel": "Cancel",
"doneTitle": "Task deleted",
"failedTitle": "Couldn't delete task",
"failedBody": "Please try again."
},
"toast": {
"needSubjectTitle": "Add a subject",
+21
View File
@@ -140,6 +140,27 @@ export async function deletePatient(fileNumber: string): Promise<void> {
);
}
// Remove a single lab result from a patient's record. The lab has no id on the
// client, so it's identified by name + value + takenAt (DELETE
// /api/patients/:fileNumber/labs, gated by `lab:write`). Returns the updated
// patient.
export async function deleteLab(
fileNumber: string,
lab: Pick<Lab, "name" | "value" | "takenAt">,
): Promise<Patient> {
return apiFetch<Patient>(
`/api/patients/${encodeURIComponent(fileNumber.trim())}/labs`,
{
method: "DELETE",
body: JSON.stringify({
name: lab.name,
value: lab.value,
takenAt: lab.takenAt,
}),
},
);
}
// Reassign a patient to another clinician (sets their primary provider + PCP).
export async function transferPatient(
fileNumber: string,