88 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			88 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
|  | // frontend/src/components/Dashboard.tsx
 | ||
|  | 
 | ||
|  | import { useEffect, useState } from 'react'; | ||
|  | import { Box, Button, Typography, Stack } 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 FormularioConfiguracion from './FormularioConfiguracion'; | ||
|  | import TablaTitulares from './TablaTitulares'; | ||
|  | import AddTitularModal from './AddTitularModal'; | ||
|  | 
 | ||
|  | const Dashboard = () => { | ||
|  |   const [titulares, setTitulares] = useState<Titular[]>([]); | ||
|  |   const [modalOpen, setModalOpen] = useState(false); | ||
|  | 
 | ||
|  |   const cargarTitulares = async () => { | ||
|  |     try { | ||
|  |       const data = await api.obtenerTitulares(); | ||
|  |       setTitulares(data); | ||
|  |     } catch (error) { | ||
|  |       console.error("Error al cargar titulares:", error); | ||
|  |     } | ||
|  |   }; | ||
|  | 
 | ||
|  |   useEffect(() => { | ||
|  |     cargarTitulares(); | ||
|  |   }, []); | ||
|  | 
 | ||
|  |   const handleReorder = async (titularesReordenados: Titular[]) => { | ||
|  |     setTitulares(titularesReordenados); // Actualización optimista de la UI
 | ||
|  |     const payload = titularesReordenados.map((item, index) => ({ | ||
|  |       id: item.id, | ||
|  |       nuevoOrden: index | ||
|  |     })); | ||
|  |     try { | ||
|  |       await api.actualizarOrdenTitulares(payload); | ||
|  |     } catch (err) { | ||
|  |       console.error("Error al reordenar:", err); | ||
|  |       cargarTitulares(); // Revertir en caso de error
 | ||
|  |     } | ||
|  |   }; | ||
|  | 
 | ||
|  |   const handleDelete = async (id: number) => { | ||
|  |     if (window.confirm('¿Estás seguro de que quieres eliminar este titular?')) { | ||
|  |       try { | ||
|  |         await api.eliminarTitular(id); | ||
|  |         setTitulares(titulares.filter(t => t.id !== id)); // Actualizar UI
 | ||
|  |       } catch (err) { | ||
|  |         console.error("Error al eliminar:", err); | ||
|  |       } | ||
|  |     } | ||
|  |   }; | ||
|  | 
 | ||
|  |   const handleAdd = async (texto: string) => { | ||
|  |     try { | ||
|  |       await api.crearTitularManual(texto); | ||
|  |       cargarTitulares(); // Recargar la lista para ver el nuevo titular
 | ||
|  |     } catch (err) { | ||
|  |       console.error("Error al añadir titular:", err); | ||
|  |     } | ||
|  |   }; | ||
|  | 
 | ||
|  |   return ( | ||
|  |     <> | ||
|  |       <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}> | ||
|  |         <Typography variant="h4" component="h1"> | ||
|  |           Titulares Dashboard | ||
|  |         </Typography> | ||
|  |         <Stack direction="row" spacing={2}> | ||
|  |           <Button variant="outlined" startIcon={<SyncIcon />}> | ||
|  |             Generate CSV | ||
|  |           </Button> | ||
|  |           <Button variant="contained" startIcon={<AddIcon />} onClick={() => setModalOpen(true)}> | ||
|  |             Add Manual | ||
|  |           </Button> | ||
|  |         </Stack> | ||
|  |       </Box> | ||
|  | 
 | ||
|  |       <FormularioConfiguracion /> | ||
|  |       <TablaTitulares titulares={titulares} onReorder={handleReorder} onDelete={handleDelete} /> | ||
|  | 
 | ||
|  |       <AddTitularModal open={modalOpen} onClose={() => setModalOpen(false)} onAdd={handleAdd} /> | ||
|  |     </> | ||
|  |   ); | ||
|  | }; | ||
|  | 
 | ||
|  | export default Dashboard; |