import { useEffect, useState } from "react"; import { AlertCircle } from "lucide-react"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "../../../../components/ui/dialog.tsx"; import { Button } from "../../../../components/ui/button.tsx"; import { Input } from "../../../../components/ui/input.tsx"; import { Label } from "../../../../components/ui/label.tsx"; import { Alert, AlertDescription } from "../../../../components/ui/alert.tsx"; import { relayServerFailure } from "../../../../utils/fetchFailureMessage"; import { AKASHIC_LAB_CONNECTION, connectionProblem, LAB_CONNECTION_TYPES, type LabConnection, type LabConnectionDraft, type LabConnectionType, } from "../../../../hooks/useLabConnections.ts"; import "./DiagnosticsPage.css"; // Recording a laboratory, and changing one that is already recorded. // // THE NPI CANNOT BE CHANGED ONCE IT IS SAVED, and the field says so rather than being refused after // somebody has typed. The connection is stored at an id derived from it, so a changed NPI would be a // different laboratory wearing this one's address and account number -- the server refuses it, and a // screen that offered the field anyway would be inviting a round trip that can only fail. // // No credential field here: a sign-in has its own dialog and route, so this save can never echo one. export type ConnectionTarget = | { mode: "add" } | { mode: "edit"; connection: LabConnection } | undefined; interface Props { target: ConnectionTarget; onClose: () => void; addConnection: (draft: LabConnectionDraft) => Promise; saveConnection: (id: string, draft: LabConnectionDraft) => Promise; } const EMPTY: LabConnectionDraft = { name: "", npi: "", connectionType: "", address: "", accountNumber: "", }; const draftFrom = (connection: LabConnection): LabConnectionDraft => ({ name: connection.name ?? "", npi: connection.npi ?? "", connectionType: connection.connectionType ?? "", address: connection.address ?? "", accountNumber: connection.accountNumber ?? "", }); /** What goes in the address box depends entirely on the transport, so the hint follows it. */ const ADDRESS_HINT: Record = { akashic: "", "hl7v2-mllp": "mllp://orders.example-lab.com:2575", "hl7-fhir-rest": "https://api.example-lab.com/fhir/R4", "secure-email": "orders@example-lab.com", "direct-project": "orders@direct.example-lab.com", }; const LabConnectionEditor = ({ target, onClose, addConnection, saveConnection }: Props) => { const [draft, setDraft] = useState(EMPTY); const [saving, setSaving] = useState(false); const [error, setError] = useState(); useEffect(() => { setDraft(target?.mode === "edit" ? draftFrom(target.connection) : EMPTY); setError(undefined); }, [target]); if (!target) return null; const editing = target.mode === "edit"; const akashic = draft.connectionType === AKASHIC_LAB_CONNECTION; // An Akashic link is made only by adding it, and a transport is never turned into one, so an edit offers // only the kind the connection already is. const offered = LAB_CONNECTION_TYPES.filter((transport) => !editing || (transport.id === AKASHIC_LAB_CONNECTION) === (target.connection.connectionType === AKASHIC_LAB_CONNECTION)); const set = (patch: Partial) => setDraft((prev) => ({ ...prev, ...patch })); const submit = async () => { const problem = connectionProblem(draft); if (problem) { setError(problem); return; } setSaving(true); setError(undefined); try { if (target.mode === "edit") { await saveConnection(target.connection.id as string, draft); } else { await addConnection(draft); } onClose(); } catch (failure) { console.error("Error saving the laboratory connection:", failure); setError(relayServerFailure( failure, "That laboratory could not be saved. Please try again.", )); } finally { setSaving(false); } }; return ( { if (!open && !saving) onClose(); }}> {editing ? "Edit a laboratory" : "Add a laboratory"} Where this practice sends the work it does not run itself. {error ? ( {error} ) : null}
{akashic && !editing ? null : (
set({ name: e.target.value })} placeholder="Riverbend Reference Laboratory" disabled={akashic} /> {akashic ?

Akashic names a laboratory on Akashic from its NPI.

: null}
)}
set({ npi: e.target.value })} placeholder="1548273901" inputMode="numeric" disabled={editing} />

{editing ? "A different NPI is a different laboratory. Add that one separately and switch this one off." : akashic ? "Ten digits. Akashic finds the practice with this NPI and names it." : "Ten digits. This is how the laboratory is identified."}

How it is connected {offered.map((transport) => ( // Paired by `htmlFor`/`id` rather than by nesting, and the name is a // direct child of the label so it has discoverable accessible text. ))}
{akashic ? null : (
set({ address: e.target.value })} placeholder={ draft.connectionType ? ADDRESS_HINT[draft.connectionType] : "Choose a transport first" } />
)}
set({ accountNumber: e.target.value })} placeholder="The client number this laboratory bills you under" />

This prints on the requisition, so the laboratory knows whose account the work belongs to.

); }; export default LabConnectionEditor;