import type { Appointment } from "fhir/r4"; /** * WHAT AN APPOINTMENT IS FOR, on every surface that shows a row for one. * * MEASURED, 2026-08-30: a self-booked visit read "Routine" on the front-desk calendar and on the * patient's own upcoming list, for an appointment booked as a Consultation. Nothing was wrong with the * record - the service was on it the whole time - but three screens were rendering * `appointmentType` in the slot where a reader looks to find out what the visit is. * * AND appointmentType IS A CONSTANT FOR SELF-BOOKINGS. Patient self-booking hardcodes ROUTINE at the * form default and forces it again on reset; there is no control anywhere in that flow that changes it. * So the column was the same word on every row a patient will ever create, occupying the position a * receptionist scans - and answering a question nobody asked. * * WHY THIS IS ONE HELPER RATHER THAN THREE EDITS. `getAppointmentTypeDisplay` already existed as three * separate copies - the appointments calendar, the receptionist details dialog, and the task assignment * modal - and the comment above one of them is a warning written by whoever last paid for that: * "There were THREE copies of this idea across the app and they disagreed... Do not reintroduce a local * copy. Same question same answer, everywhere." This is that advice applied to the next question. */ /** The HL7 v2 ADT-0008 code every self-booking carries, and the only one that carries no information. */ const ROUTINE_CODE = "ROUTINE"; const trimmed = (value: string | undefined): string | undefined => { const text = value?.trim(); return text ? text : undefined; }; /** The service the visit was booked for, as a person would say it. */ const serviceLabel = (appointment: Appointment): string | undefined => { for (const concept of appointment.serviceType ?? []) { const label = trimmed(concept.text) ?? trimmed(concept.coding?.find((coding) => trimmed(coding.display))?.display); if (label) return label; } return undefined; }; /** The appointment type, as a person would say it. */ const typeLabel = (appointment: Appointment): string | undefined => trimmed(appointment.appointmentType?.text) ?? trimmed(appointment.appointmentType?.coding?.find((coding) => trimmed(coding.display))?.display); /** Is the appointment type something other than the routine default? */ const typeIsNotable = (appointment: Appointment): boolean => { const codes = (appointment.appointmentType?.coding ?? []) .map((coding) => trimmed(coding.code)?.toUpperCase()) .filter((code): code is string => Boolean(code)); // No code at all is not "notable" - it is unknown, and an unknown must not be dressed up as a // deliberate choice. A walk-in is a decision somebody made; a missing code is an absence. if (codes.length === 0) return false; return !codes.every((code) => code === ROUTINE_CODE); }; export interface AppointmentSubject { /** * What the visit is FOR. The service when one is recorded, otherwise exactly what these surfaces * showed before - so a record with no service reads no worse than it does today. */ label: string; /** * The appointment type, but ONLY when it says something. * * CONTROL, and the reason this is not simply a swap: a walk-in and an emergency must stay * distinguishable from a booked visit. Replacing the type with the service outright would delete the * only place that distinction is shown. So a NON-routine type survives beside the service; the * routine default, which is every self-booking and carries nothing, does not. */ notableType?: string; } export const describeAppointmentSubject = (appointment: Appointment): AppointmentSubject => { const service = serviceLabel(appointment); const type = typeLabel(appointment); return { // The fallback chain ends where the old helpers ended, deliberately: this must never render an // empty cell on a record that produced a word before. label: service ?? type ?? "Appointment", notableType: typeIsNotable(appointment) && type && type !== service ? type : undefined, }; }; /** The one line a row shows: the service, with a non-routine type marked beside it. */ export const appointmentSubjectLine = (appointment: Appointment): string => { const { label, notableType } = describeAppointmentSubject(appointment); return notableType ? `${label} ยท ${notableType}` : label; };