import { useCallback, useEffect, useState } from 'react'; import { BadgeCheck } from 'lucide-react'; import { useProofingServiceContext } from '../../services/ProofingService.tsx'; import { useAuthServiceContext } from '../../services/AuthService.tsx'; import { useProofingReturn } from '../../hooks/useProofingReturn.tsx'; // The sidebar "identity verified" marker - shown next to the signed-in person's name/avatar once // Stripe Identity has verified them. // // FAILS TOWARD NOT SHOWING, deliberately the OPPOSITE of every other proofing/authorization // surface in this app. Those are GATES: something that might block access must not silently vanish, // so they fail toward showing. This is an ASSERTION - "this person's government ID was checked" - // and staff make trust decisions off it. A badge rendered because a status call timed out is a false // claim about a human's identity. So: only an explicit 'verified' from the server renders anything; // unknown, degraded, and errored all render nothing. // // Only 'verified' qualifies - NOT 'pending'. A verification in flight is not a verification, and // there is a real window between the Stripe redirect and the webhook landing where the status is // still 'pending'. ProofingBanner covers that window with its own "Verifying..." state; this component // stays silent rather than claiming something not yet true. // // On return from Stripe this REFETCHES rather than optimistically assuming success (ProofingBanner // may assume - it is prompting, not asserting). The badge therefore appears a beat later, once the // webhook has actually landed, which is the correct trade for a claim of this kind. // // No request at all for staff: proofing is a patient/related-person trust decision (the routes admit // only AUTH.ROLES.PATIENTS and RELATED_PERSONS), so a practitioner session must not spend a call // asking about a status it can never hold. Gating here also keeps this safe to mount in the shell - // an authed fetch with no session would otherwise risk the provider auth-gate reload loop (see the // reference-app-provider-auth-gate memory). const VerifiedIdentityBadge = () => { const { getProofingStatus } = useProofingServiceContext(); const { currentUser } = useAuthServiceContext(); const [verified, setVerified] = useState(false); const resourceType = currentUser?.fhir?.resourceType; const canBeProofed = resourceType === 'Patient' || resourceType === 'RelatedPerson'; const [reloadKey, setReloadKey] = useState(0); useProofingReturn(useCallback(() => setReloadKey((key) => key + 1), [])); useEffect(() => { if (!canBeProofed) { return; } let cancelled = false; (async () => { try { const { status } = await getProofingStatus(); if (!cancelled) setVerified(status === 'verified'); } catch (err) { // See the assertion rule above - an unknown status is never rendered as verified. console.error('Failed to load proofing status for the identity badge:', err); if (!cancelled) setVerified(false); } })(); return () => { cancelled = true; }; }, [canBeProofed, getProofingStatus, reloadKey]); if (!verified) { return null; } // The wrapping span carries the tooltip and the accessible name rather than relying on the icon // library to forward a