import { useEffect, useRef, useState } from 'react'; import { RECORDS_INSTRUMENT } from '../../../config/consentInstruments.ts'; import { useOrgAuthorizationServiceContext, type OrgAuthorizationStatusValue, } from '../../../services/OrgAuthorizationService.tsx'; // Phase 2 (clinical-authorization gate), client Task 12 - the receptionist appointments-overview // "not authorized" indicator (spec §7). This hook is the per-patient dedup/cache layer: v1 reads // are per-patient only (a batch endpoint is explicitly deferred, spec §12), so the same patient // appearing on multiple listed appointments (e.g. two visits) must trigger exactly ONE // getStatus(patientId) call, not one per appointment row. // // Cache lives for this hook instance's lifetime (a ref, not component state) - once a fetch has // been started for a patientId it is never re-issued for that instance, even across re-renders // that pass the same patientIds in a different order or with different duplicate counts. A failed // fetch is NOT cached (removed from the "requested" set) so a later render gets a retry, rather // than permanently hiding the indicator for that patient. export type OrgAuthorizationStatusByPatientId = Record; export const useOrgAuthorizationStatusByPatient = ( patientIds: Array, ): OrgAuthorizationStatusByPatientId => { const { getStatus } = useOrgAuthorizationServiceContext(); const [statusByPatientId, setStatusByPatientId] = useState({}); const requestedPatientIdsRef = useRef>(new Set()); // A stable, order/duplicate-independent key for the effect's dependency array - recomputed // every render (cheap), but only changes (and re-runs the effect) when the actual set of // unique patient ids changes. const uniquePatientIdsKey = Array.from( new Set(patientIds.filter((patientId): patientId is string => Boolean(patientId))), ) .sort() .join('|'); useEffect(() => { const uniquePatientIds = uniquePatientIdsKey ? uniquePatientIdsKey.split('|') : []; uniquePatientIds.forEach((patientId) => { if (requestedPatientIdsRef.current.has(patientId)) { return; } requestedPatientIdsRef.current.add(patientId); // THREE DOCUMENTS NOW EXIST AND THIS ROW STILL ASKS ABOUT ONE: the instrument named here is the HIPAA Authorization because that is the // one whose BEHAVIOUR the old welded "Authorization to Treat" actually had - an unsigned authorization // meant the practice could not see the record, which answers access, on an object whose name said // treatment. Naming it keeps this surface doing exactly what it did. Rebuilding these surfaces around // all three documents is the consent-flow work, not this change. void getStatus(patientId, undefined, RECORDS_INSTRUMENT) .then(({ status }) => { setStatusByPatientId((current) => ({ ...current, [patientId]: status })); }) .catch((error) => { console.error(`Failed to load org-authorization status for Patient/${patientId}:`, error); requestedPatientIdsRef.current.delete(patientId); }); }); // uniquePatientIdsKey fully determines the set iterated above; patientIds itself is // deliberately excluded so a same-set re-render (new array identity, same members) does // not re-run this effect. // eslint-disable-next-line react-hooks/exhaustive-deps }, [uniquePatientIdsKey, getStatus]); return statusByPatientId; };