import type { Bundle, Reference, ServiceRequest } from "fhir/r4"; import type { DirectoryLocation } from "../hooks/useReferralDirectory"; import { readOrderReferralState } from "./referralQueue"; /** * A REFERRAL IS THE PATIENT'S TO BOOK, read from the order itself (Spencer, 2026-09-06). * * The referral-coded Task is the coordinator's work item and stays off the patient's list; the * `ServiceRequest` is the referral, and the patient may read it. */ export const REFERRAL_PATIENT_BOOKED_EXTENSION_URL = "https://akashichealthrecords.com/fhir/StructureDefinition/referral-patient-booked"; /** The patient's "Not now" to inviting the recipient, kept on the order so it holds on every device. */ export const REFERRAL_INVITE_DECLINED_EXTENSION_URL = "https://akashichealthrecords.com/fhir/StructureDefinition/referral-invite-declined"; /** How to reach the recipient, carried on the performer from the directory entry chosen at placement. */ export const REFERRAL_RECIPIENT_CONTACT_EXTENSION_URL = "https://akashichealthrecords.com/fhir/StructureDefinition/referral-recipient-contact"; export type PatientReferralStage = "choosing" | "book" | "booked"; export interface PatientReferral { id: string; title: string; practice?: string; practitioner?: string; /** The recipient's Akashic organization, once one is named on the order. */ practiceOrganizationId?: string; onAkashic: boolean; address?: string; phone?: string; referredBy?: string; authoredOn?: string; reason?: string; stage: PatientReferralStage; bookedByPatientAt?: string; inviteDeclinedAt?: string; /** The recipient's NPI, when the directory entry chosen at placement carried one. */ recipientNpi?: string; } // The placement dialog writes "Practitioner — Practice" when a person was chosen. const NAME_SEPARATOR = " — "; const contactOf = (performer: Reference | undefined) => { const contact = performer?.extension?.find((e) => e.url === REFERRAL_RECIPIENT_CONTACT_EXTENSION_URL); const part = (url: string) => contact?.extension?.find((e) => e.url === url)?.valueString?.trim() || undefined; return { address: part("address"), phone: part("phone") }; }; const reasonOf = (order: ServiceRequest): string | undefined => { const reason = order.reasonCode?.[0]; return reason?.text?.trim() || reason?.coding?.[0]?.display?.trim() || undefined; }; export const patientBookedAt = (order: ServiceRequest): string | undefined => order.extension?.find((e) => e.url === REFERRAL_PATIENT_BOOKED_EXTENSION_URL)?.valueDateTime; const inviteDeclinedAt = (order: ServiceRequest): string | undefined => order.extension?.find((e) => e.url === REFERRAL_INVITE_DECLINED_EXTENSION_URL)?.valueDateTime; export const patientReferral = (order: ServiceRequest): PatientReferral | undefined => { const state = readOrderReferralState(order); if (!order.id || !state || state === "expired") return undefined; const performers = order.performer ?? []; const onPlatform = performers.find((p) => p.reference?.startsWith("Organization/")); const named = performers.find((p) => !p.reference && p.display?.trim()); const [first, second] = (named?.display ?? "").split(NAME_SEPARATOR).map((part) => part.trim()); const practice = onPlatform?.display?.trim() || (second ? second : first) || undefined; const bookedByPatientAt = patientBookedAt(order); const stage: PatientReferralStage = state === "scheduled" || bookedByPatientAt ? "booked" : performers.length === 0 ? "choosing" : "book"; const specialty = order.performerType?.text?.trim() || order.performerType?.coding?.[0]?.display?.trim(); return { id: order.id, title: practice ? `Book with ${practice}` : specialty ? `A ${specialty.toLowerCase()} referral` : "A referral", practice, practitioner: second ? first : undefined, practiceOrganizationId: onPlatform?.reference?.split("/")[1], onAkashic: performers.some((p) => Boolean(p.reference)), ...contactOf(named), referredBy: order.requester?.display?.trim() || undefined, authoredOn: order.authoredOn, reason: reasonOf(order), stage, bookedByPatientAt, inviteDeclinedAt: inviteDeclinedAt(order), recipientNpi: named?.identifier?.value?.trim() || undefined, }; }; export const patientReferrals = (bundle: Bundle | undefined): PatientReferral[] => (bundle?.entry ?? []) .map((entry) => entry.resource) .filter((resource): resource is ServiceRequest => resource?.resourceType === "ServiceRequest") .map(patientReferral) .filter((referral): referral is PatientReferral => Boolean(referral)); /** The patient may say they booked only where no booking here can say it for them. */ export const patientMayMarkBooked = (referral: PatientReferral): boolean => referral.stage === "book" && !referral.onAkashic; export const referralDay = (iso: string | undefined): string | undefined => { if (!iso) return undefined; const date = new Date(iso); if (Number.isNaN(date.getTime())) return undefined; return new Intl.DateTimeFormat("en-US", { month: "short", day: "numeric" }).format(date); }; /** The performer's contact extension, or nothing when the directory entry gave neither part. */ export const recipientContactExtension = (contact?: { address?: string; phone?: string }) => { const parts = (["address", "phone"] as const) .map((url) => ({ url, valueString: contact?.[url]?.trim() })) .filter((part): part is { url: "address" | "phone"; valueString: string } => Boolean(part.valueString)); return parts.length ? { extension: [{ url: REFERRAL_RECIPIENT_CONTACT_EXTENSION_URL, extension: parts }] } : {}; }; /** One line of address and the phone, from the registry location the referral was addressed to. */ export const contactFromDirectoryLocation = (location?: DirectoryLocation) => { if (!location) return undefined; const cityLine = [location.city, [location.state, location.postalCode].filter(Boolean).join(" ")] .filter(Boolean) .join(", "); const address = [location.street, location.street2, cityLine].filter(Boolean).join(", "); return { address: address || undefined, phone: location.phone || undefined }; };