import { useEffect, useState } from "react"; import type { RelatedPerson } from "fhir/r4"; import { ScanEye, ShieldUser, UserRoundX } from "lucide-react"; import { toast } from "sonner"; import { AlertDialog, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "../../../components/ui/alert-dialog"; import { useRelatedPersonServiceContext } from "../../../services"; import { TIER_LABELS, type AuthorityGrant } from "../../../services/relatedPersonAuthority"; import { describeCurrentAccess } from "../../../components/FhirRelatedPersonDisplay/tierWords"; import { inviteAnswerOf } from "../../../config/relatedPersonInviteStatus"; import { relayServerFailure } from "../../../utils/fetchFailureMessage"; import { GUARDIAN_KEEPS_GRANT_MESSAGE, guardianKeepsGrant } from "../../../utils/guardianKeepsGrant"; import { PersonAction } from "./FamilyPerson"; import "./RelatedPersonsPage.css"; interface InboundAccessActionsProps { relatedPerson: RelatedPerson; displayName: string; grant?: AuthorityGrant; onUpdatePermissions?: () => void; /** Opens what this person has opened or changed on the record. */ onShowActivity?: () => void; onRevoked: () => void; /** Rows in the phone overlay; beside Save, the ending is a red button. */ variant?: "rows" | "button"; /** The server says this guardianship has ended: nothing is left to change or revoke. */ ended?: boolean; } // Someone who can access me: change what they may do, or end it. Revoking is its own action, not a tier. export const InboundAccessActions = ({ relatedPerson, displayName, grant, onUpdatePermissions, onShowActivity, onRevoked, variant = "rows", ended = false, }: InboundAccessActionsProps) => { const { deleteRelatedPerson } = useRelatedPersonServiceContext(); const [confirming, setConfirming] = useState(false); const [revoking, setRevoking] = useState(false); const [error, setError] = useState(null); // An unanswered invitation has granted nothing yet, so ending it is withdrawing it. const invited = inviteAnswerOf(relatedPerson) !== "accepted"; const kept = guardianKeepsGrant(relatedPerson); const keptNote =

{GUARDIAN_KEEPS_GRANT_MESSAGE}

; // Nothing can be revoked here once the grant is the guardian's to keep, or the guardianship has ended. const unrevocable = kept || ended; // A confirmation already open when that turns out to be so closes, and does not reopen. useEffect(() => { if (unrevocable) setConfirming(false); }, [unrevocable]); const endLabel = invited ? "Withdraw the invitation" : "Revoke access"; // Ending access removes authority, not history: what they did on the record stays readable. const endEffect = invited ? "The invitation ends immediately. Its history is kept." : "Their access ends immediately. The history of their access is kept."; const revoke = async () => { if (unrevocable) return; setRevoking(true); setError(null); try { await deleteRelatedPerson(relatedPerson); setConfirming(false); toast.success( invited ? `The invitation to ${displayName} was withdrawn.` : `Access revoked. ${displayName} no longer has access to your record.`, { position: "top-right" }, ); window.dispatchEvent(new CustomEvent("relatedPersonDeleted")); onRevoked(); } catch (err) { setError(relayServerFailure(err, "That could not be completed.")); } finally { setRevoking(false); } }; const confirm = ( { if (!revoking) setConfirming(open); }} > {invited ? `Withdraw the invitation to ${displayName}?` : `Revoke ${displayName}'s access?`} {endEffect} {error &&

{error}

} {invited ? "Keep the invitation" : "Keep their access"}
); // An ended guardianship already gives them nothing; the card beside this says so. if (variant === "button") { if (ended) return null; if (kept) return keptNote; return ( <> {confirm} ); } return (
{ended && (

{displayName}’s guardianship has ended, so it no longer gives them access. What they did while it lasted stays in the record.

)} {kept && !ended && keptNote} {onUpdatePermissions && !kept && !ended && ( )} {onShowActivity && ( )} {!kept && !ended && ( setConfirming(true)} danger disabled={revoking} testId="revoke-access" /> )} {confirm}
); }; export default InboundAccessActions;