import { useState } from "react"; import { Activity } from "lucide-react"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from "../../../components/ui/dialog"; /** * The reopen dialog, shared by both reopen buttons (the queue's focus panel and the open encounter) so * they ask the same question. It is the app's dialog rather than `window.prompt`, which a browser can * suppress. Confirm stays disabled until a non-blank reason is typed; dismissing writes nothing. */ export const REOPEN_REASON_QUESTION = "Reopening this visit is recorded in the patient’s history. Why are you reopening it?"; /** * The ask, and the dialog that does the asking. * * A HOOK RATHER THAN A FUNCTION CALL, because a dialog cannot answer synchronously the way `prompt` did. * `ask()` opens it; `dialog` is rendered by the caller. Both call sites get the same wording, the same * dismissal behaviour and the same required reason. */ export const useReopenReason = ( onReopen: (reason: string) => void, ): { ask: () => void; dialog: React.ReactNode } => { const [open, setOpen] = useState(false); const [reason, setReason] = useState(""); const answer = reason.trim(); const confirm = () => { if (!answer) return; setOpen(false); onReopen(answer); }; return { ask: () => { // Cleared on the way IN, not on the way out: a reason typed and then dismissed must not be sitting // there the next time somebody opens this, on a different visit. setReason(""); setOpen(true); }, dialog: ( { // DISMISSAL IS A CANCEL, and it is the only way out other than the button. `onOpenChange` // fires for Escape, the close control and a press outside; none of them calls `onReopen`, so // nothing is written. The card's first control is exactly this. setOpen(next); }} > Reopen this visit?
{/* Says the reason is KEPT, and where. A dialog that only asked "why?" would collect a shrug; this is why the wording survived the move from the browser's prompt intact. */}

{REOPEN_REASON_QUESTION}

{/* NO `autoFocus`. The a11y rule refuses it and Radix already moves focus into the dialog on open, so the attribute bought a keystroke and cost a ratchet. */}
{/* NO CANCEL BUTTON. Dismissal is Escape, the close control or a press outside - the app's convention everywhere, and a Cancel button beside a primary action is a second way to do the thing the dialog already does. */}
), }; };