import { useEffect } from 'react'; import { Invoice } from 'fhir/r4'; import { useInvoiceServiceContext, useFhirServiceContext, useWebSocketServiceContext } from '../services'; // Optional patientId: when provided (a patient-scoped invoice list), only react to that patient's // invoices. When omitted (the org-wide list), react to all - the list is already org-scoped server-side. export const useFhirInvoiceBroadcast = (patientId?: string) => { const { subscribe, unsubscribe } = useWebSocketServiceContext(); const { invoiceList, setInvoiceList } = useInvoiceServiceContext(); const { extractReferenceId } = useFhirServiceContext(); useEffect(() => { const handleInvoiceEvent = (cloudEvent: any) => { const invoice: Invoice = cloudEvent.data; const eventType = cloudEvent.type; const invoicePatientId = extractReferenceId(invoice.subject); if (patientId && patientId !== invoicePatientId) { return; } switch (eventType) { case 'com.akashichealthrecords.fhir.invoice.created': // The list has two writers: this broadcast, and the service's own refetch after a write // (several of which POLL until the new id appears). Refetch first and the list already holds // the record, so an unconditional append put a SECOND copy of it on screen - observed on a // patient's questionnaire answers, where one submission rendered as two completed forms. // Keeping the broadcast's copy rather than skipping: its body is at least as fresh. setInvoiceList(prev => prev.some(p => p.id === invoice.id) ? prev.map(p => p.id === invoice.id ? invoice : p) : [...prev, invoice] ); break; case 'com.akashichealthrecords.fhir.invoice.updated': // Invoices aren't archived - a voided/cancelled invoice stays visible with its new // status (e.g. a "paid"/"void" badge flip), so this always replaces, never removes. setInvoiceList(prev => prev.map(i => i.id === invoice.id ? invoice : i)); break; case 'com.akashichealthrecords.fhir.invoice.deleted': setInvoiceList(prev => prev.filter(i => i.id !== invoice.id)); break; } }; subscribe('com.akashichealthrecords.fhir.invoice.created', handleInvoiceEvent); subscribe('com.akashichealthrecords.fhir.invoice.updated', handleInvoiceEvent); subscribe('com.akashichealthrecords.fhir.invoice.deleted', handleInvoiceEvent); return () => { unsubscribe('com.akashichealthrecords.fhir.invoice.created', handleInvoiceEvent); unsubscribe('com.akashichealthrecords.fhir.invoice.updated', handleInvoiceEvent); unsubscribe('com.akashichealthrecords.fhir.invoice.deleted', handleInvoiceEvent); }; }, [patientId, subscribe, unsubscribe, extractReferenceId, invoiceList, setInvoiceList]); };