import { useCallback } from "react"; import { useHttpService } from "../services/HttpService.tsx"; import { environment } from "../environments/environment.ts"; import type { SaveTransport } from "../utils/saveOperation"; /** * Sending a test out to a laboratory the practice does not run, and the paper that goes with it. * * ONE ACT ON THE SERVER. Recording where it went and advancing the order happen in a single write, so * an order cannot reach "sent" with no laboratory named -- which is the state the queue could produce * before this existed. * * THE PAGE IS RENDERED ON THE SERVER, never here. The queue row carries no date of birth, no ordering * clinician and no diagnosis, and a page drawn twice is two pages whose difference only shows on the * one nobody can take back. */ /** Paper never transmits, even to a connected laboratory. */ export type SendMethod = "electronic" | "paper"; export interface SendOutRequest { npi: string; method?: SendMethod; display?: string; accountNumber: string; theirOrderCode?: string; note?: string; } export interface SentOut { orderId?: string; state?: string; laboratory?: string; npi?: string; accountNumber?: string; theirOrderCode?: string; sentAt?: string; /** Queued to the laboratory over a configured connection; false is the paper case. */ transmitting?: boolean; /** Saved to go electronically but not confirmed queued (refused or unanswered); the order offers a retry. */ transmission?: "queued" | "refused" | "unconfirmed" | "none"; /** Delivered into an Akashic laboratory's own intake, where it waits for them to accept it. */ akashic?: { laboratory?: string; deliveredAt?: string }; } export interface RequisitionPdf { contentType: string; filename: string; pdfBase64: string; pageCount?: number; } const ORDER_API = environment.fhirBaseApi; export const useSendOutDiagnosticOrder = () => { const { get, post } = useHttpService(); const sendOut = useCallback( (orderId: string, request: SendOutRequest) => post(`${ORDER_API}/diagnostic-order/${orderId}/send-out`, { npi: request.npi, accountNumber: request.accountNumber.trim(), ...(request.method ? { method: request.method } : {}), ...(request.display?.trim() ? { display: request.display.trim() } : {}), ...(request.theirOrderCode?.trim() ? { theirOrderCode: request.theirOrderCode.trim() } : {}), ...(request.note?.trim() ? { note: request.note.trim() } : {}), }), [post], ); const requisition = useCallback( (orderId: string) => get(`${ORDER_API}/diagnostic-order/${orderId}/requisition`), [get], ); /** Queue the saved electronic send again, the same one; the server refuses once a send has started. */ const resumeTransmission = useCallback( (orderId: string, transport?: SaveTransport) => post(`${ORDER_API}/diagnostic-order/${orderId}/send-out`, { resume: "transmission" }, { ...transport }), [post], ); return { sendOut, requisition, resumeTransmission }; }; /** * Put the rendered page in front of somebody. * * THE TAB IS OPENED BEFORE THE AWAIT, and that ordering is the whole of it: a popup blocker only * allows `window.open` while the click's user activation is alive, and one `await` ends it. The * referral preview learned this and it is copied rather than rediscovered. * * `noopener` IS NOT PASSED, because it makes `window.open` return null and there is then no tab to * point anywhere; `opener` is cleared by hand instead. * * THE OBJECT URL IS REVOKED ON A TIMER rather than immediately - revoking synchronously races the * opening tab onto a blank page. */ export const openPdfInTab = (tab: Window | null, pdf: RequisitionPdf) => { const binary = atob(pdf.pdfBase64); const bytes = new Uint8Array(binary.length); for (let at = 0; at < binary.length; at += 1) bytes[at] = binary.charCodeAt(at); const url = URL.createObjectURL(new Blob([bytes], { type: pdf.contentType })); if (tab) { tab.location.href = url; } setTimeout(() => URL.revokeObjectURL(url), 60_000); };