// src/pages/Distribucion/GestionarNovedadesCanillaPage.tsx import React, { useState, useEffect, useCallback } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { Box, Typography, Button, Paper, IconButton, Menu, MenuItem, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, CircularProgress, Alert, TextField, Tooltip } from '@mui/material'; import AddIcon from '@mui/icons-material/Add'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import EditIcon from '@mui/icons-material/Edit'; import DeleteIcon from '@mui/icons-material/Delete'; import FilterListIcon from '@mui/icons-material/FilterList'; import novedadCanillaService from '../../services/Distribucion/novedadCanillaService'; import canillaService from '../../services/Distribucion/canillaService'; import type { NovedadCanillaDto } from '../../models/dtos/Distribucion/NovedadCanillaDto'; import type { CreateNovedadCanillaDto } from '../../models/dtos/Distribucion/CreateNovedadCanillaDto'; import type { UpdateNovedadCanillaDto } from '../../models/dtos/Distribucion/UpdateNovedadCanillaDto'; import type { CanillaDto } from '../../models/dtos/Distribucion/CanillaDto'; import NovedadCanillaFormModal from '../../components/Modals/Distribucion/NovedadCanillaFormModal'; import { usePermissions } from '../../hooks/usePermissions'; import axios from 'axios'; const GestionarNovedadesCanillaPage: React.FC = () => { const { idCanilla: idCanillaStr } = useParams<{ idCanilla: string }>(); const navigate = useNavigate(); const idCanilla = Number(idCanillaStr); const [canillita, setCanillita] = useState(null); const [novedades, setNovedades] = useState([]); const [loading, setLoading] = useState(true); const [errorPage, setErrorPage] = useState(null); // Error general de la página const [filtroFechaDesde, setFiltroFechaDesde] = useState(''); const [filtroFechaHasta, setFiltroFechaHasta] = useState(''); const [modalOpen, setModalOpen] = useState(false); const [editingNovedad, setEditingNovedad] = useState(null); const [apiErrorMessage, setApiErrorMessage] = useState(null); // Para modal/delete const [anchorEl, setAnchorEl] = useState(null); const [selectedNovedadRow, setSelectedNovedadRow] = useState(null); const { tienePermiso, isSuperAdmin } = usePermissions(); const puedeGestionarNovedades = isSuperAdmin || tienePermiso("CG006"); const puedeVerCanillitas = isSuperAdmin || tienePermiso("CG001"); // Cargar datos del canillita (solo una vez o si idCanilla cambia) useEffect(() => { if (isNaN(idCanilla)) { setErrorPage("ID de Canillita inválido."); setLoading(false); // Detener carga principal return; } if (!puedeVerCanillitas && !puedeGestionarNovedades) { setErrorPage("No tiene permiso para acceder a esta sección."); setLoading(false); return; } setLoading(true); // Iniciar carga para datos del canillita const fetchCanillita = async () => { try { if (puedeVerCanillitas) { const canData = await canillaService.getCanillaById(idCanilla); setCanillita(canData); } else { // Si no puede ver detalles del canillita pero sí novedades, al menos mostrar ID setCanillita({ idCanilla, nomApe: `ID ${idCanilla}` } as CanillaDto); } } catch (err) { console.error("Error cargando datos del canillita:", err); setErrorPage(`Error al cargar datos del canillita (ID: ${idCanilla}).`); } // No ponemos setLoading(false) aquí, porque la carga de novedades sigue. }; fetchCanillita(); }, [idCanilla, puedeVerCanillitas, puedeGestionarNovedades]); // Cargar/filtrar novedades const cargarNovedades = useCallback(async () => { if (isNaN(idCanilla) || (!puedeGestionarNovedades && !puedeVerCanillitas)) { // Los permisos ya se validaron en el useEffect anterior, pero es bueno tenerlo return; } // Si ya está cargando los datos del canillita, no iniciar otra carga paralela // Se usará el mismo 'loading' para ambas operaciones iniciales. // if (!loading) setLoading(true); // No es necesario si el useEffect anterior ya lo hizo setApiErrorMessage(null); // Limpiar errores de API de acciones previas // setErrorPage(null); // No limpiar error de página aquí, podría ser por el canillita try { const params = { fechaDesde: filtroFechaDesde || null, fechaHasta: filtroFechaHasta || null, }; const dataNovedades = await novedadCanillaService.getNovedadesPorCanilla(idCanilla, params); setNovedades(dataNovedades); // Si no hay datos con filtros, no es un error de API, simplemente no hay datos. // El mensaje de "no hay novedades" se maneja en la tabla. } catch (err: any) { console.error("Error al cargar/filtrar novedades:", err); const message = axios.isAxiosError(err) && err.response?.data?.message ? err.response.data.message : 'Error al cargar las novedades.'; setErrorPage(message); // Usar el error de página para problemas de carga de novedades setNovedades([]); // Limpiar en caso de error } finally { // Solo poner setLoading(false) después de que AMBAS cargas (canillita y novedades) se intenten. // Como se llaman en secuencia implícita por los useEffect, el último setLoading(false) es el de novedades. setLoading(false); } }, [idCanilla, puedeGestionarNovedades, puedeVerCanillitas, filtroFechaDesde, filtroFechaHasta]); // useEffect para cargar novedades cuando los filtros o el canillita (o permisos) cambian useEffect(() => { // Solo cargar si tenemos un idCanilla válido y permisos if (!isNaN(idCanilla) && (puedeGestionarNovedades || puedeVerCanillitas)) { cargarNovedades(); } else if (isNaN(idCanilla)){ setErrorPage("ID de Canillita inválido."); setLoading(false); } else if (!puedeGestionarNovedades && !puedeVerCanillitas) { setErrorPage("No tiene permiso para acceder a esta sección."); setLoading(false); } }, [idCanilla, cargarNovedades, puedeGestionarNovedades, puedeVerCanillitas]); // `cargarNovedades` ya tiene sus dependencias const handleOpenModal = (item?: NovedadCanillaDto) => { if (!puedeGestionarNovedades) { setApiErrorMessage("No tiene permiso para agregar o editar novedades."); return; } setEditingNovedad(item || null); setApiErrorMessage(null); setModalOpen(true); }; const handleCloseModal = () => { setModalOpen(false); setEditingNovedad(null); }; const handleSubmitModal = async (data: CreateNovedadCanillaDto | UpdateNovedadCanillaDto, idNovedad?: number) => { if (!puedeGestionarNovedades) return; setApiErrorMessage(null); try { if (editingNovedad && idNovedad) { await novedadCanillaService.updateNovedad(idNovedad, data as UpdateNovedadCanillaDto); } else { await novedadCanillaService.createNovedad(data as CreateNovedadCanillaDto); } cargarNovedades(); // Recargar lista de novedades } catch (err: any) { const message = axios.isAxiosError(err) && err.response?.data?.message ? err.response.data.message : 'Error al guardar la novedad.'; setApiErrorMessage(message); throw err; } }; const handleDelete = async (idNovedadDelRow: number) => { if (!puedeGestionarNovedades) return; if (window.confirm(`¿Seguro de eliminar esta novedad (ID: ${idNovedadDelRow})?`)) { setApiErrorMessage(null); try { await novedadCanillaService.deleteNovedad(idNovedadDelRow); cargarNovedades(); // Recargar lista de novedades } catch (err: any) { const message = axios.isAxiosError(err) && err.response?.data?.message ? err.response.data.message : 'Error al eliminar la novedad.'; setApiErrorMessage(message); } } handleMenuClose(); }; const handleMenuOpen = (event: React.MouseEvent, item: NovedadCanillaDto) => { setAnchorEl(event.currentTarget); setSelectedNovedadRow(item); }; const handleMenuClose = () => { setAnchorEl(null); setSelectedNovedadRow(null); }; const formatDate = (dateString?: string | null) => dateString ? new Date(dateString).toLocaleDateString('es-AR', {timeZone: 'UTC'}) : '-'; if (loading && !canillita) { // Muestra cargando solo si aún no tenemos los datos del canillita return ; } if (errorPage && !canillita) { // Si hay un error al cargar el canillita, no mostrar nada más return {errorPage}; } // Si no tiene permiso para la sección en general if (!puedeGestionarNovedades && !puedeVerCanillitas) { return Acceso denegado.; } return ( Novedades de: {canillita?.nomApe || `Canillita ID ${idCanilla}`} {puedeGestionarNovedades && ( )} setFiltroFechaDesde(e.target.value)} InputLabelProps={{ shrink: true }} disabled={loading} // Deshabilitar durante cualquier carga /> setFiltroFechaHasta(e.target.value)} InputLabelProps={{ shrink: true }} disabled={loading} // Deshabilitar durante cualquier carga /> {/* Mostrar error de API (de submit/delete) o error de carga de novedades */} {(apiErrorMessage || (errorPage && novedades.length === 0 && !loading)) && ( {apiErrorMessage || errorPage} )} {loading && } Fecha Detalle de Novedad {puedeGestionarNovedades && Acciones} {novedades.length === 0 && !loading ? ( No hay novedades registradas { (filtroFechaDesde || filtroFechaHasta) && "con los filtros aplicados"}. ) : ( novedades.map((nov) => ( {formatDate(nov.fecha)} {nov.detalle || '-'} {puedeGestionarNovedades && ( handleMenuOpen(e, nov)} disabled={!puedeGestionarNovedades}> )} )))}
{puedeGestionarNovedades && selectedNovedadRow && ( { handleOpenModal(selectedNovedadRow); handleMenuClose(); }}> Editar)} {puedeGestionarNovedades && selectedNovedadRow && ( handleDelete(selectedNovedadRow.idNovedad)}> Eliminar)} {idCanilla && setApiErrorMessage(null)} /> }
); }; export default GestionarNovedadesCanillaPage;