import { useRef, useState } from "react"; import { useNavigate } from "react-router-dom"; import { CareTeam } from "fhir/r4"; import { FhirCareTeamDisplay } from "../../../../components"; import { useFhirCareTeamBroadcast, useFhirCareTeams, useFhirCareTeamTargetedBroadcast, } from "../../../../hooks"; import { useAuthServiceContext, usePatientServiceContext } from "../../../../services"; import { useViewerIsPatient } from "../../../../hooks"; import { useCareTeamReadScope } from "../../../../hooks/useCareTeamReadScope"; import { Calendar, ChevronRight, Edit, FileText, Plus } from "lucide-react"; import { formatDateForDisplay } from "../../../../lib/utils.ts"; import { Sheet, SheetContent } from "../../../../components/ui/sheet.tsx"; import { Button } from "../../../../components/ui/button.tsx"; import { Skeleton } from "../../../../components/ui/skeleton.tsx"; import { isOutsideProvidersTeam } from "../../../../utils/outsideProviders.ts"; const CareTeams = () => { const navigate = useNavigate(); const { userRole, USER_ROLES } = useAuthServiceContext(); const viewerIsPatient = useViewerIsPatient(); const { loading: teamsLoading, error, answered, careTeamsList } = useFhirCareTeams(); // A read that has not answered is still loading, never an empty list. const loading = teamsLoading || !answered; const visibleCareTeams = careTeamsList.filter( (careTeam: CareTeam) => !isOutsideProvidersTeam(careTeam), ); // An open team belongs to the viewer, practice and patient it was opened for, and to that one opening: a // change of any retires it at once, and returning to the same practice or patient does not bring it back. const { patientState } = usePatientServiceContext(); const scope = useCareTeamReadScope(patientState?.id); const openings = useRef(0); const [opened, setOpened] = useState<{ id: number; scope: string; team: CareTeam } | null>(null); const [openedScope, setOpenedScope] = useState(scope); if (openedScope !== scope) { setOpenedScope(scope); setOpened(null); } const current = opened && opened.scope === scope ? opened : null; const selectedCareTeam = current?.team ?? null; const showDisplayModal = current !== null; const openingId = current?.id; const setShowDisplayModal = (open: boolean) => { if (!open) setOpened(null); }; useFhirCareTeamBroadcast(); useFhirCareTeamTargetedBroadcast({ careTeam: selectedCareTeam || undefined, isOpen: showDisplayModal, onUpdate: (updatedCareTeam) => { setOpened((prev) => (prev && prev.id === openingId ? { ...prev, team: updatedCareTeam } : prev)); }, onDelete: () => { setOpened((prev) => (prev && prev.id === openingId ? null : prev)); }, }); const viewCareTeam = (careTeam: CareTeam) => { setOpened({ id: ++openings.current, scope, team: careTeam }); }; const editCareTeam = (event: React.MouseEvent, careTeam: CareTeam) => { event.stopPropagation(); navigate(careTeam.id as string, { relative: "path" }); }; const addCareTeam = () => { navigate("new", { relative: "path" }); }; const isAuthorizedToEdit = () => { return userRole && [USER_ROLES.PRACTITIONER].includes(userRole as string); }; /** * WHO IS READING THIS SCREEN, because it is reachable by BOTH and the copy assumed one of them. * * Found in the practitioner walk, 2026-08-22: a clinician opening a patient's chart at * Care Provision Care Teams was told *"You don't have Care team yet. Your care team will add them * here when they are created."* **Patient copy on a staff surface** - it addresses the clinician as * the patient, and then tells them to wait for themselves. * * The component ALREADY knew: `isAuthorizedToEdit` reads the same role a line above, to decide * whether to show **Add**. The reader was identified and the sentences did not use it. * * A patient never has `USER_ROLES.PRACTITIONER`, so this defaults to the patient voice - the * original behaviour for the original reader. */ /* * Was `userRole === PRACTITIONER`, which is the wrong half to enumerate. A receptionist, an admin or a * platform manager reading this chart is just as much "not the patient", and every one of them got the * patient voice - told to wait for a care team they are part of. Listing the staff roles means each new * staff role silently defaults to the wrong sentence, which is how this spread to the sibling screens. * * The patient side is a closed pair, so asking that question instead cannot rot as roles are added. */ const staffIsViewing = !viewerIsPatient; const getParticipantCount = (careTeam: CareTeam): number => { return careTeam.participant?.length || 0; }; return (
{/* ๐ป The patient line also said "your care team shared by your care team" โ the same noun twice, which was already wrong before anyone asked who was reading it. */} {staffIsViewing ? "The practitioners and organizations caring for this patient." : "The practitioners and organizations caring for you."}
Try again later.
{staffIsViewing ? "No clinical care team recorded" : "No clinical care team yet"}
{/* โ The staff line must not tell a clinician to wait for somebody else โ THEY are the care team, and the Add button is right there. */} {staffIsViewing ? "No care team is recorded for this patient. Add a team to record who is involved in their care." : "Your practice will add the people involved in your care here."}
{careTeam?.name || "Team name not available"}{" "} {careTeam.status ? careTeam.status : "Status unknown"}
{/* {category && Category: {category}} */}