import { useEffect } from 'react'; import { QuestionnaireResponse } from 'fhir/r4'; import { useQuestionnaireResponseServiceContext, useFhirServiceContext, usePatientServiceContext, useWebSocketServiceContext } from '../services'; import { isArchived } from '../utils/archivedResource'; export const useFhirQuestionnaireResponseBroadcast = () => { const { subscribe, unsubscribe } = useWebSocketServiceContext(); const { questionnaireResponsesList, setQuestionnaireResponsesList } = useQuestionnaireResponseServiceContext(); const { patientState } = usePatientServiceContext(); const { extractReferenceId } = useFhirServiceContext(); useEffect(() => { if (!patientState) { return; } const handleQuestionnaireResponseEvent = (cloudEvent: any) => { const questionnaireResponse: QuestionnaireResponse = cloudEvent.data; const eventType = cloudEvent.type; const patientId = extractReferenceId(questionnaireResponse.author); if (patientState.id === patientId) { switch (eventType) { /** * The append is CONDITIONAL, because this list has two writers and they race. * * A patient submitting an assigned questionnaire triggers BOTH a refetch (which polls * until the new id appears and then replaces the whole list) and this broadcast. When * the refetch lands first the list already holds the record, and an unconditional * append put a SECOND copy of it on the patient's Questionnaire Responses page - * observed 2026-08-20: one submission, one resource on the server at `versionId: 1`, * two identical rows on screen, and a reload showed one. Nothing was duplicated in * the record; the patient was simply told they had submitted twice. * * Replacing rather than skipping: the event body is at least as fresh as whatever * the refetch returned, so if both are present the broadcast's copy is the one to keep. */ case 'com.akashichealthrecords.fhir.questionnaireresponse.created': setQuestionnaireResponsesList(prev => prev.some(p => p.id === questionnaireResponse.id) ? prev.map(p => p.id === questionnaireResponse.id ? questionnaireResponse : p) : [...prev, questionnaireResponse] ); break; case 'com.akashichealthrecords.fhir.questionnaireresponse.updated': setQuestionnaireResponsesList(prev => isArchived(questionnaireResponse) ? prev.filter(p => p.id !== questionnaireResponse.id) : prev.map(p => p.id === questionnaireResponse.id ? questionnaireResponse : p) ); break; case 'com.akashichealthrecords.fhir.questionnaireresponse.deleted': setQuestionnaireResponsesList(prev => prev.filter(p => p.id !== questionnaireResponse.id)); break; } } }; subscribe('com.akashichealthrecords.fhir.questionnaireresponse.created', handleQuestionnaireResponseEvent); subscribe('com.akashichealthrecords.fhir.questionnaireresponse.updated', handleQuestionnaireResponseEvent); subscribe('com.akashichealthrecords.fhir.questionnaireresponse.deleted', handleQuestionnaireResponseEvent); return () => { unsubscribe('com.akashichealthrecords.fhir.questionnaireresponse.created', handleQuestionnaireResponseEvent); unsubscribe('com.akashichealthrecords.fhir.questionnaireresponse.updated', handleQuestionnaireResponseEvent); unsubscribe('com.akashichealthrecords.fhir.questionnaireresponse.deleted', handleQuestionnaireResponseEvent); }; }, [patientState, subscribe, unsubscribe, extractReferenceId, questionnaireResponsesList]); };