import { useEffect, useState } from 'react'; import { useAkashicAgreementsServiceContext, type AcceptedAgreement, type PatientAgreementKind } from '../../../services/AkashicAgreementsService'; import { formatDateForDisplay } from '../../../lib/utils'; import { blocksShowTheirText, deriveBody, resolveCopy, type AgreementCopy } from '../../../components/FirstSignInGate/agreementCopy.ts'; import { AgreementBlocks } from '../../../components/FirstSignInGate/AgreementBlocks.tsx'; /** * WHAT THIS PERSON ACCEPTED FROM AKASHIC, AND AT WHICH VERSION. * * Both instruments are accepted in one breath at first sign-in and then nothing in the portal said so: * the navigation had no agreements entry and the profile showed neither. The write side has been proven * for a year; this is the read. * * BOTH ROWS ALWAYS, even when one cannot be read. A surface that renders the instrument it managed to * fetch and drops the other leaves a gap that reads as "not accepted" rather than "not readable", for * two documents a patient answered together - so each row carries its own state and says which it is. */ const INSTRUMENTS: { kind: PatientAgreementKind; name: string }[] = [ { kind: 'terms-of-service', name: 'Terms of Service' }, { kind: 'privacy-consent', name: 'HIPAA Privacy Notice' }, ]; type RowState = | { phase: 'loading' } | { phase: 'read'; accepted: AcceptedAgreement } | { phase: 'unreadable' }; /** * THE TEXT OF THE VERSION SIGNED, NEVER THE VERSION IN FORCE NOW. * * Mirrors FirstSignInGate's own resolution: a served copy is trusted only when its two halves agree * (`deriveBody(blocks) === body`), and the bundle is tried only by passing the ACCEPTED version to * `resolveCopy` - which refuses on any mismatch, so a bundle written for today's text can never stand * in for an older acceptance. */ function resolveAcceptedCopy(kind: PatientAgreementKind, accepted: AcceptedAgreement): AgreementCopy | undefined { const served = accepted.acceptedCopy; const servedCopy: AgreementCopy | undefined = served && served.blocks?.length && deriveBody(served.blocks) === served.body && blocksShowTheirText(served.blocks) ? { title: served.title, blocks: served.blocks, body: served.body } : undefined; if (servedCopy) return servedCopy; return accepted.acceptedVersion ? resolveCopy(kind, accepted.acceptedVersion) : undefined; } export const AcceptedAgreements = () => { const { getAccepted } = useAkashicAgreementsServiceContext(); const [rows, setRows] = useState>({}); const [expanded, setExpanded] = useState>({}); useEffect(() => { let cancelled = false; INSTRUMENTS.forEach(({ kind }) => { (async () => { try { const accepted = await getAccepted(kind); if (!cancelled) setRows((prev) => ({ ...prev, [kind]: { phase: 'read', accepted } })); } catch (error) { // SAID, NOT SWALLOWED. A failed read here is indistinguishable on screen from never // having accepted, and those are opposite facts about a legal agreement. console.error('Could not read the accepted agreement:', error); if (!cancelled) setRows((prev) => ({ ...prev, [kind]: { phase: 'unreadable' } })); } })(); }); return () => { cancelled = true; }; }, [getAccepted]); return (

Akashic agreements

What you have accepted from Akashic, and the version you accepted. These are separate from any agreement with a practice.

    {INSTRUMENTS.map(({ kind, name }) => { const row = rows[kind] ?? { phase: 'loading' as const }; return (
  • {name}

    {row.phase === 'loading' && (

    Checking…

    )} {row.phase === 'unreadable' && (

    We could not read this one just now. It does not mean you have not accepted it.

    )} {row.phase === 'read' && row.accepted.applies === false && (

    {row.accepted.applicabilityReason === 'demo' ? 'Not applicable in this demo. The Demo agreement governs this fictional visit.' : 'Does not apply. Nobody needs to accept this one for them.'}

    )} {row.phase === 'read' && row.accepted.applies !== false && !row.accepted.accepted && (

    Not accepted yet.

    )} {row.phase === 'read' && row.accepted.applies !== false && row.accepted.accepted && ( <>

    {row.accepted.acceptedByName ? `Accepted by ${row.accepted.acceptedByName}${row.accepted.acceptedByGuardian ? ' as parent or guardian' : ''}` : row.accepted.acceptedByGuardian ? 'Accepted for them by a parent or guardian' : 'Accepted'} {row.accepted.acceptedAt ? ` on ${formatDateForDisplay(row.accepted.acceptedAt)}` : ''} {row.accepted.acceptedVersion ? `, version ${row.accepted.acceptedVersion}` : ''}

    {/* THE VERSION HAVING MOVED IS NOT A PROBLEM AND MUST NOT READ AS ONE. Nothing is owed until the practice asks again; what matters is that the version shown is the one signed, never today's wording. */} {!row.accepted.acceptedCurrentVersion && (

    {row.accepted.guardianAnswers ? 'Because you are under 18, a parent or guardian answers this for you now.' : row.accepted.ageUnknown ? 'Your date of birth is needed before this can be answered.' : `The current version is ${row.accepted.currentVersion}. You will be asked about it the next time it matters.`}

    )} {row.accepted.acceptedVersion && ( <> {expanded[kind] && (() => { const copy = resolveAcceptedCopy(kind, row.accepted); return copy ? (
    ) : (

    The text of version {row.accepted.acceptedVersion} is not available here.

    ); })()} )} )}
  • ); })}
); }; export default AcceptedAgreements;