// The single app-level video mount. Rendered as a CHILD of #akashic-overlay-root (see App.tsx) rather // than portalling into it: the provider mounts far above where that div is rendered, so a portal would // resolve a null container on first render. Being a child is equivalent for CSS containment and // removes the ordering hazard entirely. // // `MeetingWindow` DOES portal into that same div, through `FloatingWindow`. That is safe // for the reason above rather than in spite of it: a call cannot be live on the first render - the // phase starts `idle` and this component renders nothing at all until a user action moves it - so by // the time the window mounts, #akashic-overlay-root has long been in the document. What it does NOT // survive is that div's subtree REMOUNTING mid-call: `getAkashicPortalContainer()` would resolve null // for that pass and `FloatingWindow` fails closed (renders nothing) with no retry. Nothing remounts it // today; a future conditional above it would need this checked. // // Task 13 added the join affordance ("a meeting exists for you"). It renders ALONGSIDE the live // surface rather than instead of it: `call.available` is separate state from `call.phase`, so being // offered a meeting while already in one is a legitimate, simultaneous fact. import { useEffect, useState } from 'react'; import { AlertTriangle, X } from 'lucide-react'; import { useVideoServiceContext } from '../../services/VideoService'; import { AvailableMeetingBanner } from './AvailableMeetingBanner'; import { MeetingWindow } from './MeetingWindow'; /** What is left to say once the call itself is gone. Deliberately NOT the call chrome: there is * nothing to mute, no camera to turn off and nobody to leave - only something the user needs to * know. It carries no `VideoTileGrid`, so it cannot make tile binding ambiguous. */ const CallFailureNotice = ({ message, onDismiss }: { message: string; onDismiss: () => void }) => (

{message}

); /** Deliberately NOT `CallFailureNotice`. Being removed from a visit is not a failure and the person * reading it may be a patient in crisis, so it carries no alert colour and no warning icon - but it * is a `role="status"` announcement, because a screen reader user is otherwise dropped in silence. */ /** Renamed from `CallRemovedNotice` 2026-09-14: it carries two notices now - a removal, and a visit * somebody else ended - and a name that says `removed` on the second one is a comment that lies. */ const CallNotice = ({ message, onDismiss }: { message: string; onDismiss: () => void }) => (

{message}

); /** TWO SURFACES AND AN ESCAPE HATCH ONCE LIVED HERE, and deleted all three: * * 1. `DockedCallEscapeHatch` - a Leave-only stub with no grid, no mute and no camera, shown when a * "docked" call had no docked surface mounted. Task 13 replaced it with the full floating surface. * 2. `FloatingCallSurface` - the 22rem pane parked bottom-right. * 3. The ARBITRATION between the floating and docked surfaces (`dockedSurfaceMounted`), whose only * job was keeping exactly one `VideoTileGrid` mounted. * * `MeetingWindow` is now the single in-call surface, so the one-grid rule is structural and there is * no surface decision left to take. See the header of `MeetingWindow.tsx` for the two defects the * two-surface shape produced - both of them were surface-CHOICE defects. */ export const CallOverlay = () => { const { call } = useVideoServiceContext(); // NOT `phase === 'active'`. Every non-idle phase is a call the user is in the middle of: // `creating`/`joining` is someone who clicked Start and is owed feedback while the meeting is // provisioned and the camera comes up, and `ending` is the only thing that keeps the disabled // "Leaving..." state on screen - the one moment a second click on Leave must be impossible. // Anchored on `idle` rather than listing the live phases so that a phase added later fails SAFE: // it shows the call, instead of silently vanishing it. const live = call.phase !== 'idle'; const [dismissed, setDismissed] = useState(false); // A NEW failure must never be hidden by the dismissal of the previous one. Every route to a new // failure passes through `error: undefined` first (`START` and `JOIN_AVAILABLE` both clear it), // so resetting when the error clears is exact rather than approximate. useEffect(() => { if (!call.error) setDismissed(false); }, [call.error]); // Tracked separately from the failure dismissal: a notice and a call failure are different // messages and dismissing one must not silence the other. const [noticeDismissed, setNoticeDismissed] = useState(false); useEffect(() => { if (!call.notice) setNoticeDismissed(false); }, [call.notice]); // THERE IS NO SURFACE DECISION ANY MORE, and that is the point of. A live call gets // the meeting window; every viewer, every context. The two defects this feature shipped were both // decisions ABOUT the viewer taken from a fact about the MEETING (`presentation`, then // `dockedSurfaceMounted`) - a question that cannot be answered wrongly if it is never asked. const surface = !live // A CALL-LIFECYCLE FAILURE OUTLIVES THE CALL, and that is the whole reason this branch // exists. A `/leave` that reached the broker and failed leaves this user very possibly still // a participant in a live, BILLING meeting - while the provider's teardown has already run // and returned the phase to idle. Every in-call surface is unmounted by then, so a failure // held in the chrome's own state (`CallControls` used to do exactly that) can never reach the // screen. This overlay is the piece that survives, so this is where it gets reported. Same // for a refused `startCall`/`joinAvailable`, which had no reporter at all before this. ? (!call.error || dismissed ? null : setDismissed(true)} />) : ; // The banner is OUTSIDE that decision on purpose: `available` is separate state from `phase`, so // a meeting you may join can legitimately be on screen next to the call you are already in. // Outside the surface decision for the same reason the banner is, and for one of its own: a removal // notice has to survive the teardown that returns `phase` to idle, which unmounts every in-call // surface that could otherwise have carried it. return ( <> {surface} {call.notice && !noticeDismissed && ( setNoticeDismissed(true)} /> )} ); };