import { ServiceRequest, Task } from 'fhir/r4'; /** * - SORTING A COORDINATOR'S REFERRALS INTO THE TWO COLUMNS THEY WORK IN. * * Pure, so the columns can be reasoned about without a rendered page or a network call. The workspace * itself is thin on top of this. */ export const AKASHIC_TASK_TYPE_SYSTEM = 'https://akashichealthrecords.com/fhir/CodeSystem/task-type'; export const REFERRAL_TASK_CODE = 'referral'; export const AKASHIC_REFERRAL_STATE_SYSTEM = 'https://akashichealthrecords.com/fhir/CodeSystem/referral-state'; export const REFERRAL_ORDER_STATE_EXTENSION_URL = 'https://akashichealthrecords.com/fhir/StructureDefinition/referral-state'; export type ReferralState = 'sent' | 'delivered' | 'claimed' | 'scheduled' | 'expired' | 'withdrawn'; // `withdrawn` is the sender's own closed state (2026-10-01): never read as expired. const STATES: readonly string[] = ['sent', 'delivered', 'claimed', 'scheduled', 'expired', 'withdrawn']; /** Claimed and Scheduled take the blue info pill; a closure reason or any other state stays neutral. */ export const referralPillClass = (state?: ReferralState, closed?: boolean): string => !closed && (state === 'claimed' || state === 'scheduled') ? 'ak-pill ak-pill--info' : 'ak-pill'; export const isReferralState = (value: unknown): value is ReferralState => typeof value === 'string' && STATES.includes(value); /** * - WHY A REFERRAL WAS CLOSED, said to the practice that sent it. * * Spencer ruled it on 2026-08-24, choosing *the coordinator closes it with a reason, and the sending * practice sees the reason* over a bare *"it ended"*, and the argument was about the patient rather than * about tidiness: *"they declined"* and *"we sent it to the wrong place"* lead the sender to do * different things for somebody who still needs care. * * THE SENDER COULD NOT TELL THEM APART. Measured 2026-09-13 on the coordinator's own queue: two closed * referrals both rendered **Expired**, the state an untouched referral reaches by running out of time. * The reason was on the shared order the whole time and simply never left the server. * * FOUR CODES AND NO FREE TEXT, which is the server's fence and not this file's: the value crosses an * organization boundary, and a sentence somebody types about a patient is a disclosure surface. These * labels are the receiving practice's own words from the closure control, kept identical on purpose - * the sentence the coordinator chose is the sentence the sender reads. */ export const REFERRAL_CLOSURE_REASON_LABELS: Record = { 'declined-by-patient': 'The patient declined', duplicate: 'Duplicate of another referral', 'not-a-service-we-offer': 'Not a service they offer', 'unable-to-reach-patient': 'They could not reach the patient', }; /** * The label for a closure reason, or `undefined` for a referral that carries none. * * UNDEFINED RATHER THAN A FALLBACK SENTENCE, deliberately: a referral that expired on the clock and one * closed for a reason nobody has taught this map are different, and inventing *"Closed"* for the second * would state something nobody checked. An unknown code leaves the state label alone. */ export const referralClosureReasonLabel = (reason?: string): string | undefined => reason ? REFERRAL_CLOSURE_REASON_LABELS[reason] : undefined; /** The patient's word that they booked, said as theirs; it never replaces the referral's state. */ export const patientBookedLine = (patientBookedAt?: string): string | undefined => { if (!patientBookedAt) return undefined; const date = new Date(patientBookedAt); if (Number.isNaN(date.getTime())) return 'Patient says booked'; return `Patient says booked ยท ${new Intl.DateTimeFormat('en-US', { month: 'short', day: 'numeric' }).format(date)}`; }; export const isReferralTask = (task: Task): boolean => (task.code?.coding ?? []).some( (coding) => coding.system === AKASHIC_TASK_TYPE_SYSTEM && coding.code === REFERRAL_TASK_CODE, ); /** The state the coordinator's own Task carries - their working copy of where this got to. */ export const readTaskReferralState = (task: Task): ReferralState | undefined => { const code = (task.businessStatus?.coding ?? []).find( (coding) => coding.system === AKASHIC_REFERRAL_STATE_SYSTEM, )?.code; return isReferralState(code) ? code : undefined; }; /** The state the shared ORDER carries - the one both practices read, and the sender's source of truth. */ export const readOrderReferralState = (order?: ServiceRequest): ReferralState | undefined => { const code = (order?.extension ?? []).find( (extension) => extension.url === REFERRAL_ORDER_STATE_EXTENSION_URL, )?.valueCode; return isReferralState(code) ? code : undefined; }; export const REFERRAL_CLOSURE_REASON_EXTENSION_URL = 'https://akashichealthrecords.com/fhir/StructureDefinition/referral-closure-reason'; /** The code the receiving practice closed the order with, or `undefined` when it carries none. */ export const readOrderClosureReason = (order?: ServiceRequest): string | undefined => (order?.extension ?? []).find((extension) => extension.url === REFERRAL_CLOSURE_REASON_EXTENSION_URL)?.valueCode; /** * WHETHER A REFERRAL ROUTED TO A PRACTICE ON AKASHIC REACHED IT, as the order records it. The server writes * `pending` with the order, then `delivered` or `failed` once delivery has run; an order never routed in-system * carries none. A code this does not know is read as no outcome, never as one. */ export const REFERRAL_IN_SYSTEM_DELIVERY_EXTENSION_URL = 'https://akashichealthrecords.com/fhir/extensions/referral-in-system-delivery'; export type ReferralDeliveryOutcome = 'pending' | 'delivered' | 'failed'; /** The sender's words for each outcome, on the coordinator's Outbound row and the patient's chart alike. */ export const REFERRAL_DELIVERY_LABELS: Record = { failed: 'Delivery failed', pending: 'Delivery not confirmed', delivered: 'Delivered', }; export const readOrderInSystemDelivery = (order?: ServiceRequest): ReferralDeliveryOutcome | undefined => { const code = (order?.extension ?? []).find( (extension) => extension.url === REFERRAL_IN_SYSTEM_DELIVERY_EXTENSION_URL, )?.valueCode; return code === 'pending' || code === 'delivered' || code === 'failed' ? code : undefined; }; export type ReferralDirection = 'outbound' | 'inbound'; /** * WHICH COLUMN A REFERRAL BELONGS IN, and it is decided by WHO PLACED THE ORDER - never by who is * looking. * * The design's two columns are *"referrals this practice is sending"* and *"referrals arriving here"*. * The honest discriminator is the order's `requester`: if this organization asked for it, it is outbound; * otherwise it arrived. Deciding from the Task's owner instead would put a referral in the wrong column * the moment a coordinator reassigns it, which is an ordinary thing to do. * * AN UNKNOWN REQUESTER READS AS INBOUND, and that is the safe direction rather than an oversight. Most * referrals arriving today are typed in by hand from a fax, because the sender is not on Akashic - so * "somebody sent this to us and we do not know who" is the ordinary case, not an error. Defaulting to * OUTBOUND would put another practice's referral in the list this practice believes it sent. */ export const referralDirection = ( order: ServiceRequest | undefined, organizationId: string | undefined, /** * The practice the requester belongs to, resolved by the server. An outgoing referral names the * ordering PractitionerRole rather than the practice, so the reference alone can no longer answer * this - and the client cannot resolve a role. Absent, the Organization rule below still applies, * which is what an inbound referral logged off a fax carries. */ requesterOrganizationId?: string, ): ReferralDirection => { const requester = order?.requester?.reference; if (!organizationId) return 'inbound'; if (requesterOrganizationId) { return requesterOrganizationId === organizationId ? 'outbound' : 'inbound'; } if (!requester) return 'inbound'; return requester === `Organization/${organizationId}` ? 'outbound' : 'inbound'; }; export interface ReferralQueueItem { taskId?: string; orderId?: string; direction: ReferralDirection; /** The ORDER's state, falling back to the Task's. See the note on `referralQueueItem`. */ state?: ReferralState; patientReference?: string; /** Where it was sent - an organization, a specialty, or nobody yet. All three are legitimate. */ performerDisplay?: string; authoredOn?: string; } /** * THE ORDER'S STATE WINS, AND THE TASK'S IS THE FALLBACK. Spencer ruled on 2026-08-21 that the shared * order carries the state precisely so both practices read one fact - so a screen that preferred the local * Task would show the sender their own stale copy and call it the truth, which is the exact failure the * ruling exists to prevent. * * The Task's copy is still read, because a referral whose order has not been fetched (or that predates * the order carrying state) should render as what the coordinator last knew rather than as blank. */ export const referralQueueItem = ( task: Task, order: ServiceRequest | undefined, organizationId: string | undefined, ): ReferralQueueItem => ({ taskId: task.id, orderId: order?.id ?? task.focus?.reference?.split('/').pop(), direction: referralDirection(order, organizationId), state: readOrderReferralState(order) ?? readTaskReferralState(task), patientReference: task.for?.reference, performerDisplay: (order?.performer ?? [])[0]?.display, authoredOn: order?.authoredOn ?? task.authoredOn, }); /** * NEWEST FIRST, and a missing date sorts LAST rather than first. * * An undefined `authoredOn` compared with `>` is not merely "unsorted" - it lands wherever the sort * happens to leave it, so a referral with no date can appear at the top of a coordinator's queue as though * it were the most recent thing that happened. Undated is unknown, and unknown is not urgent. */ export const sortReferrals = (items: T[]): T[] => [...items].sort((left, right) => { if (!left.authoredOn && !right.authoredOn) return 0; if (!left.authoredOn) return 1; if (!right.authoredOn) return -1; return right.authoredOn.localeCompare(left.authoredOn); }); export interface ReferralColumns { outbound: ReferralQueueItem[]; inbound: ReferralQueueItem[]; } export const referralColumns = ( tasks: Task[], ordersById: Record, organizationId: string | undefined, ): ReferralColumns => { const items = tasks .filter(isReferralTask) .map((task) => { const orderId = task.focus?.reference?.split('/').pop(); return referralQueueItem(task, orderId ? ordersById[orderId] : undefined, organizationId); }); return { outbound: sortReferrals(items.filter((item) => item.direction === 'outbound')), inbound: sortReferrals(items.filter((item) => item.direction === 'inbound')), }; };