import type { Encounter } from 'fhir/r4'; /** * The line that says which visit an item is about to be filed to. * * Drawn in `mockups/practitioner/encounter.html` directly under the modal's heading, in two forms: * * Filed to this visit - today, 4:05 PM * Filed to Tuesday's visit - September 2, finished 4:12 PM * * IT IS THERE FOR THE EVENING, WHICH IS THE HARDER HALF OF THIS WHOLE FLOW. The deck: *"a practitioner * writing up at six o'clock is still documenting the four o'clock visit, and the line at the top says * which one."* Filing to the right encounter after the visit has ended is one of the named requirements * of this surface, and without this line nothing on screen tells the clinician which visit they are in - * so somebody finishing three notes in a row has no way to notice they are in the wrong one. * * IT NEVER GUESSES. A visit with no start time is described without one rather than being given a * plausible hour, and no encounter at all is said plainly instead of the line claiming a visit that is * not there. A wrong confident answer here misfiles clinical data. * * DATES ARE WRITTEN THE WAY THE REST OF THE PRODUCT WRITES THEM. The deck renders `2 September`; every * other surface here reads `Aug 16, 2026`, and these are US practices. A drawing's date order is not a * ruling about locale, so the product's own convention wins. */ const time = (value: Date): string => value.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' }); const day = (value: Date): string => value.toLocaleDateString('en-US', { month: 'long', day: 'numeric' }); const weekday = (value: Date): string => value.toLocaleDateString('en-US', { weekday: 'long' }); const isSameDay = (a: Date, b: Date): boolean => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate(); const parse = (value?: string): Date | undefined => { if (!value) return undefined; const parsed = new Date(value); return Number.isNaN(parsed.getTime()) ? undefined : parsed; }; /** True once the visit is over, by either of the two things that say so. */ const hasEnded = (encounter: Encounter): boolean => encounter.status === 'finished' || Boolean(encounter.period?.end); export const describeFilingTarget = (encounter: Encounter | undefined, now: Date): string => { // NO VISIT IS NOT "THIS VISIT". An item can still be filed - it simply is not attached to an // encounter - and saying so is the difference between a record entry and a misfiled one. if (!encounter) return 'Filed to the patient’s record'; const started = parse(encounter.period?.start); const ended = parse(encounter.period?.end); const anchor = started ?? ended; if (!anchor) return 'Filed to this visit'; const today = isSameDay(anchor, now); // "this visit" only while it IS this one. On any other day the weekday names it, and the date // beside it removes the ambiguity a weekday alone would carry a fortnight later. const which = today ? 'this visit' : `${weekday(anchor)}’s visit`; const when = today ? 'today' : day(anchor); const at = hasEnded(encounter) && ended ? `finished ${time(ended)}` : started ? time(started) : undefined; return at ? `Filed to ${which} · ${when}, ${at}` : `Filed to ${which} · ${when}`; }; /** Where items added from a note's suggestion list are filed; the save row states the note itself. */ export const describeWhereAddedItemsGo = (encounter: Encounter | undefined, now: Date): string => `Anything you add here is filed to ${describeFilingTarget(encounter, now).replace(/^Filed to /, '')}`; export default describeFilingTarget;