From 37795e65862b989931e7ee1143cb05a90f1c4691 Mon Sep 17 00:00:00 2001 From: enlineawork Date: Sat, 5 Sep 2026 17:24:42 -0300 Subject: [PATCH] =?UTF-8?q?F1.4:=20integrar=20pendientes=20en=20la=20plani?= =?UTF-8?q?ficaci=C3=B3n=20de=20inspecci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inspections/FieldBriefingPanel.tsx | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 web-v2/src/features/inspections/FieldBriefingPanel.tsx diff --git a/web-v2/src/features/inspections/FieldBriefingPanel.tsx b/web-v2/src/features/inspections/FieldBriefingPanel.tsx new file mode 100644 index 0000000..5839bbb --- /dev/null +++ b/web-v2/src/features/inspections/FieldBriefingPanel.tsx @@ -0,0 +1,97 @@ +import { useEffect, useState } from 'react'; +import { Link } from 'react-router'; +import { Alert, EmptyState, LoadingBlock, errorMessage } from '../../components/Feedback'; +import { Icon } from '../../components/Icon'; +import type { InspectionVisit } from '../../lib/api'; +import { formatDate, formatDateOnly } from '../../lib/format'; +import { + getInspectionFieldBriefing, + type FieldBriefing, + type FieldBriefingActState, +} from './fieldBriefingApi'; + +function stateLabel(state: FieldBriefingActState): string { + if (state === 'ACT_RESPONSE_OVERDUE') return 'Respuesta del Acta vencida'; + if (state === 'ACT_RESPONSE_DUE_SOON') return 'Respuesta próxima a vencer'; + if (state === 'COMPANY_COMMITMENT_OVERDUE') return 'Compromiso de empresa vencido'; + if (state === 'VERIFICATION_PENDING') return 'Verificación pendiente'; + if (state === 'RESPONSE_RECEIVED') return 'Respuesta recibida'; + return 'Esperando respuesta'; +} + +function stateClass(state: FieldBriefingActState): string { + if (state === 'ACT_RESPONSE_OVERDUE' || state === 'COMPANY_COMMITMENT_OVERDUE') return 'danger'; + if (state === 'ACT_RESPONSE_DUE_SOON' || state === 'VERIFICATION_PENDING') return 'warning'; + return 'pending'; +} + +export function FieldBriefingPanel({ visit }: { visit: InspectionVisit }) { + const [briefing, setBriefing] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(''); + + useEffect(() => { + let active = true; + setLoading(true); + setError(''); + getInspectionFieldBriefing(visit.id) + .then((value) => { if (active) setBriefing(value); }) + .catch((requestError) => { if (active) setError(errorMessage(requestError)); }) + .finally(() => { if (active) setLoading(false); }); + return () => { active = false; }; + }, [visit.id, visit.updatedAt]); + + return
+
+
+ ANTES DE CONFIRMAR LA SALIDA +

Pendientes para revisar en campo

+

Actas anteriores del mismo Área y Operadora que requieren atención durante esta inspección. El plazo administrativo pertenece al Acta y los hallazgos se mantienen dentro de su expediente de origen.

+
+
+ Vista imprimible +
+
+ + {error && {error}} + {loading ? : briefing && <> +
+
{briefing.summary.acts}actas con pendientes
+
{briefing.summary.findings}hallazgos a revisar
+
{briefing.summary.inventoryItems}registros involucrados
+
{briefing.summary.responseOverdue}respuestas vencidas
+
{briefing.summary.commitmentOverdue}compromisos vencidos
+
{briefing.summary.verificationPending}verificaciones pendientes
+
+ +
+ +

Contexto de salida: {briefing.inspection.area?.name ?? 'Área sin definir'} · {briefing.inspection.operatorCompany?.name ?? 'Operadora sin definir'} · {formatDateOnly(briefing.plannedOn)}.

+
+ + {briefing.acts.length === 0 + ? + :
{briefing.acts.map((act) =>
+
+
{act.actCode}{formatDate(act.occurredAt)} · {act.findings.length} hallazgo{act.findings.length === 1 ? '' : 's'}
+ {stateLabel(act.adminState)} +
+
+ + {act.findings.map((finding) => + + + + + + )} +
HallazgoInventarioGravedadControl
{finding.title}{finding.code} · {finding.status}{finding.asset.name}{finding.asset.code} · {finding.asset.typeName}{finding.severity ?? '—'}{finding.nextControlOn ? formatDateOnly(finding.nextControlOn) : 'A definir'}Ver Acta
+
+ Plazo empresa: {act.responseDueOn ? formatDateOnly(act.responseDueOn) : 'sin definir'} + Respuesta: {act.responseReceivedOn ? formatDateOnly(act.responseReceivedOn) : 'pendiente'} + Compromiso: {act.committedCorrectionOn ? formatDateOnly(act.committedCorrectionOn) : '—'} +
+
)}
} + } +
; +}