import React, { useMemo } from 'react'; import { useAuthServiceContext } from '../../../services/AuthService'; import { noteAuthorOf, useEncounterNotesStore, EncounterNotesProvider } from './EncounterNotesContext'; import { useActiveEncounterStore, ActiveEncounterProvider } from './ActiveEncounterContext'; import { FloatingEncounterNotes } from './FloatingEncounterNotes'; /** * sub-task 1 - THE HOIST. Mount ABOVE `` in App.tsx. * * THE BUG THIS FIXES IS LIVE TODAY. `EncounterNotesProvider` used to mount inside * `ClinicianOverviewPage`, which is a ROUTE element. Navigating off `/overview` mid-encounter unmounted it * and destroyed `entriesRef` - the entire in-memory draft store. The note is **deliberately not autosaved** * (per-keystroke writes produced a HealthLake version chain of half-sentences, and an empty-string PUT * 400s), so the uncommitted clinical note was simply gone. It read as expected behaviour only because the * notes lived on the page you were leaving. * * The video provider was already hoisted this way (`AppVideoServiceProvider`), which is why a call survives * navigation and a note did not. * * MOUNT POSITION IS LOAD-BEARING, in both directions: * - ABOVE `` - below it and the draft dies on navigation again, silently. * - BELOW `FhirServiceProviders` - the notes store consumes ClinicalImpressionService + FhirService, and * the active-encounter slot consumes EncounterService. All three live inside `FhirServiceProviders` * (FhirService App.tsx:813 - EncounterService:862 in Base - ClinicalImpressionService:912 in Summary), * so mounting any higher throws "must be used within a...Provider" at app start. * * Checked before hoisting, NOT assumed: neither store performs an authed fetch on mount - * `useEncounterNotesStore` only reads its two service contexts and fetches lazily inside `ensureLoaded`. * So the app-wide-provider landmine (an authed `useHttpService` fetch in an app-wrapping provider that * does not gate on `currentUser` refresh logout /login loop) does NOT apply here. If either store * ever gains a mount-time fetch, that gate becomes mandatory. * * Drafts stay IN MEMORY. No localStorage, no PHI at rest - that is the design, not an oversight. A hard * refresh discarding uncommitted drafts is intentional; the Save button is the mitigation. * * sub-task 3 - `` mounts here too, alongside `children`, for the * identical reason: the popped-out pane must survive navigation the same way the store and the active * slot do. It renders `null` on its own whenever there is no active encounter or the pane is docked, so * mounting it unconditionally here costs nothing when the pane is closed. */ export const EncounterSessionProviders: React.FC<{ children: React.ReactNode }> = ({ children }) => { // The signed-in practitioner is the author of the notes written in this session. const { currentUser } = useAuthServiceContext(); const noteAuthor = useMemo(() => noteAuthorOf(currentUser?.fhir), [currentUser?.fhir]); const notes = useEncounterNotesStore(noteAuthor); const activeEncounter = useActiveEncounterStore(); return ( {children} ); };