import { useCallback, useEffect, useRef, useState } from "react"; import type { Appointment } from "fhir/r4"; import { Button } from "../../../../components/ui/button.tsx"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../../../../components/ui/dialog.tsx"; import { useOrgAuthorizationServiceContext, type OrgAuthorizationStatusValue, type OrgAuthorizationWithdrawResponse, } from "../../../../services/OrgAuthorizationService.tsx"; import { answerEligibilityOf } from "../../../../utils/proxyFormAuthority"; import { practiceDecisionFollowUp, PRACTICE_TEAM_PENDING_COPY } from '../../../../utils/practiceDecisionFollowUp'; import AgreementText from "../../../../components/OrgAuthorizationPrompt/AgreementText.tsx"; import { CONSENT_INSTRUMENT_DEFINITIONS, RECORDS_INSTRUMENT, agreementStateCopy, type ConsentInstrumentId, } from '../../../../config/consentInstruments.ts'; import { orgAgreementName } from '../../../../components/OrgAgreements/orgAgreements'; import type { OrgCollabTeam } from '../../../../utils/orgCollabTeams'; import { agreementStatusDeniedMessage, agreementStatusFailure } from "../../../../utils/agreementStatusFailure"; import { usePatientServiceContext } from "../../../../services/PatientService.tsx"; import { useAuthServiceContext } from "../../../../services/AuthService.tsx"; import { isAgreementAuthorityLost, useProxyMayAnswerAgreements } from "../../../../hooks/useProxyMayAnswerAgreements"; import { isSaveRetired } from "../../../../utils/saveOperation"; import { useAppointmentServiceContext } from "../../../../services/AppointmentService.tsx"; import { visitsAWithdrawalCancels, withdrawnVisitName } from "../../../../utils/withdrawalCancelledVisits.ts"; import { formatDate, formatTimeOfDay } from "../../../../utils/dateUtils.ts"; // // - THE PATIENT-FACING WITHDRAWAL. Until this existed the consent chain could only GRANT: // three capture paths, agreement versioning, a stale guard - and no way for a patient to press "no". // // IT LIVES ON THE PRACTICE'S OWN PAGE, not in a settings screen, because that is where the question // actually occurs to someone: they open the practice they are wondering about and see what it can see. // A "privacy settings" page listing organizations would be a second, competing list of the same thing. // // AND IT WORKS FOR AN AWAY PRACTICE, which is the part that needed thought. The patient's record is // org-agnostic and My Providers lists every practice involved in their care - but every org-scoped call // defaults to the WordPress install the patient is standing in. So each call here passes THIS page's // organization id explicitly. Without that, a patient viewing practice B and pressing withdraw would // have withdrawn from practice A, silently and irreversibly-looking. // // THE COPY IS LOAD-BEARING AND IS NOT A DRAFT TO BE TIGHTENED LATER. Spencer's ruling: withdrawal is // FORWARD-ONLY - the practice keeps everything it could see up to the instant, because that retention is // a legal requirement, and loses new information from then on. This card exists because the product's // patient-facing words already promised more than the code did, so wording that implies the record is // clawed back would recreate the exact defect it was raised to close. // type Phase = "loading" | "error" | "denied" | OrgAuthorizationStatusValue; type AffectedVisits = { state: "loading" } | { state: "failed" } | { state: "read"; visits: Appointment[] }; type WithdrawalOutcome = | { state: "checking" } | { state: "unconfirmed" } | { state: "read"; cancelled: Appointment[]; standing: Appointment[] }; const formatWhen = (iso?: string): string => { if (!iso) return ""; const parsed = new Date(iso); if (Number.isNaN(parsed.getTime())) return ""; return parsed.toLocaleDateString(undefined, { year: "numeric", month: "long", day: "numeric" }); }; const WithdrawnVisitList = ({ visits }: { visits: Appointment[] }) => (