// / My History - say what a thing IS, in words a patient uses. // // The feed was rendering raw type names: "changed your Communication", "changed your DirectThread". // Neither means anything outside this codebase, and the second is not even FHIR - it is our own // DynamoDB thread record surfacing through the audit trail. On a screen whose entire job is letting // someone judge whether an access looks wrong, a word they cannot parse is worse than useless: it // makes the row unreadable and quietly teaches them to ignore the feed. // // THE FALLBACK IS THE LOAD-BEARING PART. An unmapped type degrades to "your record" - never to the // type name - because leaking the type name is precisely the defect this fixes. New resource types // will appear faster than anyone updates this map, so the default has to be safe rather than // informative. A test asserts no mapping can emit a CamelCase word. const LABELS: Readonly> = { // The two that prompted this. Communication: 'a message', CommunicationRequest: 'a message', DirectThread: 'a message thread', // Clinical. Observation: 'a test result', Condition: 'a health condition', AllergyIntolerance: 'an allergy', MedicationStatement: 'a medication', MedicationRequest: 'a medication', MedicationAdministration: 'a medication', MedicationDispense: 'a medication', Immunization: 'an immunization', Procedure: 'a procedure', DiagnosticReport: 'a test report', ClinicalImpression: 'a clinical note', FamilyMemberHistory: 'family history', Encounter: 'a visit', EpisodeOfCare: 'an episode of care', // Care planning. CarePlan: 'a care plan', CareTeam: 'a care team', Goal: 'a care goal', NutritionOrder: 'a nutrition order', RiskAssessment: 'a risk assessment', // Ordered FOR the patient. `ServiceRequest` was the omission that prompted this group: it is the // lab, the image and the referral, so it is close to the most consequential row this feed carries, // and every one of them was rendering as the anonymous fallback while a medication beside it was // named. One word covers all three because the patient's question is what was ordered, not which // department fills it. ServiceRequest: 'an order', DeviceRequest: 'a device order', DeviceUseStatement: 'a device you use', Device: 'a device', VisionPrescription: 'a vision prescription', ImmunizationRecommendation: 'an immunization due', ImmunizationEvaluation: 'an immunization review', // Safety. These two are the rows a patient is most likely to want explained, and they were both // reading as an unnamed change to "your record" by a named clinician. DetectedIssue: 'a safety concern', AdverseEvent: 'something that went wrong', // Administrative - the things a patient actually recognises day to day. Patient: 'your profile', Appointment: 'an appointment', // Booking writes a Slot and then the Appointment, so a patient who books once sees two rows. // Measured on My History 2026-09-07: the Slot arrived as "You added something to your // record", the generic fallback, which is the least useful thing that page can say about an // action the patient took deliberately two minutes earlier. Labelled rather than hidden - // this feed never silently drops a row, so the second row has to be true instead of absent. Slot: 'a time on the schedule', Task: 'a task', QuestionnaireResponse: 'a form you filled in', DocumentReference: 'a document', Invoice: 'an invoice', PaymentReconciliation: 'a payment', Coverage: 'your insurance', RelatedPerson: 'a caregiver', Consent: 'a consent', Flag: 'an alert', }; /** * The safe default. Plain, true of anything in this feed, and free of jargon. * * EXPORTED because a caller composing a sentence around the label has to know when it got this one: * "updated your record" reads correctly and "added your record" does not, so the generic case needs a * different sentence rather than a different word. Comparing against this constant is the only way to * tell an unmapped type from a mapped one, and re-deriving it by re-reading LABELS would put the same * decision in two places. */ export const GENERIC_RESOURCE_LABEL = 'your record'; export function resourceLabel(resourceType: string | undefined): string { if (!resourceType) return GENERIC_RESOURCE_LABEL; return LABELS[resourceType] ?? GENERIC_RESOURCE_LABEL; }