import { useEffect, useMemo, useState, type ReactNode } from 'react';
import { Outlet, useLocation } from 'react-router-dom';
import { useAuthServiceContext } from '../../../../services/AuthService';
import { authSessionId } from '../../../../services/authStorage';
import { AgreementBlocks } from '../../../../components/FirstSignInGate/AgreementBlocks';
import { useMsaRecovery, type MsaRecoveryLocator, type MsaRecoveryOpening } from '../../../../hooks/useMsaRecovery';
import { heldMsaKey, msaOperationId, readHeldMsa, type HeldMsaOperation } from '../../../../utils/msaRecovery';
import { msaClosingLines, resolveMsaBlocks } from '../../../../utils/msaAgreement';
import { formatDayMonthYear } from '../../../../utils/dateUtils';
import type { BaaSignFormParts } from './BaaSignForm';
type Parts = (parts: BaaSignFormParts) => ReactNode;
const RecoveryView = ({ opening, children }: { opening: MsaRecoveryOpening; children: Parts }) => {
const { read, busy, error, actorMatches, canResume, check, resume } = opening;
const preview = actorMatches && read?.actorMayResume ? read.frozen?.preview : undefined;
const request = read?.frozen?.request;
const facts = preview && request ? { ...preview.facts, signerName: request.signerName, signerTitle: request.signerTitle, signDate: request.signDate } : undefined;
const body =
This checks the acceptance you already started. It does not start a new agreement or change your Business Associate Agreement.
{busy &&
Checking your original acceptance…
}
{error &&
{error}
}
{!busy && read?.state === 'accepted' && actorMatches &&
Version {read.version} accepted on {formatDayMonthYear(read.acceptedAt ?? '')}. Your original acceptance is confirmed.
}
{!busy && read?.state === 'absent' &&
Your original acceptance has not been found yet. Check again; a delayed request may still arrive.
}
{!busy && read?.state === 'conflict' &&
This acceptance needs Akashic support. Its original reference has been kept.
}
{!busy && read && read.state !== 'absent' && !actorMatches &&
This acceptance belongs to another sign-in. Use the original account to check it.
}
{!busy && read?.state === 'admitted' && actorMatches && (!read.actorMayResume || !preview) &&
The original agreement could not be confirmed for recording. Check again before continuing.
}
{!busy && read?.state === 'admitted' && actorMatches && read.actorMayResume && preview &&
Your acceptance could not be confirmed yet. Resume recording to finish that same acceptance.
}
{preview && facts &&
{preview.title}
{msaClosingLines(facts).map((line) =>
{line}
)}
}
;
const actions =
{canResume && }
;
return <>{children({ body, actions, wide: true })}>;
};
export const MsaRecoveryPage = ({ opening }: { opening: MsaRecoveryOpening }) =>
Master Subscription Agreement
{({ body, actions }) => <>{body}{actions}>}
;
const HeldOpening = ({ locator, onAccepted, children }: { locator: MsaRecoveryLocator; onAccepted: () => void; children: Parts }) => {
const opening = useMsaRecovery(locator, onAccepted);
return {children};
};
export const MsaHeldForm = ({ held, onAccepted, children }: { held: HeldMsaOperation; onAccepted: () => void; children: Parts }) => {
const { currentUser, wpOrganization, actingAsSessionRef } = useAuthServiceContext();
const practitionerId = currentUser?.fhir?.resourceType === 'Practitioner' ? currentUser.fhir.id : undefined;
if (!practitionerId || currentUser?.cognito?.sub !== held.actorId || wpOrganization.current?.id !== held.organizationId) {
return Use the original sign-in and practice to check this acceptance.
;
}
const key = [held.request.operationId, held.actorId, practitionerId, authSessionId(), actingAsSessionRef.current].join('|');
return {children};
};
const RouteOpening = ({ locator, renderOpening }: { locator: MsaRecoveryLocator; renderOpening?: (opening: MsaRecoveryOpening) => ReactNode }) => {
const [captured] = useState(locator);
const opening = useMsaRecovery(captured);
return opening.canOpen
? <>{renderOpening ? renderOpening(opening) : }>
: ;
};
/** Only this MSA route receives the recovery opening; the existing fresh-owner sheet remains its fallback. */
export const MsaRecoveryAccess = ({ fallback, renderOpening }: { fallback: ReactNode; renderOpening?: (opening: MsaRecoveryOpening) => ReactNode }) => {
const { currentUser, wpOrganization, actingAsSessionRef } = useAuthServiceContext();
const { search } = useLocation();
const organizationId = wpOrganization.current?.id;
const actorId = currentUser?.cognito?.sub;
const practitionerId = currentUser?.fhir?.resourceType === 'Practitioner' ? currentUser.fhir.id : undefined;
const [revision, setRevision] = useState(0);
useEffect(() => {
const changed = (event: StorageEvent) => {
if (organizationId && actorId && (event.key === null || event.key === heldMsaKey(organizationId, actorId)
|| event.key?.startsWith(heldMsaKey(organizationId, actorId) + '.op.'))) setRevision((n) => n + 1);
};
window.addEventListener('storage', changed);
return () => window.removeEventListener('storage', changed);
}, [organizationId, actorId]);
const held = useMemo(() => organizationId && actorId ? readHeldMsa(organizationId, actorId) : undefined, [organizationId, actorId, revision]);
const requested = new URLSearchParams(search).get('msaOperation');
if (!held && requested === null) return <>{fallback}>;
const operationId = requested ?? (held && held !== 'unavailable' ? held.request.operationId : undefined);
if (!organizationId || !actorId || !practitionerId || !msaOperationId(operationId)) return
Your previous acceptance could not be read safely. Contact Akashic support before starting another.
;
const saved = held && held !== 'unavailable' && held.request.operationId === operationId ? held : undefined;
const key = [organizationId, actorId, practitionerId, operationId, authSessionId(), actingAsSessionRef.current, saved ? JSON.stringify(saved.request) : 'discovered'].join('|');
return ;
};