'use client' import { useState, useEffect } from 'react' import { useRouter } from 'next/navigation' import { FileUpload } from '@/components/incidents/file-upload' import type { IncidentType, MedicalStatus } from '@/lib/incidents/validate' import { useTranslations } from '@/lib/i18n/context' interface Props { zoneToken: string | null zoneName: string | null siteName: string | null } export function ReportForm({ zoneToken }: Props) { const router = useRouter() const t = useTranslations('ReportForm') const itLabels = useTranslations('IncidentType') const msLabels = useTranslations('MedicalStatus') const INCIDENT_TYPE_OPTIONS: [IncidentType, string][] = [ ['injury', itLabels.injury], ['near_miss', itLabels.near_miss], ['hazard', itLabels.hazard], ['asset_damage', itLabels.asset_damage], ['environmental', itLabels.environmental], ['security', itLabels.security], ['fire', itLabels.fire], ] const MEDICAL_STATUS_OPTIONS: [MedicalStatus, string][] = [ ['none', msLabels.none], ['first_aid', msLabels.first_aid], ['medical_treatment', msLabels.medical_treatment], ['lti', msLabels.lti], ] const [submitting, setSubmitting] = useState(false) const [error, setError] = useState(null) const [files, setFiles] = useState([]) const [isOnline, setIsOnline] = useState(true) const [savedOffline, setSavedOffline] = useState(false) const [qualityCheck, setQualityCheck] = useState<{ score: number passes: boolean feedback: string suggestions: string[] } | null>(null) const [overrideQuality, setOverrideQuality] = useState(false) const [form, setForm] = useState({ incident_type: '' as IncidentType | '', description: '', injury_involved: false, medical_status: '' as MedicalStatus | '', asset_involved: false, }) useEffect(() => { // eslint-disable-next-line react-hooks/set-state-in-effect setIsOnline(navigator.onLine) const onOnline = () => setIsOnline(true) const onOffline = () => setIsOnline(false) window.addEventListener('online', onOnline) window.addEventListener('offline', onOffline) return () => { window.removeEventListener('online', onOnline) window.removeEventListener('offline', onOffline) } }, []) async function handleSubmit(e: React.FormEvent) { e.preventDefault() setError(null) setSubmitting(true) // Offline path — save to IndexedDB if (!isOnline) { try { const { addPendingReport } = await import('@/lib/offline/db') await addPendingReport({ zone_token: zoneToken ?? '', incident_type: form.incident_type as IncidentType, description: form.description, injury_involved: form.injury_involved, asset_involved: form.asset_involved, medical_status: form.medical_status || undefined, created_at: new Date().toISOString(), }) setSavedOffline(true) } catch (err) { console.error('Offline save error:', err) setError(t.errorGeneric) } setSubmitting(false) return } if (!overrideQuality) { try { const qcRes = await fetch('/api/incidents/ai/quality-check', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ description: form.description, incident_type: form.incident_type, }), }) if (qcRes.ok) { const qc = await qcRes.json() as { score: number passes: boolean feedback: string suggestions: string[] } setQualityCheck(qc) if (!qc.passes) { setSubmitting(false) return } } } catch { // Quality check failure is non-blocking } } try { const fd = new FormData() if (zoneToken) fd.append('zone_token', zoneToken) fd.append('incident_type', form.incident_type) fd.append('description', form.description) fd.append('injury_involved', String(form.injury_involved)) fd.append('asset_involved', String(form.asset_involved)) if (form.injury_involved && form.medical_status) { fd.append('medical_status', form.medical_status) } files.forEach(f => fd.append('files', f)) const res = await fetch('/api/incidents', { method: 'POST', body: fd }) const data = await res.json() if (!res.ok) { setError(data.details ? data.details.join('. ') : data.error) return } router.push(`/report/success?ref=${data.reference_no}`) } catch { setError(t.errorGeneric) } finally { setSubmitting(false) } } if (savedOffline) { return (
{t.savedOffline}
) } return (
{!isOnline && (
{t.offlineBanner}
)} {error && (
{error}
)}