diff --git a/client/src/App.tsx b/client/src/App.tsx index 4502774..6e43c49 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -4,6 +4,9 @@ import Layout from '@/components/Layout'; import Extensions from '@/pages/Extensions'; import Faq from '@/pages/Faq'; import Dictation from '@/pages/Dictation'; +import Encounter from '@/pages/Encounter'; +import Soap from '@/pages/Soap'; +import SickVisit from '@/pages/SickVisit'; const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 30_000, retry: 1 } }, @@ -19,8 +22,11 @@ function Home() {

Ported tabs so far:

@@ -34,8 +40,11 @@ export default function App() { }> } /> - } /> + } /> } /> + } /> + } /> + } /> } /> {/* catch-all falls back to home while more tabs port over */} } /> diff --git a/client/src/components/Layout.tsx b/client/src/components/Layout.tsx index dfb4a3d..57f53c5 100644 --- a/client/src/components/Layout.tsx +++ b/client/src/components/Layout.tsx @@ -22,7 +22,7 @@ const NAV: NavGroup[] = [ { label: 'Encounters', items: [ - { to: '/encounter', label: 'Encounter HPI', available: false }, + { to: '/encounter', label: 'Encounter HPI', available: true }, { to: '/dictation', label: 'Dictation HPI', available: true }, ], }, @@ -31,9 +31,9 @@ const NAV: NavGroup[] = [ items: [ { to: '/hospital', label: 'Hospital Course', available: false }, { to: '/chart', label: 'Chart Review', available: false }, - { to: '/soap', label: 'SOAP Note', available: false }, + { to: '/soap', label: 'SOAP Note', available: true }, { to: '/wellvisit', label: 'Well Visit', available: false }, - { to: '/sickvisit', label: 'Sick Visit', available: false }, + { to: '/sickvisit', label: 'Sick Visit', available: true }, ], }, { diff --git a/client/src/pages/Encounter.tsx b/client/src/pages/Encounter.tsx new file mode 100644 index 0000000..c6710e8 --- /dev/null +++ b/client/src/pages/Encounter.tsx @@ -0,0 +1,112 @@ +// ============================================================ +// ENCOUNTER — live encounter → HPI via /api/generate-hpi-encounter +// Minimum-viable port: same shape as Dictation (same endpoint family). +// Audio capture + save/load + refine deferred to follow-up commits. +// ============================================================ + +import { useState } from 'react'; +import { useMutation } from '@tanstack/react-query'; +import { api, ApiError } from '@/lib/api'; +import type { HpiOk } from '@/shared/types'; +import { HpiEncounterRequestSchema, type HpiEncounterRequest } from '@/shared/schemas'; + +type Setting = 'outpatient' | 'inpatient'; + +export default function Encounter() { + const [patientAge, setPatientAge] = useState(''); + const [patientGender, setPatientGender] = useState(''); + const [setting, setSetting] = useState('outpatient'); + const [transcript, setTranscript] = useState(''); + const [result, setResult] = useState(null); + const [validationError, setValidationError] = useState(null); + + const generate = useMutation({ + mutationFn: (body) => api.post('/api/generate-hpi-encounter', body), + onSuccess: (data) => setResult(data.hpi), + }); + + function submit(e: React.FormEvent) { + e.preventDefault(); + setValidationError(null); + const body: HpiEncounterRequest = { transcript, patientAge, patientGender, setting }; + const parsed = HpiEncounterRequestSchema.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'; + + return ( +
+
+

Live Encounter → HPI

+

+ Record or paste an encounter transcript; generate a structured HPI. +

+
+ +
+
+ + + +
+ +