| 
									
										
										
										
											2025-09-28 19:04:09 -03:00
										 |  |  | // 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}> | 
					
						
							| 
									
										
										
										
											2025-10-20 11:03:19 -03:00
										 |  |  |                                         <td>({agrupacion.id}) {agrupacion.nombre}</td> | 
					
						
							| 
									
										
										
										
											2025-09-28 19:04:09 -03:00
										 |  |  |                                         <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> | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | }; |