Fase 3:
- Backend API: Autenticación y autorización básicas con JWT implementadas. Cambio de contraseña funcional. Módulo "Tipos de Pago" (CRUD completo) implementado en el backend (Controlador, Servicio, Repositorio) usando Dapper, transacciones y con lógica de historial. Se incluyen permisos en el token JWT. - Frontend React: Estructura base con Vite, TypeScript, MUI. Contexto de autenticación (AuthContext) que maneja el estado del usuario y el token. Página de Login. Modal de Cambio de Contraseña (forzado y opcional). Hook usePermissions para verificar permisos. Página GestionarTiposPagoPage con tabla, paginación, filtro, modal para crear/editar, y menú de acciones, respetando permisos. Layout principal (MainLayout) con navegación por Tabs (funcionalidad básica de navegación). Estructura de enrutamiento (AppRoutes) que maneja rutas públicas, protegidas y anidadas para módulos.
This commit is contained in:
88
Frontend/src/pages/Distribucion/DistribucionIndexPage.tsx
Normal file
88
Frontend/src/pages/Distribucion/DistribucionIndexPage.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
// src/pages/distribucion/DistribucionIndexPage.tsx
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Box, Tabs, Tab, Paper, Typography } from '@mui/material';
|
||||
import { Outlet, useNavigate, useLocation, Link as RouterLink } from 'react-router-dom';
|
||||
|
||||
// Define las sub-pestañas del módulo Distribución
|
||||
// El path es relativo a la ruta base del módulo (ej: /distribucion)
|
||||
const distribucionSubModules = [
|
||||
{ label: 'E/S Canillas', path: 'es-canillas' }, // Se convertirá en /distribucion/es-canillas
|
||||
{ label: 'Ctrl. Devoluciones', path: 'control-devoluciones' },
|
||||
{ label: 'E/S Distribuidores', path: 'es-distribuidores' },
|
||||
{ label: 'Salidas Otros Dest.', path: 'salidas-otros-destinos' },
|
||||
{ label: 'Canillas', path: 'canillas' },
|
||||
{ label: 'Distribuidores', path: 'distribuidores' },
|
||||
{ label: 'Publicaciones', path: 'publicaciones' },
|
||||
{ label: 'Otros Destinos', path: 'otros-destinos' },
|
||||
{ label: 'Zonas', path: 'zonas' },
|
||||
{ label: 'Empresas', path: 'empresas' },
|
||||
];
|
||||
|
||||
const DistribucionIndexPage: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const [selectedSubTab, setSelectedSubTab] = useState<number | false>(false);
|
||||
|
||||
// Sincronizar el sub-tab con la URL actual
|
||||
useEffect(() => {
|
||||
// location.pathname será algo como /distribucion/canillas
|
||||
// Necesitamos extraer la última parte para compararla con los paths de subSubModules
|
||||
const currentBasePath = '/distribucion'; // Ruta base de este módulo
|
||||
const subPath = location.pathname.startsWith(currentBasePath + '/')
|
||||
? location.pathname.substring(currentBasePath.length + 1)
|
||||
: (location.pathname === currentBasePath ? distribucionSubModules[0]?.path : undefined); // Si es /distribucion, selecciona el primero
|
||||
|
||||
const activeTabIndex = distribucionSubModules.findIndex(
|
||||
(subModule) => subModule.path === subPath
|
||||
);
|
||||
|
||||
if (activeTabIndex !== -1) {
|
||||
setSelectedSubTab(activeTabIndex);
|
||||
} else {
|
||||
// Si no coincide ninguna sub-ruta, pero estamos en /distribucion, ir al primer tab
|
||||
if (location.pathname === currentBasePath && distribucionSubModules.length > 0) {
|
||||
navigate(distribucionSubModules[0].path, { replace: true }); // Navegar a la primera sub-ruta
|
||||
setSelectedSubTab(0);
|
||||
} else {
|
||||
setSelectedSubTab(false); // Ningún sub-tab activo
|
||||
}
|
||||
}
|
||||
}, [location.pathname, navigate]);
|
||||
|
||||
const handleSubTabChange = (_event: React.SyntheticEvent, newValue: number) => {
|
||||
setSelectedSubTab(newValue);
|
||||
navigate(distribucionSubModules[newValue].path); // Navega a la sub-ruta (ej: 'canillas')
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h5" gutterBottom>Módulo de Distribución</Typography>
|
||||
<Paper square elevation={1}>
|
||||
<Tabs
|
||||
value={selectedSubTab}
|
||||
onChange={handleSubTabChange}
|
||||
indicatorColor="primary"
|
||||
textColor="primary"
|
||||
variant="scrollable"
|
||||
scrollButtons="auto"
|
||||
aria-label="sub-módulos de distribución"
|
||||
>
|
||||
{distribucionSubModules.map((subModule) => (
|
||||
// Usar RouterLink para que el tab se comporte como un enlace y actualice la URL
|
||||
// La navegación real la manejamos con navigate en handleSubTabChange
|
||||
// para poder actualizar el estado del tab seleccionado.
|
||||
// Podríamos usar `component={RouterLink} to={subModule.path}` también,
|
||||
// pero manejarlo con navigate da más control sobre el estado.
|
||||
<Tab key={subModule.path} label={subModule.label} />
|
||||
))}
|
||||
</Tabs>
|
||||
</Paper>
|
||||
<Box sx={{ pt: 2 }}> {/* Padding para el contenido de la sub-pestaña */}
|
||||
{/* Outlet renderizará el componente de la sub-ruta activa (ej: CanillasPage) */}
|
||||
<Outlet />
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default DistribucionIndexPage;
|
||||
Reference in New Issue
Block a user