import { useState } from "react"; import { AlertCircle } from "lucide-react"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "../../../components/ui/dialog.tsx"; import { Alert, AlertDescription } from "../../../components/ui/alert.tsx"; import { Button } from "../../../components/ui/button.tsx"; import { Label } from "../../../components/ui/label.tsx"; import { Textarea } from "../../../components/ui/textarea.tsx"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from "../../../components/ui/select.tsx"; import type { BenchRow, RejectionInput, RejectionOutcome } from "../../../hooks/useBench.ts"; import { ActWithdrawn } from "../DiagnosticOrdersPage/ActWithdrawn.tsx"; interface Props { row?: BenchRow; onClose: () => void; /** Rejects with the words to show when the refusal could not be confirmed. */ onReject: (row: BenchRow, input: RejectionInput) => Promise; /** The caller may no longer make this write: the dialog stays readable and closable, and cannot send. */ withdrawn?: boolean; } // Each line is what the server confirmed, so a task or a message that failed says so. const outcomeLines = (outcome: RejectionOutcome, reason: string): string[] => [ outcome.alreadyRecorded ? "This rejection was already recorded: " + reason + "." : "Specimen rejected: " + reason + ".", "The order stays open. Record receipt only when the replacement specimen arrives.", ...(outcome.senderNotified === "delivered" ? ["The ordering practice has been told and arranges recollection."] : outcome.senderNotified === "failed" ? ["The ordering practice could not be told. Contact them directly."] : outcome.patientTaskRaised ? ["The patient has a task to give another sample."] : ["The patient’s redraw task could not be raised. Ask them to return another way."]), ]; export const RejectSpecimenDialog = ({ row, onClose, onReject, withdrawn }: Props) => { // One refusal, one attempt: a retry after a lost answer finishes it instead of starting another. const [attemptId] = useState(() => crypto.randomUUID()); const [reasonCode, setReasonCode] = useState(""); const [note, setNote] = useState(""); const [busy, setBusy] = useState(false); const [error, setError] = useState(); const [outcome, setOutcome] = useState(); if (!row) return null; const reasons = (row.rejectionReasons ?? []).filter((each) => each.code); const displayOf = (code: string) => reasons.find((each) => each.code === code)?.display ?? code; const identity = [row.patientDisplay ?? "Patient not recorded", row.test ?? "Test not recorded"].join(" · "); const detail = [row.orderedBy, row.accession].filter(Boolean).join(" · "); const submit = async () => { if (!reasonCode) return; setBusy(true); setError(undefined); try { setOutcome(await onReject(row, { attemptId, reasonCode, note })); } catch (failure) { setError(failure instanceof Error ? failure.message : String(failure)); } finally { setBusy(false); } }; return ( { if (!open && !busy) onClose(); }}> {outcome ? "Recollection needed" : "Reject specimen"}
{identity} {detail ? {detail} : null}
{outcome ? (
{outcomeLines(outcome, displayOf(outcome.reason ?? reasonCode)).map((line) => (

{line}

))}
) : ( <>