Feat Widgets Cards y Optimización de Consultas
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
// 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>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user