import { useEffect, useState } from 'react'; import { Alert, EmptyState, LoadingBlock, errorMessage } from '../../components/Feedback'; import { getAssetMediaBlob, getInspectionFindingEvidenceBlob, listInspectionActFieldMedia, listInspectionFindingEvidence, listInspectionFindings, } from '../../lib/api'; import type { InspectionActFieldMedia, InspectionFinding, InspectionFindingEvidence } from '../../lib/api'; import { formatDate } from '../../lib/format'; type FindingWithPhotos = { finding: InspectionFinding; photos: InspectionFindingEvidence[] }; function Photo({ id, title, caption, load }: { id: string; title: string; caption: string; load: (id: string) => Promise }) { const [url, setUrl] = useState(''); useEffect(() => { let active = true; let objectUrl = ''; load(id).then((blob) => { if (!active) return; objectUrl = URL.createObjectURL(blob); setUrl(objectUrl); }).catch(() => undefined); return () => { active = false; if (objectUrl) URL.revokeObjectURL(objectUrl); }; }, [id, load]); return
{url ? {title} : Cargando foto…}
{caption}
; } function Finding({ item, assetPhotos }: { item: FindingWithPhotos; assetPhotos: InspectionActFieldMedia[] }) { const { finding, photos } = item; return
{finding.code}

{finding.title}

{finding.asset.name} · {finding.asset.code}

{finding.description}

{finding.legalBasis &&

Normativa: {finding.legalBasis}

} {finding.severity != null &&

Gravedad {finding.severity}/10

} {(photos.length > 0 || assetPhotos.length > 0) &&
{photos.map((photo) => )} {assetPhotos.map((photo) => )}
} {photos.length === 0 && assetPhotos.length === 0 && Sin fotografías vinculadas.}
; } export function InspectionActMediaPanel({ actId }: { actId: string }) { const [items, setItems] = useState([]); const [assetPhotos, setAssetPhotos] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); useEffect(() => { let active = true; setLoading(true); setError(''); Promise.all([listInspectionFindings(actId), listInspectionActFieldMedia(actId).catch(() => [])]) .then(async ([findings, media]) => { const records = await Promise.all(findings.map(async (finding) => ({ finding, photos: (await listInspectionFindingEvidence(finding.id)).filter((evidence) => evidence.kind === 'PHOTO' && evidence.purpose === 'OBSERVATION'), }))); if (!active) return; setItems(records); setAssetPhotos(media.filter((photo) => photo.kind === 'PHOTO')); }) .catch((requestError) => active && setError(errorMessage(requestError))) .finally(() => active && setLoading(false)); return () => { active = false; }; }, [actId]); const findingAssetIds = new Set(items.map((item) => item.finding.asset.id)); const otherPhotos = assetPhotos.filter((photo) => !findingAssetIds.has(photo.assetId)); return

Hallazgos del Acta

Cada hallazgo reúne su descripción y las fotos tomadas en campo.

{items.length}
{error && {error}} {loading ? : items.length ?
{items.map((item) => photo.assetId === item.finding.asset.id)} />)}
: } {!loading && otherPhotos.length > 0 &&

Fotos de otras instalaciones

{otherPhotos.map((photo) => )}
}
; }