import { useEffect, useState } from 'react'; import type { Invoice } from 'fhir/r4'; import { usePatientServiceContext } from '../../../services'; import { formatFhirHumanName } from '../../../utils/fhirHumanName'; import { UNREADABLE_BILL_FIELD } from './invoiceDisplay'; const subjectId = (invoice: Invoice) => invoice.subject?.reference?.split('/')[1]; export const useInvoicePatientNames = (invoices: Invoice[]): Record => { const { patientList, fetchPatient } = usePatientServiceContext(); const [fetched, setFetched] = useState>({}); const [failed, setFailed] = useState>({}); const names: Record = {}; for (const invoice of invoices) { const id = subjectId(invoice); const frozen = invoice.subject?.display?.trim(); if (id && frozen) names[id] = frozen; } const ids = [...new Set(invoices.map(subjectId).filter((id): id is string => Boolean(id)))]; for (const patient of patientList) { const name = patient.id && ids.includes(patient.id) ? formatFhirHumanName(patient.name, { emptyText: '' }) : ''; if (name) names[patient.id as string] = name; } for (const id of ids) { if (!names[id] && fetched[id]) names[id] = fetched[id]; if (!names[id] && failed[id]) names[id] = UNREADABLE_BILL_FIELD; } useEffect(() => { let cancelled = false; const dropGone = >(prev: T): T => { const extra = Object.keys(prev).filter((id) => !ids.includes(id)); if (extra.length === 0) return prev; const next = { ...prev }; for (const id of extra) delete next[id]; return next as T; }; setFetched(dropGone); setFailed(dropGone); const missing = ids.filter((id) => !names[id] && !failed[id] && !fetched[id]); if (missing.length === 0 || typeof fetchPatient !== 'function') return; void Promise.all(missing.map(async (id) => { try { const patient = await fetchPatient(id); const name = formatFhirHumanName(patient.name, { emptyText: '' }); if (cancelled) return; if (name) setFetched((prev) => (prev[id] ? prev : { ...prev, [id]: name })); else setFailed((prev) => (prev[id] ? prev : { ...prev, [id]: true })); } catch { if (!cancelled) setFailed((prev) => (prev[id] ? prev : { ...prev, [id]: true })); } })); return () => { cancelled = true; }; }, [ids.join(','), fetchPatient]); return names; }; export const invoiceSubjectId = subjectId;