import type { RelatedPerson } from 'fhir/r4'; /* * THE INVITE-STATUS EXTENSION, CLIENT SIDE - the mirror of * `aws/sam/services/api/src/utils/relatedPersonInviteStatus.ts`. * * THE URLS MUST MATCH THE SERVER BYTE FOR BYTE. The server WRITES these and the client READS them * back; a typo here is not a compile error, it is a screen that silently says nothing. */ export const RELATED_PERSON_INVITE_STATUS_URL = 'https://akashichealthrecords.com/fhir/StructureDefinition/related-person-invite-status'; export const RELATED_PERSON_INVITE_DECLINED_AT_URL = 'https://akashichealthrecords.com/fhir/StructureDefinition/related-person-invite-declined-at'; export type RelatedPersonInviteAnswer = 'pending' | 'declined' | 'accepted'; /** * WHAT THE INVITER IS OWED, AND WHY THIS EXISTS AT ALL. * * The defect this was raised on: the person who sent an invitation cannot tell the difference between * declined and never seen, and waits forever on an answer already given. * * MEASURED IN THE PRODUCT 2026-09-02, after the decline route landed: a declined invitation rendered * on the inviter's own Family page as a row with **no badge** - byte-identical to a pending one, because * the only thing the row read was `active === true`. **The refusal was recorded and no screen read it.** * A durable answer nothing displays is the same to the person waiting as no answer at all. * * `active` ALONE CANNOT ANSWER THIS, which is the trap. A pending link and a declined link are BOTH * `active: false` - deliberately, so that a refusal keeps failing closed on every access chokepoint. The * two are distinguished only by this extension's VALUE. */ export const inviteAnswerOf = (relatedPerson: RelatedPerson | undefined | null): RelatedPersonInviteAnswer => { if (relatedPerson?.active === true) return 'accepted'; const status = relatedPerson?.extension?.find((e) => e.url === RELATED_PERSON_INVITE_STATUS_URL); return status?.valueCode === 'declined' ? 'declined' : 'pending'; }; /** ISO-8601, when they answered. Absent on a link declined before the instant was recorded. */ export const declinedAtOf = (relatedPerson: RelatedPerson | undefined | null): string | undefined => relatedPerson?.extension?.find((e) => e.url === RELATED_PERSON_INVITE_DECLINED_AT_URL)?.valueInstant;