import { useEffect } from 'react'; import { Device } from 'fhir/r4'; import { useDeviceServiceContext, usePatientServiceContext, useWebSocketServiceContext } from '../services'; import { isSaveRetired, useSaveScope, type SaveOperation } from '../utils/saveOperation'; import { olderThan } from '../utils/versionOrder'; interface UseDeviceWebSocketOptions { device?: Device; deviceId?: string; isOpen?: boolean; onUpdate: (device: Device) => void; onDelete: () => void; } export const useFhirDeviceTargetedBroadcast = ({ device, deviceId, isOpen = true, onUpdate, onDelete, }: UseDeviceWebSocketOptions) => { const { subscribe, unsubscribe } = useWebSocketServiceContext(); const { patientState } = usePatientServiceContext(); const { fetchDevice } = useDeviceServiceContext(); const patientId = patientState?.id; const targetId = deviceId ?? device?.id; const bound = Boolean(isOpen && patientId && targetId && device?.id === targetId && device.patient?.reference === `Patient/${patientId}`); const scope = useSaveScope(bound ? `${patientId}/${targetId}` : undefined); useEffect(() => { if (!bound || !device || !targetId) return; let live = true; let active: SaveOperation | undefined; const updated = 'com.akashichealthrecords.fhir.device.updated'; const deleted = 'com.akashichealthrecords.fhir.device.deleted'; const handleDeviceEvent = async (event: { type?: string; data?: { id?: string; resourceType?: string } }) => { if (!live || event?.data?.id !== targetId || (event.data.resourceType && event.data.resourceType !== 'Device') || (event.type !== updated && event.type !== deleted)) return; active?.retire(); const operation = scope.start(); active = operation; try { // A notice names a read; only the authorized answer can replace the displayed record. const fresh = await operation.step(() => fetchDevice(targetId, operation.transport)); operation.admit(); if (!live || active !== operation || fresh.resourceType !== 'Device' || fresh.id !== targetId || fresh.patient?.reference !== `Patient/${patientId}` || !fresh.meta?.versionId || olderThan(fresh, device)) return; onUpdate(fresh); } catch (error) { if (!live || active !== operation || isSaveRetired(error) || !operation.belongs()) return; try { operation.admit(); } catch { return; } if (event.type === deleted && (error as { status?: unknown })?.status === 404) onDelete(); } finally { operation.retire(); if (active === operation) active = undefined; } }; subscribe(updated, handleDeviceEvent); subscribe(deleted, handleDeviceEvent); return () => { live = false; active?.retire(); unsubscribe(updated, handleDeviceEvent); unsubscribe(deleted, handleDeviceEvent); }; }, [bound, patientId, targetId, device, fetchDevice, onUpdate, onDelete, subscribe, unsubscribe, scope]); };