// ============================================================ // SICK VISIT — /api/sick-visit/note // ============================================================ import { useState } from 'react'; import { useMutation } from '@tanstack/react-query'; import { api, ApiError } from '@/lib/api'; import type { VisitNoteOk } from '@/shared/types'; import { SickVisitRequestSchema, type SickVisitRequest } from '@/shared/schemas'; import Recorder from '@/components/Recorder'; import EncounterToolbar from '@/components/EncounterToolbar'; import EditableResult from '@/components/EditableResult'; import RosPeTable, { rosAllWnl, rosClear } from '@/components/RosPeTable'; import DxPicker from '@/components/DxPicker'; import { ROS_SYSTEMS, PE_SYSTEMS, formatRosForAI, formatDxForAI, type RosData, type DxEntry, } from '@shared/clinical/ros-pe-dx'; const TYPE = 'sickvisit' as const; export default function SickVisit() { const [label, setLabel] = useState(''); const [patientAge, setPatientAge] = useState(''); const [patientGender, setPatientGender] = useState(''); const [chiefComplaint, setChiefComplaint] = useState(''); const [transcript, setTranscript] = useState(''); const [interim, setInterim] = useState(''); const [rosData, setRosData] = useState({}); const [peData, setPeData] = useState({}); const [diagnoses, setDiagnoses] = useState([]); const [dxFreetext, setDxFreetext] = useState(''); const [result, setResult] = useState(null); const [validationError, setValidationError] = useState(null); const [recError, setRecError] = useState(null); const generate = useMutation({ mutationFn: (body) => api.post('/api/sick-visit/note', body), onSuccess: (data) => setResult(data.note), }); function submit(e: React.FormEvent) { e.preventDefault(); setValidationError(null); const rosText = formatRosForAI(ROS_SYSTEMS, rosData, 'Review of Systems'); const peText = formatRosForAI(PE_SYSTEMS, peData, 'Physical Examination'); const dxText = formatDxForAI(diagnoses, dxFreetext); const body: SickVisitRequest = { patientAge, patientGender, chiefComplaint, transcript: (interim || transcript).trim(), ros: rosText || undefined, physicalExam: peText || undefined, diagnoses: dxText || undefined, }; const parsed = SickVisitRequestSchema.safeParse(body); if (!parsed.success) { setValidationError(parsed.error.issues.map((i: { message: string }) => i.message).join(', ')); return; } setResult(null); generate.mutate(parsed.data); } const input = 'w-full rounded-md border border-input bg-background px-3 py-2 text-sm'; const displayedTranscript = interim || transcript; return (

Sick Visit

Chief complaint + transcript → structured sick-visit note.

{ setTranscript(enc.transcript || ''); setInterim(''); setResult(enc.generated_note || null); try { const pd = enc.partial_data ? JSON.parse(enc.partial_data) : null; if (pd?.age) setPatientAge(pd.age); if (pd?.gender) setPatientGender(pd.gender); if (pd?.chiefComplaint) setChiefComplaint(pd.chiefComplaint); if (pd?.rosData) setRosData(pd.rosData); if (pd?.peData) setPeData(pd.peData); if (pd?.diagnoses) setDiagnoses(pd.diagnoses); if (pd?.dxFreetext) setDxFreetext(pd.dxFreetext); } catch { /* ignore */ } setLabel(enc.label || ''); }} onClear={() => { setTranscript(''); setInterim(''); setResult(null); setValidationError(null); setPatientAge(''); setPatientGender(''); setChiefComplaint(''); setRosData({}); setPeData({}); setDiagnoses([]); setDxFreetext(''); }} />
{ setTranscript((prev) => (meta.appended ? (prev ? prev + ' ' + text : text) : text)); setInterim(''); setRecError(null); }} onInterim={(t) => setInterim(t ? (transcript ? transcript + ' ' + t : t) : '')} onError={(msg) => setRecError(msg)} /> {recError &&
{recError}
}