import { useState } from "react"; import { useNavigate } from "react-router-dom"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "../ui/dialog.tsx"; import { DismissibleAlert } from "../ui/dismissible-alert"; import { initialsOf } from "../ui/org-badge.tsx"; import { PortalDepartureCard } from "../PortalDeparture/PortalDepartureCard"; import { TaskStatusRow } from "./TaskStatusRow"; import { useMyOrganizations } from "../../hooks/useMyOrganizations"; import { getPatientPortalUrl } from "../../utils/patientPortalUrl"; import { relayServerFailure } from "../../utils/fetchFailureMessage"; import { patientMayMarkBooked, referralDay, type PatientReferral, } from "../../utils/patientReferrals"; import "./TaskDialog.css"; const INVITE_PATH = "/dashboard/collaboration-teams"; /** The collaboration invite, with the recipient's NPI ready to look up when the order carries one. */ export const referralInvitePath = (referral: PatientReferral): string => referral.recipientNpi ? `${INVITE_PATH}?invite=${encodeURIComponent(referral.recipientNpi)}` : INVITE_PATH; /** * A referral the patient has to book, drawn as the deck's referral card * (`mockups/patient-portal/packets-checklists-and-referrals.html`, the three referral frames and the * one where the recipient is still being chosen). Its actions live here, not on the list row. */ export interface PatientReferralDialogProps { referral: PatientReferral | undefined; onClose: () => void; onMarkBooked: (referralId: string) => Promise; onDeclineInvite: (referralId: string) => Promise; } const statusOf = (referral: PatientReferral): { label: string; tone: "open" | "done" } => { if (referral.stage === "booked") return { label: "Booked", tone: "done" }; if (referral.stage === "choosing") return { label: "Being arranged", tone: "open" }; return { label: "To book", tone: "open" }; }; const headlineOf = (referral: PatientReferral): string | undefined => { if (referral.bookedByPatientAt) return `You marked this booked, ${referralDay(referral.bookedByPatientAt)}`; if (referral.stage === "booked") return "Booked"; const day = referralDay(referral.authoredOn); const lead = referral.stage === "choosing" ? "From" : "Referred by"; if (referral.referredBy) return day ? `${lead} ${referral.referredBy}, ${day}` : `${lead} ${referral.referredBy}`; return day ? `Referred ${day}` : undefined; }; const noteOf = (referral: PatientReferral): string | undefined => { if (referral.stage !== "book") return undefined; if (referral.onAkashic) return "Book through Akashic. This item is marked complete when you book."; const how = referral.phone ? "Call" : "Contact"; return `${how} ${referral.practice} to book, then mark this item complete. Their schedule is not available in Akashic.`; }; const reasonLine = (reason: string): string => `Referred for ${reason.charAt(0).toLowerCase()}${reason.slice(1).replace(/\.$/, "")}.`; const telHref = (phone: string): string => `tel:${phone.replace(/[^\d+]/g, "")}`; /** The practice's own portal, when it is one of the patient's practices and publishes one. */ const TheirPortal = ({ organizationId }: { organizationId: string }) => { const { organizations } = useMyOrganizations(); const portalUrl = getPatientPortalUrl(organizations.find((organization) => organization.id === organizationId)); return portalUrl ? : null; }; export const PatientReferralDialog = ({ referral, onClose, onMarkBooked, onDeclineInvite }: PatientReferralDialogProps) => { const navigate = useNavigate(); const [busy, setBusy] = useState(false); const [error, setError] = useState(); if (!referral) return null; const status = statusOf(referral); // Until a recipient is named, the mark is the referring practice's, the last part of "Dr. Ellis, Great River". const markName = referral.practice ?? referral.referredBy?.split(", ").pop() ?? referral.title; const note = noteOf(referral); const invitee = referral.practitioner ?? referral.practice; const showInvite = referral.stage === "booked" && !referral.onAkashic && Boolean(invitee) && !referral.inviteDeclinedAt; const close = () => { if (busy) return; setError(undefined); onClose(); }; const markBooked = async () => { setBusy(true); setError(undefined); try { await onMarkBooked(referral.id); } catch (failure: unknown) { setError(relayServerFailure(failure, "That could not be saved. Please try again.")); } finally { setBusy(false); } }; const notNow = async () => { setBusy(true); setError(undefined); try { await onDeclineInvite(referral.id); onClose(); } catch (failure: unknown) { setError(relayServerFailure(failure, "That could not be saved. Please try again.")); } finally { setBusy(false); } }; return ( { if (!next) close(); }}> Your referral A referral from your practice.

{referral.title}

{referral.practice ?? referral.title} {headlineOf(referral) && {headlineOf(referral)}}
{referral.practitioner && (
{referral.practitioner}
)} {referral.address && (
Where {referral.address}
)} {referral.phone && ( )} {referral.stage === "choosing" && (
Your practice is finding you a specialist We'll notify you when your practice has chosen one, with details for booking.
)} {note &&

{note}

} {referral.reason && referral.stage !== "booked" && (

{reasonLine(referral.reason)}

)} {showInvite && (

Would you like {invitee} to see your record? They are not on Akashic. You can invite them — they get their own free account, not one inside your practice, and they see only what you share.

If you invite them they can
  • Read the record you share with them
  • Message you directly
  • Join the care team around you

Only you can do this, and you can take it back at any time. Nobody is added to your record without you.

)} {error && ( setError(undefined)}> {error} )} {referral.stage === "book" && referral.onAkashic && referral.practiceOrganizationId && ( )} {patientMayMarkBooked(referral) && (
{referral.phone && ( Call them )}
)} {showInvite && (
)}
); }; export default PatientReferralDialog;