// The case-conference entry point: a collaboration team's practitioners conferring ABOUT a patient, // with the patient not present. // // IT LIVES HERE, NOT IN `StaffCareTeamsPage.tsx`, ON PURPOSE. That page is a shared file other // sessions restyle, so diff there is one import and one element - every video concern // (the ship gate, the busy-elsewhere rule, the context prefix) is in this file instead. // // THE PATIENT IS EXCLUDED SERVER-SIDE, and that is where it has to be. A `collabteam#` // session's roster is filtered to the team's PRACTITIONERS before the membership test, so the subject // patient is neither notified, nor admitted on join, nor shown the session in their own late-joiner // list. Hiding a button could only ever have closed the first of those three. import { Video } from 'lucide-react'; import { useVideoServiceContext } from '../../services/VideoService'; import { collabTeamContext } from '../../services/video/videoContract'; import { TELEHEALTH_VIDEO_ENABLED } from '../../services/video/videoFlags'; import { caseConferenceEntry } from './caseConferenceEntry'; interface Props { teamId: string } export const StartCaseConferenceButton: React.FC = ({ teamId }) => { const { call, startCall, joinAvailable } = useVideoServiceContext(); // WHICH DOOR THIS OPENS. Offering Start over a conference this team already has sends the // practitioner at the create route, which the server refuses 409 `CONTEXT_TAKEN` - while the // join route answers on the same session and token. This is the client stopping short of a // request that is certain to be refused, NOT a gate: the server still decides, and its refusal // still renders if it comes. const entry = caseConferenceEntry({ teamId, phase: call.phase, callContext: call.context, available: call.available, }); const rejoining = entry.kind === 'join' || entry.kind === 'rejoin'; // Starting a second call auto-leaves the first - `ChimeCallSession.join()` tears the previous // meeting down before building the next - so an enabled control here would silently drop a live // visit somebody is sitting in. Anchored on `idle` so a phase added later fails SAFE (refuses) // rather than permitting a start mid-teardown. Same rule `EncounterVideoPane` carries. // `live` is this team's own conference already up on this screen - there is nothing to offer. const busy = entry.kind === 'live' || call.phase !== 'idle'; // THE SHIP GATE, on the ENTRY POINT only - never on call chrome, which would strand a // participant inside a meeting with no controls. Visible-and-disabled rather than hidden // (Spencer, ): an absent control reads as "this product has no telehealth", a disabled // one reads as "not yet". const gated = !TELEHEALTH_VIDEO_ENABLED; return ( ); };