import React, { useState, useEffect, useMemo } from 'react'; import { Box, Paper, Typography, List, ListItemButton, ListItemText, Collapse, CircularProgress } from '@mui/material'; import { Outlet, useNavigate, useLocation } from 'react-router-dom'; import ExpandLess from '@mui/icons-material/ExpandLess'; import ExpandMore from '@mui/icons-material/ExpandMore'; // Definición de los módulos de reporte con sus categorías, etiquetas y rutas const allReportModules: { category: string; label: string; path: string }[] = [ { category: 'Existencia Papel', label: 'Existencia de Papel', path: 'existencia-papel' }, { category: 'Movimientos Bobinas', label: 'Movimiento de Bobinas', path: 'movimiento-bobinas' }, { category: 'Movimientos Bobinas', label: 'Mov. Bobinas por Estado', path: 'movimiento-bobinas-estado' }, { category: 'Listados Distribución', label: 'Distribución Distribuidores', path: 'listado-distribucion-distribuidores' }, { category: 'Listados Distribución', label: 'Distribución Canillas', path: 'listado-distribucion-canillas' }, { category: 'Listados Distribución', label: 'Distribución General', path: 'listado-distribucion-general' }, { category: 'Listados Distribución', label: 'Distrib. Canillas (Importe)', path: 'listado-distribucion-canillas-importe' }, { category: 'Listados Distribución', label: 'Detalle Distribución Canillas', path: 'detalle-distribucion-canillas' }, { category: 'Secretaría', label: 'Venta Mensual Secretaría', path: 'venta-mensual-secretaria' }, { category: 'Tiradas por Publicación', label: 'Tiradas Publicación/Sección', path: 'tiradas-publicaciones-secciones' }, { category: 'Consumos Bobinas', label: 'Consumo Bobinas/Sección', path: 'consumo-bobinas-seccion' }, { category: 'Consumos Bobinas', label: 'Consumo Bobinas/PubPublicación', path: 'consumo-bobinas-publicacion' }, { category: 'Consumos Bobinas', label: 'Comparativa Consumo Bobinas', path: 'comparativa-consumo-bobinas' }, { category: 'Balance de Cuentas', label: 'Cuentas Distribuidores', path: 'cuentas-distribuidores' }, { category: 'Ctrl. Devoluciones', label: 'Control de Devoluciones', path: 'control-devoluciones' }, { category: 'Novedades de Canillitas', label: 'Novedades de Canillitas', path: 'novedades-canillas' }, { category: 'Listados Distribución', label: 'Dist. Mensual Can/Acc', path: 'listado-distribucion-mensual' }, { category: 'Suscripciones', label: 'Facturas para Publicidad', path: 'suscripciones-facturas-publicidad' }, ]; const predefinedCategoryOrder = [ 'Balance de Cuentas', 'Listados Distribución', 'Ctrl. Devoluciones', 'Novedades de Canillitas', 'Suscripciones', 'Existencia Papel', 'Movimientos Bobinas', 'Consumos Bobinas', 'Tiradas por Publicación', 'Secretaría', ]; const ReportesIndexPage: React.FC = () => { const navigate = useNavigate(); const location = useLocation(); const [expandedCategory, setExpandedCategory] = useState(false); const [isLoadingInitialNavigation, setIsLoadingInitialNavigation] = useState(true); const uniqueCategories = useMemo(() => predefinedCategoryOrder, []); useEffect(() => { const currentBasePath = '/reportes'; const pathParts = location.pathname.substring(currentBasePath.length + 1).split('/'); const subPathSegment = pathParts[0]; let activeReportFoundInEffect = false; if (subPathSegment && subPathSegment !== "") { // Asegurarse que subPathSegment no esté vacío const activeReport = allReportModules.find(module => module.path === subPathSegment); if (activeReport) { setExpandedCategory(activeReport.category); activeReportFoundInEffect = true; } else { setExpandedCategory(false); } } else { setExpandedCategory(false); } if (location.pathname === currentBasePath && allReportModules.length > 0 && isLoadingInitialNavigation) { let firstReportToNavigate: { category: string; label: string; path: string } | null = null; for (const category of uniqueCategories) { const reportsInCat = allReportModules.filter(r => r.category === category); if (reportsInCat.length > 0) { firstReportToNavigate = reportsInCat[0]; break; } } if (firstReportToNavigate) { navigate(firstReportToNavigate.path, { replace: true }); activeReportFoundInEffect = true; } } // Solo se establece a false si no estamos en el proceso de navegación inicial O si no se encontró reporte if (!activeReportFoundInEffect || location.pathname !== currentBasePath) { setIsLoadingInitialNavigation(false); } }, [location.pathname, navigate, uniqueCategories, isLoadingInitialNavigation]); const handleCategoryClick = (categoryName: string) => { setExpandedCategory(prev => (prev === categoryName ? false : categoryName)); }; const handleReportClick = (reportPath: string) => { navigate(reportPath); }; const isReportActive = (reportPath: string) => { return location.pathname === `/reportes/${reportPath}` || location.pathname.startsWith(`/reportes/${reportPath}/`); }; // Si isLoadingInitialNavigation es true Y estamos en /reportes, mostrar loader // Esto evita mostrar el loader si se navega directamente a un sub-reporte. if (isLoadingInitialNavigation && (location.pathname === '/reportes' || location.pathname === '/reportes/')) { return ( ); } return ( // Contenedor principal que se adaptará a su padre // Eliminamos 'height: calc(100vh - 64px)' y cualquier margen/padding que controle el espacio exterior {/* Panel Lateral para Navegación */} `1px solid ${theme.palette.divider}`, overflowY: 'auto', bgcolor: 'background.paper', // O el color que desees para el menú // display: 'flex', flexDirection: 'column' // Para que el título y la lista usen el espacio vertical }} > {/* Título del Menú Lateral */} `1px solid ${theme.palette.divider}`, // Opcional: separador // position: 'sticky', // Si quieres que el título quede fijo al hacer scroll en la lista // top: 0, // zIndex: 1, // bgcolor: 'background.paper' // Necesario si es sticky y tiene scroll la lista }} > Reportes {/* Lista de Categorías y Reportes */} {uniqueCategories.length > 0 ? ( {uniqueCategories.map((category) => { const reportsInCategory = allReportModules.filter(r => r.category === category); const isExpanded = expandedCategory === category; return ( handleCategoryClick(category)} sx={{ // py: 1.2, // Ajustar padding vertical de items de categoría // backgroundColor: isExpanded ? 'action.selected' : 'transparent', borderLeft: isExpanded ? (theme) => `4px solid ${theme.palette.primary.main}` : '4px solid transparent', pr: 1, // Menos padding a la derecha para dar espacio al ícono expander '&:hover': { backgroundColor: 'action.hover' } }} > {reportsInCategory.length > 0 && (isExpanded ? : )} {reportsInCategory.length > 0 && ( {reportsInCategory.map((report) => ( handleReportClick(report.path)} sx={{ pl: 3.5, // Indentación para los reportes (ajustar si se cambió el padding del título) py: 0.8, // Padding vertical de items de reporte ...(isReportActive(report.path) && { backgroundColor: (theme) => theme.palette.action.selected, // Un color de fondo sutil borderLeft: (theme) => `4px solid ${theme.palette.primary.light}`, // Un borde para el activo '& .MuiListItemText-primary': { fontWeight: 'medium', // O 'bold' // color: 'primary.main' }, }), '&:hover': { backgroundColor: (theme) => theme.palette.action.hover } }} > ))} )} {reportsInCategory.length === 0 && isExpanded && ( )} ); })} ) : ( No hay categorías configuradas. )} {/* Área Principal para el Contenido del Reporte */} {/* El Outlet renderiza el componente del reporte específico */} {(!location.pathname.startsWith('/reportes/') || !allReportModules.some(r => isReportActive(r.path))) && location.pathname !== '/reportes/' && location.pathname !== '/reportes' && !isLoadingInitialNavigation && ( El reporte solicitado no existe o la ruta no es válida. )} {(location.pathname === '/reportes/' || location.pathname === '/reportes') && !allReportModules.some(r => isReportActive(r.path)) && !isLoadingInitialNavigation && ( {allReportModules.length > 0 ? "Seleccione una categoría y un reporte del menú lateral." : "No hay reportes configurados."} )} ); }; export default ReportesIndexPage;