import { useRef, useState } from 'react' import { useZino } from '../api/provider.jsx' /** * A file or OCR field. * * Uploads ON PICK rather than on submit: the backend's extract endpoint takes * a REFERENCE to a stored file, so the document crosses the wire once, survives * a reload, and re-extracting costs no second upload. * * For an `ocr` field it then calls /ocr-extract, which resolves the field's own * extraction config server-side and returns the values keyed by extraction key. * Those are handed up so the form can fill the fields the document answers — * which is the entire point: nobody should be typing an engine capacity that is * printed on the RC. */ export default function FileField({ field, value, instanceId, activityUid, onChange, onExtract }) { const { client } = useZino() const inputRef = useRef(null) const [busy, setBusy] = useState('') const [err, setErr] = useState(null) const [extracted, setExtracted] = useState(null) const isOcr = field.data_type === 'ocr' const files = Array.isArray(value) ? value : [] async function pick(e) { const file = e.target.files?.[0] if (!file) return setErr(null); setExtracted(null) const ctx = { activityId: activityUid, fieldId: field.id, instanceId } try { setBusy('Uploading…') const ref = await client.uploadFile(file, ctx) onChange([ref]) if (isOcr) { setBusy('Reading the document…') // Extraction failing must NOT lose the upload. The file is already // stored and referenced; a failed read just means the fields are not // pre-filled, which is recoverable by typing. Swallowing the upload // because the OCR errored would not be. try { const out = await client.ocrExtract(ref, ctx) // The endpoint answers { extracted: {...}, raw: "..." }. const fields = out?.extracted ?? out?.fields ?? out?.data ?? null if (fields && typeof fields === 'object' && Object.keys(fields).length) { setExtracted(fields) onExtract?.(fields) } else { setErr({ status: '', message: 'Uploaded, but nothing could be read from this document.' }) } } catch (ox) { setErr({ status: ox.status ?? '', message: 'Uploaded, but reading it failed — ' + (ox.message || 'unknown error') }) } } } catch (ex) { setErr(ex) } finally { setBusy('') } } return (
{files.length ? (
{files[0].original_name || files[0].uuid}
) : null} {extracted ? (
Read from the document {Object.entries(extracted) .filter(([, v]) => v !== null && v !== undefined && String(v) !== '') .map(([k, v]) => (
{k.replace(/_/g, ' ')} {String(v)}
))}
) : null} {err ?
{err.status} {err.message}
: null}
) }