91 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			91 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| // src/components/BancasWidget.tsx
 | |
| import { useState, useEffect } from 'react';
 | |
| import { ResponsiveWaffle } from '@nivo/waffle';
 | |
| import { getBancasPorSeccion } from '../apiService';
 | |
| import type { ProyeccionBancas } from '../types';
 | |
| import './BancasWidget.css';
 | |
| 
 | |
| // Paleta de colores consistente
 | |
| const NIVO_COLORS = ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"];
 | |
| 
 | |
| // Las Secciones Electorales de la Provincia (esto podría venir de la API en el futuro)
 | |
| const secciones = [
 | |
|     { id: '1', nombre: 'Primera Sección' },
 | |
|     { id: '2', nombre: 'Segunda Sección' },
 | |
|     { id: '3', nombre: 'Tercera Sección' },
 | |
|     { id: '4', nombre: 'Cuarta Sección' },
 | |
|     { id: '5', nombre: 'Quinta Sección' },
 | |
|     { id: '6', nombre: 'Sexta Sección' },
 | |
|     { id: '7', nombre: 'Séptima Sección' },
 | |
|     { id: '8', nombre: 'Octava Sección (Capital)' },
 | |
| ];
 | |
| 
 | |
| export const BancasWidget = () => {
 | |
|     const [seccionActual, setSeccionActual] = useState('1'); // Empezamos con la Primera Sección
 | |
|     const [data, setData] = useState<ProyeccionBancas | null>(null);
 | |
|     const [loading, setLoading] = useState(true);
 | |
| 
 | |
|     useEffect(() => {
 | |
|         const fetchData = async () => {
 | |
|             setLoading(true);
 | |
|             try {
 | |
|                 const result = await getBancasPorSeccion(seccionActual);
 | |
|                 setData(result);
 | |
|             } catch (error) {
 | |
|                 console.error(`Error cargando datos de bancas para sección ${seccionActual}:`, error);
 | |
|                 setData(null); // Limpiar datos en caso de error
 | |
|             } finally {
 | |
|                 setLoading(false);
 | |
|             }
 | |
|         };
 | |
|         fetchData();
 | |
|     }, [seccionActual]); // Se ejecuta cada vez que cambia la sección
 | |
| 
 | |
|     const waffleData = data?.proyeccion.map(p => ({
 | |
|         id: p.agrupacionNombre,
 | |
|         label: p.agrupacionNombre,
 | |
|         value: p.bancas,
 | |
|     })) || [];
 | |
| 
 | |
|     const totalBancas = waffleData.reduce((sum, current) => sum + current.value, 0);
 | |
| 
 | |
|     return (
 | |
|         <div className="bancas-widget-container">
 | |
|             <div className="bancas-header">
 | |
|                 <h4>Distribución de Bancas</h4>
 | |
|                 <select value={seccionActual} onChange={e => setSeccionActual(e.target.value)}>
 | |
|                     {secciones.map(s => <option key={s.id} value={s.id}>{s.nombre}</option>)}
 | |
|                 </select>
 | |
|             </div>
 | |
|             <div className="waffle-chart-container">
 | |
|                 {loading ? <p>Cargando...</p> : !data ? <p>No hay datos disponibles para esta sección.</p> :
 | |
|                 <ResponsiveWaffle
 | |
|                     data={waffleData}
 | |
|                     total={totalBancas}
 | |
|                     rows={8}
 | |
|                     columns={10}
 | |
|                     fillDirection="bottom"
 | |
|                     padding={3}
 | |
|                     colors={NIVO_COLORS}
 | |
|                     borderColor={{ from: 'color', modifiers: [['darker', 0.3]] }}
 | |
|                     animate={true}
 | |
|                     legends={[
 | |
|                         {
 | |
|                             anchor: 'bottom',
 | |
|                             direction: 'row',
 | |
|                             justify: false,
 | |
|                             translateX: 0,
 | |
|                             translateY: 40,
 | |
|                             itemsSpacing: 4,
 | |
|                             itemWidth: 100,
 | |
|                             itemHeight: 20,
 | |
|                             itemTextColor: '#999',
 | |
|                             itemDirection: 'left-to-right',
 | |
|                             symbolSize: 20,
 | |
|                         },
 | |
|                     ]}
 | |
|                 />}
 | |
|             </div>
 | |
|         </div>
 | |
|     );
 | |
| }; |