Files
Elecciones-2025/Elecciones-Web/frontend-admin/src/components/BancasPreviasManager.tsx

125 lines
6.1 KiB
TypeScript

// src/components/BancasPreviasManager.tsx
import { useState, useEffect } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { getBancasPrevias, updateBancasPrevias, getAgrupaciones } from '../services/apiService';
import type { BancaPrevia, AgrupacionPolitica } from '../types';
import { TipoCamara } from '../types';
const ELECCION_ID_NACIONAL = 2;
export const BancasPreviasManager = () => {
const queryClient = useQueryClient();
const [editedBancas, setEditedBancas] = useState<Record<string, Partial<BancaPrevia>>>({});
const { data: agrupaciones = [], isLoading: isLoadingAgrupaciones } = useQuery<AgrupacionPolitica[]>({
queryKey: ['agrupaciones'],
queryFn: getAgrupaciones,
});
const { data: bancasPrevias = [], isLoading: isLoadingBancas } = useQuery<BancaPrevia[]>({
queryKey: ['bancasPrevias', ELECCION_ID_NACIONAL],
queryFn: () => getBancasPrevias(ELECCION_ID_NACIONAL),
});
useEffect(() => {
if (agrupaciones.length > 0) {
const initialData: Record<string, Partial<BancaPrevia>> = {};
agrupaciones.forEach(agrupacion => {
// Para Diputados
const keyDip = `${agrupacion.id}-${TipoCamara.Diputados}`;
const existingDip = bancasPrevias.find(b => b.agrupacionPoliticaId === agrupacion.id && b.camara === TipoCamara.Diputados);
initialData[keyDip] = { cantidad: existingDip?.cantidad || 0 };
// Para Senadores
const keySen = `${agrupacion.id}-${TipoCamara.Senadores}`;
const existingSen = bancasPrevias.find(b => b.agrupacionPoliticaId === agrupacion.id && b.camara === TipoCamara.Senadores);
initialData[keySen] = { cantidad: existingSen?.cantidad || 0 };
});
setEditedBancas(initialData);
}
}, [agrupaciones, bancasPrevias]);
const handleInputChange = (agrupacionId: string, camara: typeof TipoCamara.Diputados | typeof TipoCamara.Senadores, value: string) => {
const key = `${agrupacionId}-${camara}`;
const cantidad = parseInt(value, 10);
setEditedBancas(prev => ({
...prev,
[key]: { ...prev[key], cantidad: isNaN(cantidad) ? 0 : cantidad }
}));
};
const handleSave = async () => {
const payload: BancaPrevia[] = Object.entries(editedBancas)
.map(([key, value]) => {
const [agrupacionPoliticaId, camara] = key.split('-');
return {
id: 0,
eleccionId: ELECCION_ID_NACIONAL,
agrupacionPoliticaId,
camara: parseInt(camara) as typeof TipoCamara.Diputados | typeof TipoCamara.Senadores,
cantidad: value.cantidad || 0,
};
})
.filter(b => b.cantidad > 0);
try {
await updateBancasPrevias(ELECCION_ID_NACIONAL, payload);
queryClient.invalidateQueries({ queryKey: ['bancasPrevias', ELECCION_ID_NACIONAL] });
alert('Bancas previas guardadas con éxito.');
} catch (error) {
console.error(error);
alert('Error al guardar las bancas previas.');
}
};
const totalDiputados = Object.entries(editedBancas).reduce((sum, [key, value]) => key.endsWith(`-${TipoCamara.Diputados}`) ? sum + (value.cantidad || 0) : sum, 0);
const totalSenadores = Object.entries(editedBancas).reduce((sum, [key, value]) => key.endsWith(`-${TipoCamara.Senadores}`) ? sum + (value.cantidad || 0) : sum, 0);
const isLoading = isLoadingAgrupaciones || isLoadingBancas;
return (
<div className="admin-module">
<h3>Gestión de Bancas Previas (Composición Nacional)</h3>
<p>Define cuántas bancas retiene cada partido antes de la elección. Estos son los escaños que **no** están en juego.</p>
{isLoading ? <p>Cargando...</p> : (
<>
<div className="table-container">
<table>
<thead>
<tr>
<th>Agrupación Política</th>
<th>Bancas Previas Diputados (Total: {totalDiputados} / 130)</th>
<th>Bancas Previas Senadores (Total: {totalSenadores} / 48)</th>
</tr>
</thead>
<tbody>
{agrupaciones.map(agrupacion => (
<tr key={agrupacion.id}>
<td>{agrupacion.nombre}</td>
<td>
<input
type="number"
min="0"
value={editedBancas[`${agrupacion.id}-${TipoCamara.Diputados}`]?.cantidad || 0}
onChange={e => handleInputChange(agrupacion.id, TipoCamara.Diputados, e.target.value)}
/>
</td>
<td>
<input
type="number"
min="0"
value={editedBancas[`${agrupacion.id}-${TipoCamara.Senadores}`]?.cantidad || 0}
onChange={e => handleInputChange(agrupacion.id, TipoCamara.Senadores, e.target.value)}
/>
</td>
</tr>
))}
</tbody>
</table>
</div>
<button onClick={handleSave} style={{ marginTop: '1rem' }}>Guardar Bancas Previas</button>
</>
)}
</div>
);
};