import { useState } from "react"; import { useNavigate } from "react-router-dom"; import { CarePlan } from "fhir/r4"; import { FhirCarePlanDisplay } from "../../../../components"; import { useFhirCarePlanBroadcast, useFhirCarePlans, useFhirCarePlanTargetedBroadcast, } from "../../../../hooks"; import { useAuthServiceContext, usePatientServiceContext } from "../../../../services"; import { EncounterCarePlanPanel } from "../../ClinicianOverviewPage/EncounterCarePlanPanel"; import { useViewerIsPatient } from "../../../../hooks"; import { Calendar, ChevronRight, Edit, FileText, Plus } from "lucide-react"; import { Skeleton } from "../../../../components/ui/skeleton"; import { formatDateForDisplay } from "../../../../lib/utils"; import { carePlanAuthorship } from "../../../../utils/carePlanAuthorship"; import { carePlanName } from "../../../../utils/carePlanName"; import { Sheet, SheetContent } from "../../../../components/ui/sheet"; import { Button } from "../../../../components/ui/button"; import { mayEditRecord } from '../../../../utils/recordEditability'; import { useSeatStanding } from '../../../../utils/seatStanding'; const CarePlans = () => { const navigate = useNavigate(); const [building, setBuilding] = useState(false); const { patientState } = usePatientServiceContext(); const { userRole, USER_ROLES, currentOrganization, practitionerRoles } = useAuthServiceContext(); const seatStanding = useSeatStanding(); const viewerIsPatient = useViewerIsPatient(); const { loading, error, carePlansList } = useFhirCarePlans(); const [selectedCarePlan, setSelectedCarePlan] = useState( null, ); const [showDisplayModal, setShowDisplayModal] = useState(false); useFhirCarePlanBroadcast(); useFhirCarePlanTargetedBroadcast({ carePlan: selectedCarePlan || undefined, isOpen: showDisplayModal, onUpdate: (updatedCarePlan) => { setSelectedCarePlan(updatedCarePlan); }, onDelete: () => { setShowDisplayModal(false); setSelectedCarePlan(null); }, }); const viewCarePlan = (carePlan: CarePlan) => { setSelectedCarePlan(carePlan); setShowDisplayModal(true); }; const editCarePlan = (event: React.MouseEvent, carePlan: CarePlan) => { event.stopPropagation(); navigate(carePlan.id as string, { relative: "path" }); }; /* * ADD OPENS THE PLAN BUILDER, NOT THE RESOURCE EDITOR. * * This navigated to `new`, which is the generic FHIR form: Title, "Fulfills CarePlan", "Part of * referenced CarePlan", Status and Intent. A clinician drafting from the record was answering field * names while the encounter door - the same journey, one step earlier - drew the plan, its * instructions, its sharing line and its release control. * * Both doors are named in the same step, so they cannot be two different products. And the steps * behind that step - add activities, set a goal, invisible until released, released as tasks - are * all properties of the BUILT plan, so a door that produces a CarePlan with a status and an intent * cannot reach any of them. * * `useEncounterCarePlan` is named for where it was first used and is not bound to one: it takes a * patient, reads that patient's plans, and writes one resource per decision. So the builder is the * same builder here, with no encounter in sight. */ const addCarePlan = () => { setBuilding(true); }; const roleAllowsEdit = () => { return userRole && [USER_ROLES.PRACTITIONER].includes(userRole as string); }; /* * AND THE ROLE IS NOT THE RULE THE SERVER APPLIES. * * Writing a CarePlan needs a paid clinician seat, resolved per request by `callerMayWrite`. The role * check above passes for an unseated practitioner - a medical assistant, a nurse rooming patients, * somebody whose seat was turned off this morning - so the page offered Add and Edit, and the save * came back refused. A refusal that arrives after the typing has already spent the work. */ const seat = mayEditRecord({ seatStanding, resourceType: 'CarePlan', viewerIsStaff: Boolean(userRole) && ![USER_ROLES.PATIENT, USER_ROLES.RELATED_PERSON].includes(userRole as string), practitionerRoles, }); const isAuthorizedToEdit = () => roleAllowsEdit() && seat.mayEdit; // WHOSE PLAN THIS IS, asked of every row. // // TWO DIFFERENT QUESTIONS, AND THE ROLE ONE WAS THE ONLY ONE BEING ASKED. `isAuthorizedToEdit` asks // whether this VIEWER is a practitioner at all; this asks whether the PLAN is this practice's. A // practitioner reading a colleague's plan at another practice passed the first and was offered Edit, // Save and Archive on work that was never theirs. // // THE RULE IS NOT NEW AND IS NOT REDEFINED HERE. `carePlanAuthorship` is what the encounter's own // editor already uses, so the two surfaces cannot drift into disagreeing about who may edit - which // is exactly how this screen came to answer differently from the one beside it. const authorshipOf = (carePlan: CarePlan) => carePlanAuthorship(carePlan, { currentOrganizationId: currentOrganization?.id }); const getIntentDisplay = (carePlan: CarePlan): string => { if (!carePlan.intent) return ""; return ( carePlan.intent.charAt(0).toUpperCase() + carePlan.intent.slice(1).replace(/-/g, " ") ); }; const getActivitiesCount = (carePlan: CarePlan): number => { return carePlan.activity?.length || 0; }; return (

Care Plans

{viewerIsPatient ? 'View your care plans shared by your care team.' : "View the care plans this patient's care team has shared with them."}

{/* SAID, NOT WITHHELD. A control that simply disappears reads as a broken screen or as a permission the reader has lost, and both send them to an administrator to check permissions that are already correct. A seat is nameable, and a practice can enable one in a minute. */} {roleAllowsEdit() && !seat.mayEdit && (

{seat.reason}

)} {isAuthorizedToEdit() && !building && ( )} {building && ( )}
{/* The same panel the encounter draws, so the two doors named in one step are one product. It writes as it goes - each control is its own decision and its own write - so there is nothing to submit here and Done only puts the list back. */} {building && (
)} {error ? (
{" "}

Could not load Care Plans

Try again later.

) : !loading && carePlansList.length === 0 ? (

No Care Plan found

{viewerIsPatient ? 'You do not have a care plan yet. Your care team will add one here when it is created.' : "No care plan yet. Add one for this patient's care."}

) : loading ? (
{[...Array(4)].map((_, index) => (
))}
) : ( carePlansList.length !== 0 && (
{carePlansList.map((carePlan: CarePlan) => { const intent = getIntentDisplay(carePlan); const activitiesCount = getActivitiesCount(carePlan); // - the row IS the control, so it must be reachable without a pointer. // Enter and Space both, because role="button" promises both. return (
viewCarePlan(carePlan)} onKeyDown={(event: React.KeyboardEvent) => { if (event.key !== 'Enter' && event.key !== ' ') return; event.preventDefault(); viewCarePlan(carePlan); }} >

{/* THE PLAN'S OWN NAME. This read `category[0].text`, which is a classification most plans share - so "Blood pressure management" appeared as "Assessment and Plan of Treatment", and a plan with no category at all appeared as "Plan name not available" while its name was stored and present. The first is the worse half: a wrong value that looks right is harder to notice than a missing one, and every plan sharing a category shared a name. `description` before the placeholder, matching what the patient's own list already does with the same resource. */} {carePlanName(carePlan, "Plan name not available")} {carePlan.status ? carePlan.status : "Status unknown"}

{carePlan?.meta?.lastUpdated && ( {" "} {formatDateForDisplay(carePlan.meta.lastUpdated)} )}
{intent && ( Intent: {intent} )} {/* KEPT, NOT DELETED. The category was in the wrong place rather than unwanted - a clinician scanning for every assessment-and-plan is asking a real question. It reads as a classification here, beside the intent, where being the same on many rows is the point rather than the defect. */} {carePlan?.category?.[0]?.text && ( {carePlan.category[0].text} )} {activitiesCount > 0 && ( {activitiesCount}{" "} {activitiesCount === 1 ? "activity" : "activities"} )}
{/* TWO REASONS A ROW MAY BE READ-ONLY, AND ONLY ONE OF THEM CAN BE SHOWN. The plan belongs to another practice, or this reader holds no clinician seat. Authorship is asked first because it is about THIS row and is the more specific answer; the seat is about the reader and is the same on every row. Keyed on the ROLE rather than on `isAuthorizedToEdit`, which now folds the seat in - keying on that would hide the sentence along with the button, which is the thing this whole branch exists to prevent. */} {roleAllowsEdit() && (seat.mayEdit && authorshipOf(carePlan).mayEdit ? (
) : ( // SAID, NOT WITHHELD. A row that simply loses its button reads as a broken screen // or a permission the reader has lost, and both send them to the front desk. The // plan is theirs to read and somebody else's to change, which is a sentence.
{authorshipOf(carePlan).readOnlyReason ?? seat.reason}
))}
); })}
) )} {selectedCarePlan && ( { if (!open) setSelectedCarePlan(null); }} > { setShowDisplayModal(false); setSelectedCarePlan(null); }} /> )}
); }; export default CarePlans; // import { useNavigate } from 'react-router-dom'; // import { CarePlan } from 'fhir/r4'; // import { AppSpinner, FhirCarePlanDisplay, ScrollableTab } from '../../../../components'; // import { useFhirCarePlanBroadcast, useFhirCarePlans, useFhirCarePlanTargetedBroadcast } from '../../../../hooks'; // import { useAuthServiceContext, useCarePlanServiceContext } from '../../../../services'; // const CarePlans = () => { // const navigate = useNavigate(); // const { userRole, USER_ROLES } = useAuthServiceContext(); // const { getCarePlanDisplay } = useCarePlanServiceContext(); // const { loading, error, clearError, carePlansList } = useFhirCarePlans(); // const [isGuideOpen, setIsGuideOpen] = useState(false); // const [selectedCarePlan, setSelectedCarePlan] = useState(null); // const [showDisplayModal, setShowDisplayModal] = useState(false); // const spacerMargin = '24px'; // useFhirCarePlanBroadcast(); // useFhirCarePlanTargetedBroadcast({ // carePlan: selectedCarePlan || undefined, // isOpen: showDisplayModal, // onUpdate: (updatedCarePlan) => { // setSelectedCarePlan(updatedCarePlan); // }, // onDelete: () => { // setShowDisplayModal(false); // setSelectedCarePlan(null); // } // }); // const viewCarePlan = (carePlan: CarePlan) => { // setSelectedCarePlan(carePlan); // setShowDisplayModal(true); // }; // const editCarePlan = (event: React.MouseEvent, carePlan: CarePlan) => { // event.stopPropagation(); // navigate(carePlan.id as string, { relative: 'path' }); // }; // const addCarePlan = () => { // navigate('new', { relative: 'path' }); // }; // const isAuthorizedToEdit = () => { // return userRole && [USER_ROLES.PRACTITIONER].includes(userRole as string); // }; // const getStatusDisplay = (carePlan: CarePlan): { text: string, color?: string } => { // if (!carePlan) return { text: 'Unknown' }; // switch (carePlan.status) { // case 'draft': // return { text: 'Draft', color: '#757575' }; // case 'active': // return { text: 'Active', color: '#00a32a' }; // case 'on-hold': // return { text: 'On Hold', color: '#e39700' }; // case 'revoked': // return { text: 'Revoked', color: '#cc1818' }; // case 'completed': // return { text: 'Completed', color: '#4f94d4' }; // case 'entered-in-error': // return { text: 'Error', color: '#cc1818' }; // case 'unknown': // return { text: 'Unknown', color: '#757575' }; // default: // return { text: carePlan.status.charAt(0).toUpperCase() + carePlan.status.slice(1).replace(/-/g, ' ') }; // } // }; // const getIntentDisplay = (carePlan: CarePlan): string => { // if (!carePlan.intent) return ''; // return carePlan.intent.charAt(0).toUpperCase() + carePlan.intent.slice(1).replace(/-/g, ' '); // }; // const getActivitiesCount = (carePlan: CarePlan): number => { // return carePlan.activity?.length || 0; // }; // return ( // // setIsGuideOpen(false)} // resourceType="CarePlan"/> // // // // // // // {isAuthorizedToEdit() && ( // // // // )} // // // {error && ( // <> // // {error} // // // // )} // {!loading && carePlansList.length === 0 && ( // <> // // No care plans found. // // // // )} // <> // {loading ? ( // // ): ( // // {carePlansList.length !== 0 && ( // // {carePlansList.map((carePlan: CarePlan) => { // const displayTitle = getCarePlanDisplay(carePlan); // const { text: statusText, color: statusColor } = getStatusDisplay(carePlan); // const intent = getIntentDisplay(carePlan); // const activitiesCount = getActivitiesCount(carePlan); // return ( // viewCarePlan(carePlan)}> // // // // // // // // // {displayTitle} // // {intent && ( // // Intent: {intent} // // )} // {activitiesCount > 0 && ( // // {activitiesCount} {activitiesCount === 1 ? 'activity': 'activities'} // // )} // // {isAuthorizedToEdit() && ( // // // // )} // // // // // ); // })} // // )} // // )} // // {selectedCarePlan && ( // { // setShowDisplayModal(false); // setSelectedCarePlan(null); // }} // /> // )} // // ); // }; // export default CarePlans;