import type { Encounter } from 'fhir/r4'; import type { EncounterChange } from '../../../utils/encounterChange'; import { planEncounterDemotion } from './encounterLifecycle'; /** * sub-task 0 - switching the ONE active encounter. * * Spencer, 2026-08-05: *"there should only ever be one 'active' encounter at a time even though they may * have several with the status of the practitioner coming back to them."* * * Entering another encounter (or leaving to the switchboard) parks the one you were in as `onleave`. * Before this existed, nothing demoted the previous encounter - `handleEnter` never touched it and * expanding out cleared the slot with no status write - so two `in-progress` encounters were reachable. * * `onleave` is FHIR R4's only "begun but paused" status, so it is the right code - but note R4 words it * as *the patient* being on leave, whereas we mean *the practitioner stepped out*. Deliberate; documented * on. The server already agrees it is a pause, not an end (`Encounter/put.ts`). */ export const PARKED_ENCOUNTER_STATUS = 'onleave' as const; export interface SwitchActiveEncounterResult { /** The encounter that was parked, if any. */ parked?: Encounter; /** True when a park was attempted and the write failed. The switch still proceeds - see below. */ parkFailed: boolean; error?: unknown; } export async function switchActiveEncounter({ previous, next, changeEncounter, }: { previous: Encounter | undefined; next: Encounter | undefined; changeEncounter: (id: string, change: EncounterChange) => Promise; }): Promise { const plan = planEncounterDemotion(previous, next?.id); if (!plan || !previous) return { parkFailed: false }; try { // Status change ONLY, on the visit as stored, so nothing it gained since the slot was filled is dropped. A // visit no longer in progress there (finished elsewhere, say) has nothing to park. const parked = await changeEncounter(previous.id as string, (stored) => (stored.status === 'in-progress' ? { ...stored, status: PARKED_ENCOUNTER_STATUS } : 'unchanged')); return { parked, parkFailed: false }; } catch (error) { // DO NOT rethrow, and do not block the switch. The practitioner must be able to open the next // patient. This is safe ONLY because "active" is explicit state and is never derived from status: // a stale `in-progress` left behind cannot make activeness ambiguous. Reported, never swallowed. console.error('Failed to park the previous encounter as onleave', error); return { parkFailed: true, error }; } }