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>
|
||
|
|
);
|
||
|
|
};
|