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