Files
dh-inspeccion-v2/web-v2/src/pages/InspectionActEditorPage.tsx
T

82 lines
6.2 KiB
TypeScript

import { useEffect, useState } from 'react';
import { Link, useParams } from 'react-router';
import { Alert, LoadingBlock, errorMessage } from '../components/Feedback';
import { Icon } from '../components/Icon';
import {
inspectionActStatusClass,
inspectionActStatusLabel,
inspectionActVersionEventLabel,
} from '../features/inspections/inspectionActPresentation';
import { InspectionClosurePanel } from '../features/inspections/InspectionClosurePanel';
import { InspectionFindingsPanel } from '../features/inspections/InspectionFindingsPanel';
import { getInspectionVisit } from '../lib/api';
import type { InspectionVisit } from '../lib/api';
import { getInspectionActF4, type InspectionActF4 } from '../lib/inspectionActF4Api';
import { formatDate } from '../lib/format';
export function InspectionActEditorPage() {
const { actId } = useParams();
const [visit, setVisit] = useState<InspectionVisit | null>(null);
const [act, setAct] = useState<InspectionActF4 | null>(null);
const [loading, setLoading] = useState(Boolean(actId));
const [error, setError] = useState('');
useEffect(() => {
if (!actId) return;
setLoading(true);
setError('');
getInspectionActF4(actId)
.then(async (value) => {
setAct(value);
setVisit(await getInspectionVisit(value.visitId));
})
.catch((requestError) => setError(errorMessage(requestError)))
.finally(() => setLoading(false));
}, [actId]);
if (!actId) {
return <section className="survey-editor inspection-act-editor">
<div className="breadcrumb"><Link to="/inspecciones">Inspecciones</Link><span>/</span><span>Acta</span></div>
<div className="page-heading"><div><span className="eyebrow">OPERACIÓN EXCLUSIVA EN APK</span><h1>Crear acta de inspección</h1><p>Las actas sólo pueden generarse durante la inspección física desde la aplicación móvil.</p></div></div>
<div className="temporal-notice"><Icon name="clipboard" /><p><strong>Usá la APK con un usuario inspector.</strong> El dashboard recibirá el Acta, sus Hallazgos y constancias cuando la aplicación sincronice.</p></div>
<Link className="button secondary" to="/inspecciones">Volver a inspecciones</Link>
</section>;
}
if (loading) return <LoadingBlock label="Cargando acta…" />;
const isSealed = act?.status === 'SEALED' || act?.status === 'CLOSED';
return <section className="survey-editor inspection-act-editor">
<div className="breadcrumb"><Link to="/inspecciones">Inspecciones</Link><span>/</span>{visit && <><Link to={`/inspecciones/${visit.id}`}>{visit.code}</Link><span>/</span></>}<span>{act?.code ?? 'Acta'}</span></div>
<div className="page-heading survey-editor-heading"><div><span className="eyebrow">ACTA DE INSPECCIÓN · SÓLO LECTURA</span><h1>{act?.title ?? 'Acta'}</h1><p>{act ? `${act.code} · versión ${act.currentVersion}` : 'Consulta del documento sincronizado desde la APK.'}</p></div>{act && <span className={`status-badge large ${inspectionActStatusClass(act.status)}`}>{inspectionActStatusLabel(act.status)}</span>}</div>
{error && <Alert>{error}</Alert>}
{visit && <div className="temporal-notice"><Icon name="clipboard" /><p><strong>{visit.code}</strong> El contenido constatado y los Hallazgos se registran desde la APK. Una vez bloqueada, el Acta ya no vuelve a borrador; la manifestación de empresa puede completarse posteriormente por enlace seguro.</p></div>}
{act?.report && <div className="temporal-notice"><Icon name="clipboard" /><p><strong>Informe relacionado: <Link to={`/informes/${act.report.id}`}>{act.report.code}</Link>.</strong> {act.report.pdfStatus === 'READY' ? 'El documento PDF está disponible.' : 'El contenido está congelado y el PDF continúa pendiente de composición.'}</p></div>}
{isSealed && act && !act.report && <div className="temporal-notice"><Icon name="clipboard" /><p><strong>Informe pendiente de emisión.</strong> El Acta ya está sellada y habilita el circuito documental del INF.</p></div>}
{act?.status === 'CANCELLED' && <Alert>Cancelada: {act.cancellationReason}</Alert>}
{act && <section className="panel inspection-act-form">
<div className="panel-heading"><div><span className="eyebrow">CONTENIDO SINCRONIZADO</span><h2>{act.code}</h2></div><small className="muted">Actualizado {formatDate(act.updatedAt)}</small></div>
<div className="responsible-summary">
<div><small>Fecha y hora</small><strong>{formatDate(act.occurredAt)}</strong></div>
<div><small>Título</small><strong>{act.title}</strong></div>
<div><small>Urgencia</small><strong>{act.urgency === 'URGENT' ? 'Urgente' : 'No urgente'}</strong></div>
<div><small>Hallazgos</small><strong>{act.findingCount}</strong></div>
</div>
<div className="closure-section"><span className="eyebrow">DESCRIPCIÓN DE LO ACTUADO</span><p>{act.summary}</p>{act.observations && <><span className="eyebrow">OBSERVACIONES</span><p>{act.observations}</p></>}</div>
<div className="inspection-act-assets"><div><span className="eyebrow">INVENTARIO DEL ACTA</span><h3>Referencias congeladas</h3></div><span className="count-pill">{act.assets.length}</span></div>
<div className="inspection-act-asset-grid">{act.assets.map((asset) => <div className="inspection-member selected" key={asset.id}><span><strong>{asset.name}</strong><small>{asset.code} · {asset.typeName}</small></span></div>)}</div>
</section>}
{act && <InspectionFindingsPanel act={act} />}
{act && <InspectionClosurePanel act={act} />}
{act && <section className="panel survey-report-history">
<div className="panel-heading"><div><span className="eyebrow">VERSIONES INMUTABLES</span><h2>Historial exacto del acta</h2><p className="section-copy">Cada transición conserva el contenido y las versiones de los registros referenciados.</p></div><span className="count-pill">{act.versions.length}</span></div>
<div className="survey-version-list">{act.versions.map((version) => <details key={version.id}><summary><span className="count-pill">v{version.versionNumber}</span><strong>{inspectionActVersionEventLabel(version.event)}</strong><small>{formatDate(version.createdAt)} · {version.actorUsername ?? 'sistema'}</small></summary><pre>{JSON.stringify(version.snapshot, null, 2)}</pre></details>)}</div>
</section>}
</section>;
}