// frontend/src/components/Dashboard.tsx import { useEffect, useState, useCallback } from 'react'; import { Box, Button, Typography, Stack, Chip, CircularProgress } from '@mui/material'; import AddIcon from '@mui/icons-material/Add'; import SyncIcon from '@mui/icons-material/Sync'; import type { Titular } from '../types'; import * as api from '../services/apiService'; import { useSignalR } from '../hooks/useSignalR'; import FormularioConfiguracion from './FormularioConfiguracion'; import TablaTitulares from './TablaTitulares'; import AddTitularModal from './AddTitularModal'; import EditarTitularModal from './EditarTitularModal'; const Dashboard = () => { const [titulares, setTitulares] = useState([]); const [modalOpen, setModalOpen] = useState(false); const [isGeneratingCsv, setIsGeneratingCsv] = useState(false); const [titularAEditar, setTitularAEditar] = useState(null); // Usamos useCallback para que la función de callback no se recree en cada render, // evitando que el useEffect del hook se ejecute innecesariamente. const onTitularesActualizados = useCallback((titularesActualizados: Titular[]) => { console.log("Datos recibidos desde SignalR:", titularesActualizados); setTitulares(titularesActualizados); }, []); // El array vacío significa que esta función nunca cambiará // Usamos nuestro hook y le pasamos el evento que nos interesa escuchar const { connectionStatus } = useSignalR([ { eventName: 'TitularesActualizados', callback: onTitularesActualizados } ]); // La carga inicial de datos sigue siendo necesaria por si el componente se monta // antes de que llegue la primera notificación de SignalR. useEffect(() => { api.obtenerTitulares() .then(setTitulares) .catch(error => console.error("Error al cargar titulares:", error)); }, []); const handleReorder = async (titularesReordenados: Titular[]) => { setTitulares(titularesReordenados); const payload = titularesReordenados.map((item, index) => ({ id: item.id, nuevoOrden: index })); try { await api.actualizarOrdenTitulares(payload); // Ya no necesitamos hacer nada más, SignalR notificará a todos los clientes. } catch (err) { console.error("Error al reordenar:", err); // En caso de error, volvemos a pedir los datos para no tener un estado inconsistente. api.obtenerTitulares().then(setTitulares); } }; const handleDelete = async (id: number) => { if (window.confirm('¿Estás seguro de que quieres eliminar este titular?')) { try { await api.eliminarTitular(id); // SignalR se encargará de actualizar el estado. } catch (err) { console.error("Error al eliminar:", err); } } }; const handleAdd = async (texto: string) => { try { await api.crearTitularManual(texto); // SignalR se encargará de actualizar el estado. } catch (err) { console.error("Error al añadir titular:", err); } }; const getStatusChip = () => { switch (connectionStatus) { case 'Connected': return ; case 'Reconnecting': case 'Connecting': return ; default: return ; } } const handleGenerateCsv = async () => { setIsGeneratingCsv(true); try { await api.generarCsvManual(); // Opcional: mostrar una notificación de éxito } catch (error) { console.error("Error al generar CSV manualmente", error); // Opcional: mostrar una notificación de error } finally { setIsGeneratingCsv(false); } }; const handleSaveEdit = async (id: number, texto: string, viñeta: string) => { try { await api.actualizarTitular(id, { texto, viñeta: viñeta || null }); // SignalR se encargará de actualizar la UI } catch (err) { console.error("Error al guardar cambios:", err); } }; return ( <> Titulares Dashboard {getStatusChip()} setTitularAEditar(titular)} /> setModalOpen(false)} onAdd={handleAdd} /> setTitularAEditar(null)} onSave={handleSaveEdit} titular={titularAEditar} /> ); }; export default Dashboard;