import { useCallback } from "react"; import type { SaveTransport } from "../utils/saveOperation"; import type { ServiceRequest } from "fhir/r4"; import { useHttpService } from "../services/HttpService.tsx"; import { environment } from "../environments/environment.ts"; import type { IValueSet } from "../services"; import type { DiagnosticOrderKind } from "../utils/diagnosticOrderQueue"; import type { DiagnosticOrderPriority } from "./usePlaceDiagnosticOrder.ts"; /** * Ordering several tests in one act. * * NOT THE SINGLE-ORDER ROUTE CALLED N TIMES. Three calls are three acts that can half succeed with * nobody holding the result: the browser would have to decide what to do when the second failed, and * the tests would be grouped by nothing. One call means the server answers for the whole panel and * writes the parent that holds it together. * * ON THE BASE API, NOT THE CLINICAL ONE, because it is a `diagnostic-order` route and those are * declared in the base template -- the same gateway the queue and the send-out use. ServiceRequest * itself lives on the clinical gateway, which is why the single-order hook next door points there. * * THE PATIENT GOES IN THE QUERY AS WELL AS THE BODY, and that is not redundancy: the route is gated on * patient access and that gate runs in a request authorizer, which never receives a body. Without it * the call is refused before a handler sees it, and the browser is told only that it is not authorized. */ export interface DiagnosticPanelTest { /** What was ordered. Free text is legitimate -- the lookup may be unavailable. */ text: string; /** Present only when a code was actually chosen; a result is matched back through it later. */ coding?: IValueSet; } export interface PlaceDiagnosticPanelRequest { patientId: string; kind: DiagnosticOrderKind; /** What the panel is called. Optional: several tests ordered together need not have a name. */ name?: string; tests: DiagnosticPanelTest[]; priority: DiagnosticOrderPriority; encounterId?: string; reason?: string; diagnosis?: IValueSet; } export interface PlacedDiagnosticPanel { panelId?: string; name?: string; groupId?: string; /** * The stored orders, ready to show without re-reading. The search index lags a write by minutes, so * a screen that reloaded to display them would get a list without them. */ orders?: ServiceRequest[]; /** Tests the server could not write. The rest were placed and are real work. */ refused?: { test: string; message: string }[]; } const ORDER_API = environment.fhirBaseApi; export const usePlaceDiagnosticPanel = () => { const { post } = useHttpService(); return useCallback( (request: PlaceDiagnosticPanelRequest, transport?: SaveTransport): Promise => post( `${ORDER_API}/diagnostic-panel?subject=${encodeURIComponent(`Patient/${request.patientId}`)}`, { patientId: request.patientId, kind: request.kind, priority: request.priority, tests: request.tests.map((test) => ({ text: test.text, ...(test.coding ? { code: test.coding.code, system: test.coding.system } : {}), })), ...(request.name?.trim() ? { name: request.name.trim() } : {}), ...(request.encounterId ? { encounterId: request.encounterId } : {}), ...(request.reason?.trim() ? { reason: request.reason.trim() } : {}), ...(request.diagnosis ? { diagnosis: request.diagnosis } : {}), }, transport, ), [post], ); };