diff --git a/web-v2/src/pages/InspectionVisitEditorF4Page.tsx b/web-v2/src/pages/InspectionVisitEditorF4Page.tsx index 499dc51..78ba97e 100644 --- a/web-v2/src/pages/InspectionVisitEditorF4Page.tsx +++ b/web-v2/src/pages/InspectionVisitEditorF4Page.tsx @@ -11,13 +11,18 @@ import { inspectionStatusClass, inspectionVisitStatusLabel, } from '../features/inspections/inspectionPresentation'; +import { + listInspectionPreventiveCandidates, +} from '../features/inspections/preventiveCandidatesApi'; +import type { + InspectionPreventiveCandidate, +} from '../features/inspections/preventiveCandidatesApi'; import { createInspectionVisit, excludeInspectionVisitAsset, generateInspectionVisitChecklist, getInspectionVisit, includeInspectionVisitAsset, - listAssets, listInspectionAssignees, listInspectionPlanningAreas, listInspectionPlanningOperators, @@ -26,7 +31,6 @@ import { updateInspectionVisit, } from '../lib/api'; import type { - AssetListItem, InspectionPerson, InspectionPlanningContextAsset, InspectionVisit, @@ -100,7 +104,7 @@ export function InspectionVisitEditorF4Page() { const [areas, setAreas] = useState([]); const [operators, setOperators] = useState([]); const [assignees, setAssignees] = useState([]); - const [assets, setAssets] = useState([]); + const [assets, setAssets] = useState([]); const [assetSearch, setAssetSearch] = useState(''); const [newAssetId, setNewAssetId] = useState(''); const [leadInspectorId, setLeadInspectorId] = useState(''); @@ -136,9 +140,9 @@ export function InspectionVisitEditorF4Page() { }; useEffect(() => { - listInspectionPlanningAreas().then(setAreas).catch(() => undefined); + if (isNew) listInspectionPlanningAreas().then(setAreas).catch(() => undefined); if (canAssign) listInspectionAssignees().then(setAssignees).catch(() => undefined); - }, [canAssign]); + }, [canAssign, isNew]); useEffect(() => { if (!isNew || form.operationalAreaId || !context.areaId) return; @@ -158,29 +162,27 @@ export function InspectionVisitEditorF4Page() { }, [id]); useEffect(() => { - if (!form.operationalAreaId) { + if (!isNew || !form.operationalAreaId) { setOperators([]); return; } listInspectionPlanningOperators(form.operationalAreaId) .then(setOperators) .catch(() => setOperators([])); - }, [form.operationalAreaId]); + }, [form.operationalAreaId, isNew]); useEffect(() => { - if (!form.operationalAreaId || !form.operatorCompanyId) { + if (!id || !visit) { setAssets([]); return; } const timer = window.setTimeout(() => { - listAssets({ - pageSize: 100, - search: assetSearch.trim(), - operationalAreaId: form.operationalAreaId, - }).then((response) => setAssets(response.data)).catch(() => undefined); + listInspectionPreventiveCandidates(id, assetSearch) + .then(setAssets) + .catch((requestError) => setError(errorMessage(requestError))); }, 220); return () => window.clearTimeout(timer); - }, [assetSearch, form.operationalAreaId, form.operatorCompanyId]); + }, [id, assetSearch, visit?.updatedAt]); const planningEditable = !visit || visit.status === 'DRAFT' || visit.status === 'PLANNED'; const activeAssetIds = useMemo(() => new Set(visit?.assets.map((asset) => asset.id) ?? []), [visit]); @@ -209,13 +211,10 @@ export function InspectionVisitEditorF4Page() { } else if (id) { applyVisit(await updateInspectionVisit(id, { objective: form.objective.trim() || null, - scopeAssetId: visit?.scopeAsset?.id ?? null, - operationalAreaId: form.operationalAreaId || null, - operatorCompanyId: form.operatorCompanyId || null, plannedStartAt, instructions: form.instructions.trim() || null, })); - setSuccess('Planificación actualizada. Regenerá el checklist si cambió contexto o fecha.'); + setSuccess('Planificación actualizada. Si cambió la fecha, regenerá el checklist.'); } } catch (requestError) { setError(errorMessage(requestError)); @@ -240,6 +239,7 @@ export function InspectionVisitEditorF4Page() { setBusy(true); setError(''); setSuccess(''); try { applyVisit(await replaceInspectionVisitAssets(id, [...activeAssetIds, newAssetId]), false); + setAssets((current) => current.filter((asset) => asset.id !== newAssetId)); setNewAssetId(''); setSuccess('Registro agregado como preventivo.'); } catch (requestError) { setError(errorMessage(requestError)); } @@ -340,12 +340,12 @@ export function InspectionVisitEditorF4Page() { {error && {error}}{success && {success}}
-
{isNew ? 'CREACIÓN RÁPIDA' : 'PLANIFICACIÓN'}

Contexto y fecha de inicio

No existe título independiente ni fecha de fin planificada. El cierre real se registra al terminar el trabajo de campo.

{visit && Actualizado {formatDate(visit.updatedAt)}}
+
{isNew ? 'CREACIÓN RÁPIDA' : 'PLANIFICACIÓN'}

Contexto y fecha de inicio

El Área, Yacimiento y Operadora quedan fijados al crear la Inspección. La fecha puede reprogramarse antes del trabajo de campo.

{visit && Actualizado {formatDate(visit.updatedAt)}}
{visit &&
Identificador institucional{visit.code}
}
- - {!isNew && } - + {isNew ? : } + {!isNew && } + {isNew ? : } {isNew && }
@@ -354,15 +354,15 @@ export function InspectionVisitEditorF4Page() {
{visit &&
-
CHECKLIST TÉCNICO

Antecedentes y controles

Se construye por Área, Operadora y fecha. Las respuestas administrativas de empresa no modifican este checklist.

{canManage && planningEditable && }
- {visit.checklist.stale && El contexto o la fecha cambió. Regenerá el checklist antes de planificar.} +
CHECKLIST TÉCNICO

Antecedentes y controles

Se construye para el Área, Yacimiento y Operadora fijados en la Inspección, tomando la fecha planificada. Las respuestas administrativas de empresa no modifican este checklist.

{canManage && planningEditable && }
+ {visit.checklist.stale && La fecha cambió. Regenerá el checklist antes de planificar.}
{visit.checklist.verificationOverdue}controles vencidos
{visit.checklist.upcomingControls}próximos 30 días
{visit.checklist.antecedents}antecedentes
{visit.checklist.actionableAssets}registros sugeridos
{visit.checklist.items.length === 0 ? :
{visit.checklist.items.map((item) => )}
TipoHallazgoInventarioFechaGravedad
{checklistLabel(item.itemKind)}{item.findingTitle}{item.findingCode}{item.asset.name}{item.asset.code} · {item.asset.typeName}{formatDateOnly(item.referenceOn)}{item.severity ?? '—'}
}
} {visit && visit.verificationFindings.length > 0 &&
VERIFICACIÓN

Hallazgos a controlar

{visit.verificationFindings.length}
{visit.verificationFindings.map((finding) =>
{finding.title}{finding.code} · {finding.assetName} · objetivo {formatDateOnly(finding.targetControlOn ?? finding.nextControlOn)}{finding.resultNotes && {finding.resultNotes}}
{finding.outcome === 'RESOLVED' ? 'Solucionado' : finding.outcome === 'NOT_RESOLVED' ? 'No solucionado' : finding.outcome === 'REQUIRES_NEW_DATE' ? 'Reprogramar' : 'Pendiente'})}
} - {visit && planningEditable && canManage &&
PREVENTIVO

Agregar Inventario sin pendiente previo

} + {visit && planningEditable && canManage &&
PREVENTIVO

Agregar Inventario sin pendiente previo

Sólo se muestran Instalaciones y Subinstalaciones pertenecientes al Yacimiento fijado para esta Inspección.

} {visit &&
{visit.assets.length} incluidos{visit.checklist.excludedAssets} excluidos con trazabilidad
{visit.planningAssets.length === 0 ? :
{visit.planningAssets.map((asset) => )}
InventarioOrigenEstadoMotivo
{asset.name}{asset.code} · {asset.typeName}{sourceLabel(asset.planningSource)}{asset.included ? 'Incluido' : 'Excluido'}{asset.exclusionReason ?? '—'}{canManage && planningEditable && (asset.included ? : )}
}
}