Fix bancas widget
This commit is contained in:
		| @@ -17,6 +17,8 @@ export const CongresoWidget = () => { | ||||
|   const { data: composicionData, isLoading: isLoadingComposicion, error: errorComposicion } = useQuery<ComposicionData>({ | ||||
|     queryKey: ['composicionCongreso'], | ||||
|     queryFn: getComposicionCongreso, | ||||
|     // Vuelve a buscar los datos cada 20 segundos | ||||
|     refetchInterval: 20000, | ||||
|   }); | ||||
|  | ||||
|   const { data: bancadasDetalle = [] } = useQuery<BancadaDetalle[]>({ | ||||
| @@ -29,28 +31,41 @@ export const CongresoWidget = () => { | ||||
|  | ||||
|   // --- LÓGICA DE SEATFILLDATA --- | ||||
|   const seatFillData = useMemo(() => { | ||||
|     if (!datosCamaraActual || !bancadasDetalle.length) return []; | ||||
|     if (!datosCamaraActual) return []; | ||||
|  | ||||
|     const camaraId = camaraActiva === 'diputados' ? 0 : 1; | ||||
|     const bancadasDeCamara = bancadasDetalle.filter(b => b.camara === camaraId); | ||||
|     // --- LÓGICA DEL INTERRUPTOR --- | ||||
|     // Verificamos si la respuesta de la API contiene datos de ocupantes. | ||||
|     // Si bancadasDetalle tiene elementos, significa que el modo "Oficial" está activo en el backend. | ||||
|     const modoOficialActivo = bancadasDetalle.length > 0; | ||||
|  | ||||
|     // Creamos un mapa de AgrupacionId -> Color para un acceso rápido | ||||
|     const colorMap = new Map<string, string>(); | ||||
|     datosCamaraActual.partidos.forEach(p => { | ||||
|       if (p.id && p.color) { | ||||
|         colorMap.set(p.id, p.color); | ||||
|       } | ||||
|     }); | ||||
|     if (modoOficialActivo) { | ||||
|       // --- MODO OFICIAL: Construir desde las bancas físicas --- | ||||
|       const camaraId = camaraActiva === 'diputados' ? 0 : 1; | ||||
|       const bancadasDeCamara = bancadasDetalle.filter(b => b.camara === camaraId); | ||||
|  | ||||
|     // 1. Aseguramos que la lista de bancas esté en orden físico (por su ID). | ||||
|     const bancadasOrdenadas = bancadasDeCamara.sort((a, b) => a.id - b.id); | ||||
|       const colorMap = new Map<string, string>(); | ||||
|       datosCamaraActual.partidos.forEach(p => { | ||||
|         if (p.id && p.color) { | ||||
|           colorMap.set(p.id, p.color); | ||||
|         } | ||||
|       }); | ||||
|  | ||||
|     // 2. Mapeamos cada banca física a un objeto SeatFillData. | ||||
|     // El índice del array corresponderá al asiento visual. | ||||
|     return bancadasOrdenadas.map(bancada => ({ | ||||
|       color: bancada.agrupacionPoliticaId ? colorMap.get(bancada.agrupacionPoliticaId) || DEFAULT_COLOR : DEFAULT_COLOR, | ||||
|       ocupante: bancada.ocupante | ||||
|     })); | ||||
|       const bancadasOrdenadas = bancadasDeCamara.sort((a, b) => a.id - b.id); | ||||
|  | ||||
|       return bancadasOrdenadas.map(bancada => ({ | ||||
|         color: bancada.agrupacionPoliticaId ? colorMap.get(bancada.agrupacionPoliticaId) || DEFAULT_COLOR : DEFAULT_COLOR, | ||||
|         ocupante: bancada.ocupante | ||||
|       })); | ||||
|  | ||||
|     } else { | ||||
|       // --- MODO PROYECCIÓN: Construir desde los totales de los partidos --- | ||||
|       // Esta es la lógica original que teníamos para el modo proyección. | ||||
|       return datosCamaraActual.partidos.flatMap(party => { | ||||
|         const seatColor = party.color || DEFAULT_COLOR; | ||||
|         // En modo proyección, no hay ocupantes individuales. | ||||
|         return Array(party.bancasTotales).fill({ color: seatColor, ocupante: null }); | ||||
|       }); | ||||
|     } | ||||
|  | ||||
|   }, [datosCamaraActual, bancadasDetalle, camaraActiva]); | ||||
|  | ||||
|   | ||||
| @@ -127,43 +127,44 @@ export const ParliamentLayout: React.FC<ParliamentLayoutProps> = ({ | ||||
|  | ||||
|   // Si hay un presidente y su partido tiene bancas, le quitamos una para asignarla. | ||||
|   if (presidenteBancada && presidenteBancada.color) { | ||||
|     // Encontramos el índice del último asiento que pertenece al partido del presidente. | ||||
|     const lastSeatIndex = finalSeatData.map(s => s.color).lastIndexOf(presidenteBancada.color); | ||||
|  | ||||
|     if (lastSeatIndex !== -1) { | ||||
|       // Eliminamos ese asiento de la lista de asientos electorales. | ||||
|       finalSeatData.splice(lastSeatIndex, 1); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   const renderedElements = seatElements.map((child, index) => { | ||||
|   // El asiento presidencial sigue siendo un caso especial | ||||
|   if (index === PRESIDENTE_SEAT_INDEX) { | ||||
|     // --- CASO ESPECIAL: ASIENTO PRESIDENCIAL --- | ||||
|     if (index === PRESIDENTE_SEAT_INDEX) { | ||||
|       return React.cloneElement(child, { | ||||
|         fill: presidenteBancada?.color || '#A9A9A9', | ||||
|         stroke: '#000000', | ||||
|         strokeWidth: 2, | ||||
|         // Le damos un tooltip genérico al presidente | ||||
|         'data-tooltip-id': 'seat-tooltip', | ||||
|         'data-tooltip-html': `<div class="seat-tooltip"><p>Presidencia de la Cámara</p></div>` | ||||
|       }); | ||||
|     } | ||||
|  | ||||
|     // --- LÓGICA NORMAL PARA EL RESTO DE ASIENTOS --- | ||||
|     // Usamos la copia modificada 'finalSeatData'. Como este array es más corto, | ||||
|     // el último asiento electoral no encontrará datos y quedará gris, lo cual es correcto. | ||||
|     const seat = finalSeatData[index]; | ||||
|  | ||||
|     if (!seat) { | ||||
|       return React.cloneElement(child, { fill: '#E0E0E0', stroke: '#ffffff', strokeWidth: 1.5 }); | ||||
|     } | ||||
|  | ||||
|     return React.cloneElement(child, { | ||||
|       fill: presidenteBancada?.color || '#A9A9A9', | ||||
|       stroke: '#000000', | ||||
|       strokeWidth: 2, | ||||
|       fill: seat.color, | ||||
|       stroke: '#ffffff', | ||||
|       strokeWidth: 1.5, | ||||
|       'data-tooltip-id': seat.ocupante ? 'seat-tooltip' : undefined, | ||||
|       'data-tooltip-html': seat.ocupante | ||||
|         ? `<div class="seat-tooltip"><img src="${seat.ocupante.fotoUrl || '/default-avatar.png'}" alt="${seat.ocupante.nombreOcupante}" /><p>${seat.ocupante.nombreOcupante}</p></div>` | ||||
|         : undefined, | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   // La lógica ahora es simple: el asiento en el índice X del SVG | ||||
|   // corresponde al asiento en el índice X de los datos. | ||||
|   const seat = seatData[index]; | ||||
|  | ||||
|   if (!seat) { | ||||
|     return React.cloneElement(child, { fill: '#E0E0E0', stroke: '#ffffff', strokeWidth: 1.5 }); | ||||
|   } | ||||
|  | ||||
|   return React.cloneElement(child, { | ||||
|     fill: seat.color, | ||||
|     stroke: '#ffffff', | ||||
|     strokeWidth: 1.5, | ||||
|     'data-tooltip-id': seat.ocupante ? 'seat-tooltip' : undefined, | ||||
|     'data-tooltip-html': seat.ocupante | ||||
|       ? `<div class="seat-tooltip"><img src="${seat.ocupante.fotoUrl || '/default-avatar.png'}" alt="${seat.ocupante.nombreOcupante}" /><p>${seat.ocupante.nombreOcupante}</p></div>` | ||||
|       : undefined, | ||||
|   }); | ||||
| }); | ||||
|  | ||||
|   return ( | ||||
|     <svg viewBox="0 0 550 375" width={size} height={size * (375 / 550)} style={{ display: 'block', margin: 'auto' }}> | ||||
|   | ||||
| @@ -81,28 +81,29 @@ export const SenateLayout: React.FC<SenateLayoutProps> = ({ | ||||
|  | ||||
|   // Si hay un presidente y su partido tiene bancas, le quitamos una para asignarla. | ||||
|   if (presidenteBancada && presidenteBancada.color) { | ||||
|     // Encontramos el índice del último asiento que pertenece al partido del presidente. | ||||
|     const lastSeatIndex = finalSeatData.map(s => s.color).lastIndexOf(presidenteBancada.color); | ||||
|  | ||||
|     if (lastSeatIndex !== -1) { | ||||
|       // Eliminamos ese asiento de la lista de asientos electorales. | ||||
|       finalSeatData.splice(lastSeatIndex, 1); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   const renderedElements = seatElements.map((child, index) => { | ||||
|     // El asiento presidencial sigue siendo un caso especial | ||||
|     // --- CASO ESPECIAL: ASIENTO PRESIDENCIAL --- | ||||
|     if (index === PRESIDENTE_SEAT_INDEX) { | ||||
|       return React.cloneElement(child, { | ||||
|         fill: presidenteBancada?.color || '#A9A9A9', | ||||
|         stroke: '#000000', | ||||
|         strokeWidth: 2, | ||||
|         // Le damos un tooltip genérico al presidente | ||||
|         'data-tooltip-id': 'seat-tooltip', | ||||
|         'data-tooltip-html': `<div class="seat-tooltip"><p>Presidencia de la Cámara</p></div>` | ||||
|       }); | ||||
|     } | ||||
|  | ||||
|     // La lógica ahora es simple: el asiento en el índice X del SVG | ||||
|     // corresponde al asiento en el índice X de los datos. | ||||
|     const seat = seatData[index]; | ||||
|     // --- LÓGICA NORMAL PARA EL RESTO DE ASIENTOS --- | ||||
|     // Usamos la copia modificada 'finalSeatData'. Como este array es más corto, | ||||
|     // el último asiento electoral no encontrará datos y quedará gris, lo cual es correcto. | ||||
|     const seat = finalSeatData[index]; | ||||
|  | ||||
|     if (!seat) { | ||||
|       return React.cloneElement(child, { fill: '#E0E0E0', stroke: '#ffffff', strokeWidth: 1.5 }); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user