import { useEffect, useState } from 'react'; import { Link, useSearchParams } from 'react-router'; import { useAuth } from '../../auth/AuthContext'; import { Alert, EmptyState, LoadingBlock, errorMessage } from '../../components/Feedback'; import { Icon } from '../../components/Icon'; import { getAssetLineage } from '../../lib/api'; import type { AssetLineageItem } from '../../lib/api'; import { listInventoryAreas, listInventoryChildren, } from '../../lib/inventoryBrowserApi'; import type { InventoryBrowserArea, InventoryBrowserItem, InventoryQuery, } from '../../lib/inventoryBrowserApi'; import { assetOperationalStatusLabel, assetStatusClass, assetStatusLabel } from './assetPresentation'; function navigationHref(base: URLSearchParams, parentId?: string) { const params = new URLSearchParams(base); params.delete('view'); params.delete('page'); params.delete('section'); params.delete('companyId'); parentId ? params.set('parentId', parentId) : params.delete('parentId'); return `/inventarios${params.size ? `?${params}` : ''}`; } function AreaCard({ area, href }: { area: InventoryBrowserArea; href: string }) { return {area.name} {area.code} · {area.yacimientoCount} yacimiento{area.yacimientoCount === 1 ? '' : 's'} {area.currentOperator ? ` · Operadora vigente: ${area.currentOperator.name}` : ' · Sin operadora vigente'} {area.inventoryCount} instancia{area.inventoryCount === 1 ? '' : 's'} real{area.inventoryCount === 1 ? '' : 'es'} ; } function InventoryCard({ item, href }: { item: InventoryBrowserItem; href: string }) { const structural = !item.isInventoryInstance; return {item.name} {item.code} · {item.type.name} {item.inventoryFamily ? ` · ${item.inventoryFamily.name}` : ''} {item.commonName ? ` · ${item.commonName}` : ''} {structural ? <>Contexto{item.childrenCount} nivel{item.childrenCount === 1 ? '' : 'es'} inferior{item.childrenCount === 1 ? '' : 'es'}> : <>{assetStatusLabel(item.informationStatus)}{assetOperationalStatusLabel(item.operationalStatus)}>} ; } function nextLevelLabel(typeCode: string | undefined) { switch (typeCode?.toLowerCase()) { case 'area': return 'Yacimientos'; case 'yacimiento': return 'Instalaciones'; case 'instalacion': return 'Subinstalaciones'; default: return 'Niveles inferiores'; } } export function AssetHierarchyView({ filters }: { filters: InventoryQuery }) { const { hasPermission } = useAuth(); const canCreate = hasPermission('assets.create'); const [searchParams] = useSearchParams(); const parentId = searchParams.get('parentId') ?? ''; const [areas, setAreas] = useState([]); const [children, setChildren] = useState([]); const [lineage, setLineage] = useState([]); const [hasMore, setHasMore] = useState(false); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); useEffect(() => { let active = true; setLoading(true); setError(''); setAreas([]); setChildren([]); setLineage([]); setHasMore(false); const run = async () => { if (!parentId) { const response = await listInventoryAreas({ search: filters.search, operationalAreaId: filters.operationalAreaId, operatorCompanyId: filters.operatorCompanyId, }); if (active) setAreas(response.data); return; } const [loadedLineage, response] = await Promise.all([ getAssetLineage(parentId), listInventoryChildren(parentId, { search: filters.search }), ]); if (!active) return; setLineage(loadedLineage.filter((item) => ['area','yacimiento','instalacion','subinstalacion'].includes(item.type.code.toLowerCase()))); setChildren(response.data); setHasMore(response.meta.hasMore); }; run() .catch((requestError) => active && setError(errorMessage(requestError))) .finally(() => active && setLoading(false)); return () => { active = false; }; }, [parentId, filters.search, filters.operationalAreaId, filters.operatorCompanyId]); if (loading) return ; if (!parentId) { const realTotal = areas.reduce((sum, area) => sum + Number(area.inventoryCount ?? 0), 0); return {error && {error}} ESTRUCTURA TERRITORIAL Áreas Las Áreas y Yacimientos son contexto de navegación. El Inventario real comienza en las Instalaciones/Subinstalaciones efectivamente registradas. {realTotal} Inventario real {areas.length} Áreas {areas.length === 0 ? : {areas.map((area) => )}} 1ÁreaAncla territorial› 2YacimientoContexto dentro del Área› 3InstalaciónInventario real› 4SubinstalaciónInventario real ; } const current = lineage.at(-1) ?? null; const breadcrumb = Inventarios {lineage.map((item,index) => { const isLast=index===lineage.length-1; return › {isLast ? {item.name} : {item.name}} ; })} ; return {breadcrumb} {error && {error}} {hasMore && Este nivel tiene más de 200 registros. Usá la búsqueda para acotar el resultado.} {current?.type.name ?? 'INVENTARIO'} {current?.name ?? 'Nivel de Inventario'} {current?.code ?? ''} {current && Ver ficha} {canCreate && current?.type.code.toLowerCase() !== 'subinstalacion' && Agregar aquí} {nextLevelLabel(current?.type.code)}La jerarquía permitida es Área → Yacimiento → Instalación → Subinstalación. {children.length} {children.length === 0 ? : {children.map((item) => )}} ; }
Las Áreas y Yacimientos son contexto de navegación. El Inventario real comienza en las Instalaciones/Subinstalaciones efectivamente registradas.
{current?.code ?? ''}
La jerarquía permitida es Área → Yacimiento → Instalación → Subinstalación.