125 lines
6.1 KiB
TypeScript
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>
|
||
|
|
);
|
||
|
|
};
|