import type { CodeableConcept, Reference } from 'fhir/r4'; import { formatLongDate, formatTimeOfDay } from '../../utils/dateUtils'; // What a patient reads for a document's coded fields. Known codes get their plain meaning; words a record // already carries are kept; anything else is named as not recognised rather than guessed. const RECORD_STATUS: Record = { current: 'Current', superseded: 'Replaced by a newer version', 'entered-in-error': 'Entered in error', }; // Marking a document reviewed writes docStatus final, so final and amended read as reviewed. const REVIEW_STATUS: Record = { preliminary: 'Not reviewed yet', final: 'Reviewed by your care team', amended: 'Reviewed by your care team, then amended', 'entered-in-error': 'Entered in error', }; const CONFIDENTIALITY_SYSTEM = 'http://terminology.hl7.org/CodeSystem/v3-Confidentiality'; const CONFIDENTIALITY: Record = { U: 'Unrestricted', L: 'Low', M: 'Moderate', N: 'Normal', R: 'Restricted', V: 'Very restricted', }; const notRecognised = (code: string) => 'Not recognised (' + code + ')'; export const patientRecordStatus = (status?: string): string => status ? RECORD_STATUS[status] ?? notRecognised(status) : ''; export const patientReviewStatus = (docStatus?: string): string => docStatus ? REVIEW_STATUS[docStatus] ?? notRecognised(docStatus) : REVIEW_STATUS.preliminary; const conceptWords = (concept: CodeableConcept): string => { if (concept.text) return concept.text; const coding = concept.coding?.find((c) => c.display) ?? concept.coding?.[0]; if (!coding) return ''; if (coding.display) return coding.display; if (coding.system === CONFIDENTIALITY_SYSTEM && coding.code && CONFIDENTIALITY[coding.code]) { return CONFIDENTIALITY[coding.code]; } return coding.code ? notRecognised(coding.code) : ''; }; export const patientConceptWords = (concepts?: CodeableConcept[]): string => (concepts ?? []).map(conceptWords).filter(Boolean).join(', '); // The kind of file, by its media type: a known one in plain words, any other exactly as recorded, none as unknown. const FILE_TYPE: Record = { 'application/pdf': 'PDF', 'image/jpeg': 'JPEG image', 'image/png': 'PNG image', }; export const patientFileType = (contentType?: string): string => { const type = contentType?.split(';')[0].trim().toLowerCase(); if (!type) return 'Unknown type'; return FILE_TYPE[type] ?? contentType as string; }; // What a patient reads for a record the document links to. The shared reference renderer prints "Type - Type/" // when a reference has no display, and a display can itself be machine text: a raw reference, a bare id, or a UTC // timestamp ("Appointment 2026-10-13T13:00:00.000Z"). A patient reads the record's own name when it has a readable // one, any timestamp in it at their local time, and otherwise what kind of record it is. Never an id. const RECORD_KIND: Record = { Appointment: 'An appointment', CarePlan: 'A care plan', Communication: 'A message', Condition: 'A condition', Coverage: 'An insurance plan', DiagnosticReport: 'A test report', DocumentReference: 'A document', Encounter: 'A visit', Observation: 'A result', Organization: 'A practice', Patient: 'A patient', Practitioner: 'A clinician', PractitionerRole: 'A clinician', QuestionnaireResponse: 'A form', RelatedPerson: 'A helper', ServiceRequest: 'An order', Task: 'A task', }; const RAW_REFERENCE = /^(?:https?:\/\/\S+\/)?[A-Z][A-Za-z]+\/[\w.-]+(?:\/_history\/[\w.-]+)?$/; const BARE_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; const TIMESTAMP = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?/g; const recordType = (reference: Reference): string | undefined => { if (reference.type) return reference.type; const path = reference.reference?.split('/_history/')[0].split('/') ?? []; return path.length >= 2 ? path[path.length - 2] : undefined; }; const readableDisplay = (display?: string): string => { const text = display?.trim() ?? ''; if (!text || RAW_REFERENCE.test(text) || BARE_ID.test(text)) return ''; return text.replace(TIMESTAMP, (at) => `${formatLongDate(at)} at ${formatTimeOfDay(at)}`); }; export const patientReferenceWords = (reference: Reference): string => { const named = readableDisplay(reference.display); if (named) return named; const type = recordType(reference); return (type && RECORD_KIND[type]) || 'A linked record'; };