import { DragEvent, useRef, useState } from "react"; import { CameraIcon, DocumentIcon, SpinnerIcon } from "./icons"; import type { VisitTurn } from "./types"; const API_BASE: string = import.meta.env.VITE_API_BASE ?? ""; type CaptureState = "idle" | "reading" | "error" | "empty"; /** * Bring the Vietnamese paper into the visit. * * A foreign patient's language problem does not end with the conversation — * they leave holding a prescription they cannot read, and medication and * discharge are where harm concentrates. Every line read here becomes an * ordinary turn, so the risk engine and the clinician gate apply to paperwork * exactly as they do to speech. */ export default function DocumentCapture({ visitId, onTurns, disabled = false, }: { visitId: string; onTurns: (turns: VisitTurn[]) => void; disabled?: boolean; }) { const [state, setState] = useState("idle"); const [dragging, setDragging] = useState(false); const [lastCount, setLastCount] = useState(0); const inputRef = useRef(null); async function send(file: File | null | undefined) { if (!file || disabled) return; setState("reading"); const body = new FormData(); body.append("image", file); try { const response = await fetch(`${API_BASE}/api/v1/visits/${visitId}/documents`, { method: "POST", body, }); if (!response.ok) throw new Error(String(response.status)); const turns = (await response.json()) as VisitTurn[]; if (turns.length === 0) { setState("empty"); return; } setLastCount(turns.length); setState("idle"); onTurns(turns); } catch { // Nothing is partially added: the request either produced turns or none. setState("error"); } finally { if (inputRef.current) inputRef.current.value = ""; } } function onDrop(event: DragEvent) { event.preventDefault(); setDragging(false); void send(event.dataTransfer.files?.[0]); } const busy = state === "reading"; return (
{state === "error" ? (

Không đọc được giấy tờ. Thử lại hoặc gõ nội dung.

) : null} {state === "empty" ? (

Không đọc được chữ nào. Chụp lại rõ hơn hoặc gõ nội dung.

) : null} {state === "idle" && lastCount > 0 ? (

Đã đọc {lastCount} dòng. Bác sĩ xác nhận trước khi đưa cho bệnh nhân.

) : null}
); }