import { useEffect } from 'react'; import { CareTeam } from 'fhir/r4'; import { useAuthServiceContext, useCareTeamServiceContext, useFhirServiceContext, usePatientServiceContext, useWebSocketServiceContext } from '../services'; import { isArchived } from '../utils/archivedResource'; import { useCareTeamReadScope } from './useCareTeamReadScope'; export const useFhirCareTeamBroadcast = () => { const { subscribe, unsubscribe } = useWebSocketServiceContext(); const { openListWriter, writeCareTeamsList } = useCareTeamServiceContext(); const { patientState } = usePatientServiceContext(); const { currentOrganization } = useAuthServiceContext(); const scope = useCareTeamReadScope(patientState?.id); const organizationId = currentOrganization?.id; const { extractReferenceId } = useFhirServiceContext(); useEffect(() => { if (!patientState) { return; } // This subscription writes only into the list read for its own scope, and not at all once it ends. const writer = openListWriter(scope, patientState.id, organizationId); const handleCareTeamEvent = (cloudEvent: any) => { const careTeam: CareTeam = cloudEvent.data; const eventType = cloudEvent.type; const patientId = extractReferenceId(careTeam.subject); if (patientState.id === patientId) { const setCareTeamsList = (update: (prev: CareTeam[]) => CareTeam[], removed = false) => writeCareTeamsList(writer, update, { resource: careTeam, removed }); switch (eventType) { case 'com.akashichealthrecords.fhir.careteam.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. setCareTeamsList(prev => prev.some(p => p.id === careTeam.id) ? prev.map(p => p.id === careTeam.id ? careTeam : p) : [...prev, careTeam] ); break; case 'com.akashichealthrecords.fhir.careteam.updated': setCareTeamsList(prev => isArchived(careTeam) ? prev.filter(p => p.id !== careTeam.id) : prev.map(p => p.id === careTeam.id ? careTeam : p), isArchived(careTeam) ); break; case 'com.akashichealthrecords.fhir.careteam.deleted': setCareTeamsList(prev => prev.filter(p => p.id !== careTeam.id), true); break; } } }; subscribe('com.akashichealthrecords.fhir.careteam.created', handleCareTeamEvent); subscribe('com.akashichealthrecords.fhir.careteam.updated', handleCareTeamEvent); subscribe('com.akashichealthrecords.fhir.careteam.deleted', handleCareTeamEvent); return () => { writer.retired = true; unsubscribe('com.akashichealthrecords.fhir.careteam.created', handleCareTeamEvent); unsubscribe('com.akashichealthrecords.fhir.careteam.updated', handleCareTeamEvent); unsubscribe('com.akashichealthrecords.fhir.careteam.deleted', handleCareTeamEvent); }; }, [patientState, scope, organizationId, subscribe, unsubscribe, extractReferenceId, openListWriter, writeCareTeamsList]); };