Preparación Legislativas Nacionales 2025
This commit is contained in:
87
Elecciones-Web/frontend/src/components/common/DevApp.tsx
Normal file
87
Elecciones-Web/frontend/src/components/common/DevApp.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
// src/components/common/DevApp.tsx
|
||||
import { BancasWidget } from '../../features/legislativas/provinciales/BancasWidget'
|
||||
import { CongresoWidget } from '../../features/legislativas/provinciales/CongresoWidget'
|
||||
import MapaBsAs from '../../features/legislativas/provinciales/MapaBsAs'
|
||||
import { DipSenTickerWidget } from '../../features/legislativas/provinciales/DipSenTickerWidget'
|
||||
import { TelegramaWidget } from '../../features/legislativas/provinciales/TelegramaWidget'
|
||||
import { ConcejalesWidget } from '../../features/legislativas/provinciales/ConcejalesWidget'
|
||||
import MapaBsAsSecciones from '../../features/legislativas/provinciales/MapaBsAsSecciones'
|
||||
import { SenadoresWidget } from '../../features/legislativas/provinciales/SenadoresWidget'
|
||||
import { DiputadosWidget } from '../../features/legislativas/provinciales/DiputadosWidget'
|
||||
import { ResumenGeneralWidget } from '../../features/legislativas/provinciales/ResumenGeneralWidget'
|
||||
import { SenadoresTickerWidget } from '../../features/legislativas/provinciales/SenadoresTickerWidget'
|
||||
import { DiputadosTickerWidget } from '../../features/legislativas/provinciales/DiputadosTickerWidget'
|
||||
import { ConcejalesTickerWidget } from '../../features/legislativas/provinciales/ConcejalesTickerWidget'
|
||||
import { DiputadosPorSeccionWidget } from '../../features/legislativas/provinciales/DiputadosPorSeccionWidget'
|
||||
import { SenadoresPorSeccionWidget } from '../../features/legislativas/provinciales/SenadoresPorSeccionWidget'
|
||||
import { ConcejalesPorSeccionWidget } from '../../features/legislativas/provinciales/ConcejalesPorSeccionWidget'
|
||||
import { ResultadosTablaDetalladaWidget } from '../../features/legislativas/provinciales/ResultadosTablaDetalladaWidget'
|
||||
import { ResultadosRankingMunicipioWidget } from '../../features/legislativas/provinciales/ResultadosRankingMunicipioWidget'
|
||||
import '../../App.css';
|
||||
|
||||
|
||||
export const DevApp = () => {
|
||||
return (
|
||||
<>
|
||||
<h1 style={{ textAlign: 'center', fontFamily: 'sans-serif' }}>
|
||||
Showcase de Widgets - Elecciones 2025
|
||||
</h1>
|
||||
<main>
|
||||
<DipSenTickerWidget />
|
||||
<ResumenGeneralWidget />
|
||||
<SenadoresWidget />
|
||||
<DiputadosWidget />
|
||||
<ConcejalesWidget />
|
||||
<SenadoresTickerWidget />
|
||||
<DiputadosTickerWidget />
|
||||
<ConcejalesTickerWidget />
|
||||
<DiputadosPorSeccionWidget />
|
||||
<SenadoresPorSeccionWidget />
|
||||
<ConcejalesPorSeccionWidget />
|
||||
<CongresoWidget />
|
||||
<BancasWidget />
|
||||
<MapaBsAs />
|
||||
<MapaBsAsSecciones />
|
||||
<TelegramaWidget />
|
||||
<ResultadosTablaDetalladaWidget />
|
||||
<ResultadosRankingMunicipioWidget />
|
||||
|
||||
<hr className="border-gray-300 my-8" />
|
||||
|
||||
<h2>Mapa - Vista General (Por Defecto)</h2>
|
||||
<p>Carga la vista provincial completa para Diputados.</p>
|
||||
<MapaBsAs />
|
||||
|
||||
<hr className="border-gray-300 my-8" />
|
||||
|
||||
<h2>Mapa - Foco en La Plata (Diputados por defecto)</h2>
|
||||
<p>Carga el mapa y automáticamente hace zoom en La Plata.</p>
|
||||
<MapaBsAs focoMunicipio="LA PLATA" />
|
||||
|
||||
<hr className="border-gray-300 my-8" />
|
||||
|
||||
<h2>Mapa - Foco en Campana</h2>
|
||||
<p>Carga el mapa y automáticamente hace zoom en Campana.</p>
|
||||
<MapaBsAs focoMunicipio="CAMPANA" focoCategoria="senadores" />
|
||||
|
||||
<hr className="border-gray-300 my-8" />
|
||||
|
||||
<h2>Mapa - Vista General de Senadores</h2>
|
||||
<p>Carga la vista provincial completa para la categoría Senadores.</p>
|
||||
<MapaBsAs focoCategoria="senadores" />
|
||||
|
||||
<hr className="border-gray-300 my-8" />
|
||||
|
||||
<h2>Mapa - Foco en Bahía Blanca para Concejales</h2>
|
||||
<p>Carga el mapa enfocado en Bahía Blanca y con la categoría Concejales seleccionada.</p>
|
||||
<MapaBsAs focoMunicipio="BAHIA BLANCA" focoCategoria="concejales" />
|
||||
|
||||
<hr className="border-gray-300 my-8" />
|
||||
|
||||
<h2>Mapa - Foco Inválido (La Plata para Senadores)</h2>
|
||||
<p>Debería mostrar la vista provincial de Senadores y un warning en la consola del navegador.</p>
|
||||
<MapaBsAs focoMunicipio="LA PLATA" focoCategoria="senadores" />
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
// src/components/common/ImageWithFallback.tsx
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
interface Props extends React.ImgHTMLAttributes<HTMLImageElement> {
|
||||
fallbackSrc: string;
|
||||
}
|
||||
|
||||
export const ImageWithFallback = ({ src, fallbackSrc, ...props }: Props) => {
|
||||
const [imgSrc, setImgSrc] = useState(src);
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setError(false);
|
||||
setImgSrc(src);
|
||||
}, [src]);
|
||||
|
||||
const handleError = () => {
|
||||
setError(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<img
|
||||
src={error || !imgSrc ? fallbackSrc : imgSrc}
|
||||
onError={handleError}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,192 @@
|
||||
// src/components/common/ParliamentLayout.tsx
|
||||
import React, { useLayoutEffect } from 'react';
|
||||
import { assetBaseUrl } from '../../apiService';
|
||||
import { handleImageFallback } from './imageFallback';
|
||||
|
||||
// Interfaces (no cambian)
|
||||
interface SeatFillData {
|
||||
color: string;
|
||||
// Añadimos la propiedad opcional 'ocupante'
|
||||
ocupante?: {
|
||||
nombreOcupante: string;
|
||||
fotoUrl: string | null;
|
||||
} | null;
|
||||
}
|
||||
|
||||
interface ParliamentLayoutProps {
|
||||
seatData: SeatFillData[];
|
||||
size?: number;
|
||||
presidenteBancada?: { color: string | null } | null;
|
||||
}
|
||||
|
||||
const PRESIDENTE_SEAT_INDEX = 91;
|
||||
|
||||
export const ParliamentLayout: React.FC<ParliamentLayoutProps> = ({
|
||||
seatData,
|
||||
size = 400,
|
||||
presidenteBancada,
|
||||
}) => {
|
||||
// HOOK DE IMAGENES POR DEFECTO
|
||||
useLayoutEffect(() => {
|
||||
// Se ejecuta después de que el componente y el tooltip se hayan renderizado
|
||||
handleImageFallback('.seat-tooltip img', `${assetBaseUrl}/default-avatar.png`);
|
||||
}, [seatData, presidenteBancada]); // Dependencias: se vuelve a ejecutar si estos datos cambian
|
||||
const uniqueColors = [...new Set(seatData.map(d => d.color))];
|
||||
|
||||
// --- ARRAY DE ELEMENTOS ORDENADO ---
|
||||
const seatElements = [
|
||||
<circle key="seat-0" id="seat-0" r="12" cy="268.306" cx="202.26" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-1" id="seat-1" r="12" cy="214.247" cx="223.62" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-2" id="seat-2" r="12" cy="253.417" cx="184.047" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-3" id="seat-3" r="12" cy="290.475" cx="148.465" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-4" id="seat-4" r="12" cy="199.221" cx="204.812" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-5" id="seat-5" r="12" cy="238.165" cx="165.39" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-6" id="seat-6" r="12" cy="274.606" cx="129.053" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-7" id="seat-7" r="12" cy="307.801" cx="95.891" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-8" id="seat-8" r="12" cy="184.139" cx="184.653" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-9" id="seat-9" r="12" cy="223.156" cx="147.029" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-10" id="seat-10" r="12" cy="259.444" cx="110.504" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-11" id="seat-11" r="12" cy="291.519" cx="75.175" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-12" id="seat-12" r="12" cy="169.647" cx="164.36" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-13" id="seat-13" r="12" cy="209.251" cx="125.789" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-14" id="seat-14" r="12" cy="246.564" cx="88.133" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-15" id="seat-15" r="12" cy="280.15" cx="51.596" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-16" id="seat-16" r="12" cy="157.248" cx="142.356" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-17" id="seat-17" r="12" cy="197.635" cx="103.42" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-18" id="seat-18" r="12" cy="238.303" cx="63.378" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-19" id="seat-19" r="12" cy="145.84" cx="118.145" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-20" id="seat-20" r="12" cy="187.919" cx="77.562" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-21" id="seat-21" r="12" cy="137.535" cx="91.746" transform="matrix(-0.632908, 0.774227, 0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-22" id="seat-22" r="12" cy="123.093" cx="-70.302" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-23" id="seat-23" r="12" cy="143.999" cx="-118.288" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-24" id="seat-24" r="12" cy="163.733" cx="-163.582" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-25" id="seat-25" r="12" cy="183.347" cx="-208.602" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-26" id="seat-26" r="12" cy="102.267" cx="-85.471" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-27" id="seat-27" r="12" cy="125.122" cx="-134.967" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-28" id="seat-28" r="12" cy="145.407" cx="-182.84" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-29" id="seat-29" r="12" cy="167.585" cx="-230.037" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-30" id="seat-30" r="12" cy="82.48" cx="-104.338" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-31" id="seat-31" r="12" cy="108.082" cx="-153.63" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-32" id="seat-32" r="12" cy="132.154" cx="-203.666" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-33" id="seat-33" r="12" cy="160.283" cx="-255.056" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-34" id="seat-34" r="12" cy="66.206" cx="-124.894" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-35" id="seat-35" r="12" cy="93.477" cx="-175.808" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-36" id="seat-36" r="12" cy="121.335" cx="-226.656" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-37" id="seat-37" r="12" cy="51.554" cx="-147.409" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-38" id="seat-38" r="12" cy="82.117" cx="-199.609" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-39" id="seat-39" r="12" cy="114.844" cx="-252.766" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-40" id="seat-40" r="12" cy="39.969" cx="-171.147" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-41" id="seat-41" r="12" cy="74.003" cx="-224.493" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-42" id="seat-42" r="12" cy="30.215" cx="-197.157" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-43" id="seat-43" r="12" cy="68.323" cx="-249.04" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-44" id="seat-44" r="12" cy="22.948" cx="-223.55" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="seat-45" id="seat-45" r="12" cy="22.948" cx="328.246" />,
|
||||
<circle key="seat-46" id="seat-46" r="12" cy="68.323" cx="302.756" />,
|
||||
<circle key="seat-47" id="seat-47" r="12" cy="114.844" cx="299.029" />,
|
||||
<circle key="seat-48" id="seat-48" r="12" cy="160.283" cx="296.74" />,
|
||||
<circle key="seat-49" id="seat-49" r="12" cy="30.215" cx="354.639" />,
|
||||
<circle key="seat-50" id="seat-50" r="12" cy="74.003" cx="327.303" />,
|
||||
<circle key="seat-51" id="seat-51" r="12" cy="121.335" cx="325.14" />,
|
||||
<circle key="seat-52" id="seat-52" r="12" cy="167.585" cx="321.759" />,
|
||||
<circle key="seat-53" id="seat-53" r="12" cy="39.969" cx="380.649" />,
|
||||
<circle key="seat-54" id="seat-54" r="12" cy="82.117" cx="352.187" />,
|
||||
<circle key="seat-55" id="seat-55" r="12" cy="132.154" cx="348.129" />,
|
||||
<circle key="seat-56" id="seat-56" r="12" cy="183.347" cx="343.194" />,
|
||||
<circle key="seat-57" id="seat-57" r="12" cy="51.554" cx="404.387" />,
|
||||
<circle key="seat-58" id="seat-58" r="12" cy="93.477" cx="375.988" />,
|
||||
<circle key="seat-59" id="seat-59" r="12" cy="145.407" cx="368.956" />,
|
||||
<circle key="seat-60" id="seat-60" r="12" cy="66.206" cx="426.902" />,
|
||||
<circle key="seat-61" id="seat-61" r="12" cy="108.082" cx="398.166" />,
|
||||
<circle key="seat-62" id="seat-62" r="12" cy="163.733" cx="388.214" />,
|
||||
<circle key="seat-63" id="seat-63" r="12" cy="82.48" cx="447.457" />,
|
||||
<circle key="seat-64" id="seat-64" r="12" cy="125.122" cx="416.829" />,
|
||||
<circle key="seat-65" id="seat-65" r="12" cy="102.267" cx="466.325" />,
|
||||
<circle key="seat-66" id="seat-66" r="12" cy="143.999" cx="433.508" />,
|
||||
<circle key="seat-67" id="seat-67" r="12" cy="123.093" cx="481.494" />,
|
||||
<circle key="seat-68" id="seat-68" r="12" cy="-289.68" cx="440.983" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-69" id="seat-69" r="12" cy="-239.296" cx="426.798" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-70" id="seat-70" r="12" cy="-188.912" cx="412.614" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-71" id="seat-71" r="12" cy="-147.065" cx="400.833" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-72" id="seat-72" r="12" cy="-281.375" cx="467.381" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-73" id="seat-73" r="12" cy="-229.58" cx="452.656" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-74" id="seat-74" r="12" cy="-180.651" cx="437.369" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-75" id="seat-75" r="12" cy="-135.696" cx="424.411" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-76" id="seat-76" r="12" cy="-269.967" cx="491.592" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-77" id="seat-77" r="12" cy="-217.964" cx="475.026" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-78" id="seat-78" r="12" cy="-167.771" cx="459.741" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-79" id="seat-79" r="12" cy="-119.414" cx="445.127" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-80" id="seat-80" r="12" cy="-257.568" cx="513.597" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-81" id="seat-81" r="12" cy="-204.059" cx="496.265" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-82" id="seat-82" r="12" cy="-152.609" cx="478.289" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-83" id="seat-83" r="12" cy="-243.076" cx="533.889" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-84" id="seat-84" r="12" cy="-189.049" cx="514.627" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-85" id="seat-85" r="12" cy="-136.74" cx="497.701" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-86" id="seat-86" r="12" cy="-227.994" cx="554.048" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-87" id="seat-87" r="12" cy="-173.798" cx="533.284" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-88" id="seat-88" r="12" cy="-212.968" cx="572.857" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-89" id="seat-89" r="12" cy="-158.909" cx="551.496" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-90" id="seat-90" r="12" cy="-197.942" cx="591.665" transform="matrix(0.632908, 0.774227, -0.774227, 0.632908, 0, 0)" />,
|
||||
<circle key="seat-91" id="seat-91" r="12" cy="308.5" cx="-275.898" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
];
|
||||
|
||||
// Creamos una copia mutable de los datos de asientos para poder modificarla.
|
||||
const finalSeatData = [...seatData];
|
||||
|
||||
// Si hay un presidente y su partido tiene bancas, le quitamos una para asignarla.
|
||||
if (presidenteBancada && presidenteBancada.color) {
|
||||
const lastSeatIndex = finalSeatData.map(s => s.color).lastIndexOf(presidenteBancada.color);
|
||||
if (lastSeatIndex !== -1) {
|
||||
finalSeatData.splice(lastSeatIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const renderedElements = seatElements.map((child, index) => {
|
||||
// --- CASO ESPECIAL: ASIENTO PRESIDENCIAL ---
|
||||
if (presidenteBancada && index === PRESIDENTE_SEAT_INDEX) {
|
||||
return React.cloneElement(child, {
|
||||
fill: presidenteBancada.color || '#A9A9A9',
|
||||
stroke: '#000000',
|
||||
strokeWidth: 2,
|
||||
'data-tooltip-id': 'seat-tooltip'
|
||||
});
|
||||
}
|
||||
|
||||
// --- 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: 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 || `${assetBaseUrl}/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' }}>
|
||||
<defs>
|
||||
{uniqueColors.map(color => {
|
||||
const patternId = `stripes-${color.replace('#', '')}`;
|
||||
return (
|
||||
<pattern key={patternId} id={patternId} patternUnits="userSpaceOnUse" width="4" height="4" patternTransform="rotate(45)">
|
||||
<rect width="4" height="4" fill={color}></rect>
|
||||
<path d="M-1,1 l2,-2 M0,4 l4,-4 M3,5 l2,-2" stroke="rgba(255,255,255,0.7)" strokeWidth="3"></path>
|
||||
</pattern>
|
||||
);
|
||||
})}
|
||||
</defs>
|
||||
<g transform="matrix(1, 0, 0, 1, 1.166021, 0.583011)">
|
||||
{renderedElements}
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
147
Elecciones-Web/frontend/src/components/common/SenateLayout.tsx
Normal file
147
Elecciones-Web/frontend/src/components/common/SenateLayout.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
// src/components/common/SenateLayout.tsx
|
||||
import React, { useLayoutEffect } from 'react';
|
||||
import { handleImageFallback } from './imageFallback';
|
||||
import { assetBaseUrl } from '../../apiService';
|
||||
|
||||
// Interfaces
|
||||
interface SeatFillData {
|
||||
color: string;
|
||||
// Añadimos la propiedad opcional 'ocupante'
|
||||
ocupante?: {
|
||||
nombreOcupante: string;
|
||||
fotoUrl: string | null;
|
||||
} | null;
|
||||
}
|
||||
|
||||
interface SenateLayoutProps {
|
||||
seatData: SeatFillData[];
|
||||
size?: number;
|
||||
presidenteBancada?: { color: string | null } | null;
|
||||
}
|
||||
|
||||
const PRESIDENTE_SEAT_INDEX = 45; // El último asiento (índice 45 de 46)
|
||||
|
||||
export const SenateLayout: React.FC<SenateLayoutProps> = ({
|
||||
seatData,
|
||||
size = 400,
|
||||
presidenteBancada,
|
||||
}) => {
|
||||
// HOOK DE IMAGENES POR DEFECTO
|
||||
useLayoutEffect(() => {
|
||||
// Se ejecuta después de que el componente y el tooltip se hayan renderizado
|
||||
handleImageFallback('.seat-tooltip img', `${assetBaseUrl}/default-avatar.png`);
|
||||
}, [seatData, presidenteBancada]); // Dependencias: se vuelve a ejecutar si estos datos cambian
|
||||
|
||||
const uniqueColors = [...new Set(seatData.map(d => d.color).filter(Boolean))];
|
||||
|
||||
// --- NUEVO ARRAY DE ELEMENTOS ORDENADO PARA EL SENADO ---
|
||||
const seatElements = [
|
||||
<circle key="senate-seat-0" id="senate-seat-0" r="9" cy="354.956" cx="-121.933" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-1" id="senate-seat-1" r="9" cy="354.956" cx="-164.933" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-2" id="senate-seat-2" r="9" cy="331.318" cx="-121.933" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-3" id="senate-seat-3" r="9" cy="333.318" cx="-164.933" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-4" id="senate-seat-4" r="9" cy="307.598" cx="-121.933" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-5" id="senate-seat-5" r="9" cy="312.598" cx="-164.933" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-6" id="senate-seat-6" r="9" cy="285.358" cx="-121.933" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-7" id="senate-seat-7" r="9" cy="292.358" cx="-164.933" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-8" id="senate-seat-8" r="9" cy="292.358" cx="-206.672" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-9" id="senate-seat-9" r="9" cy="261.241" cx="-121.933" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-10" id="senate-seat-10" r="9" cy="269.241" cx="-165.933" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-11" id="senate-seat-11" r="9" cy="268.057" cx="-208.672" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-12" id="senate-seat-12" r="9" cy="184.514" cx="327.2" transform="matrix(-0.986454, -0.16404, -0.16404, 0.986454, 488.237, 84.441)" />,
|
||||
<circle key="senate-seat-13" id="senate-seat-13" r="9" cy="246.521" cx="-170.309" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-14" id="senate-seat-14" r="9" cy="184.514" cx="327.2" transform="matrix(-0.986454, -0.16404, -0.16404, 0.986454, 507.83, 65.575)" />,
|
||||
<circle key="senate-seat-15" id="senate-seat-15" r="9" cy="229.407" cx="-183.766" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-16" id="senate-seat-16" r="9" cy="184.514" cx="327.2" transform="matrix(-0.986454, -0.16404, -0.16404, 0.986454, 528.776, 52.17)" />,
|
||||
<circle key="senate-seat-17" id="senate-seat-17" r="9" cy="217.294" cx="-201.175" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-18" id="senate-seat-18" r="9" cy="252.557" cx="-227.172" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-19" id="senate-seat-19" r="9" cy="170.401" cx="311.791" transform="matrix(-0.986454, -0.16404, -0.16404, 0.986454, 535.427, 55.561)" />,
|
||||
<circle key="senate-seat-20" id="senate-seat-20" r="9" cy="211.882" cx="-223.172" transform="matrix(-1, 0, 0, 1, 0, 0)" />,
|
||||
<circle key="senate-seat-21" id="senate-seat-21" r="9" cy="159.989" cx="295.143" transform="matrix(-0.986454, -0.16404, -0.16404, 0.986454, 540.544, 61.56)" />,
|
||||
<circle key="senate-seat-22" id="senate-seat-22" r="9" cy="159.989" cx="295.143" transform="matrix(0.986454, -0.16404, 0.16404, 0.986454, -54.66, 61.555)" />,
|
||||
<circle key="senate-seat-23" id="senate-seat-23" r="9" cy="211.882" cx="262.728" />,
|
||||
<circle key="senate-seat-24" id="senate-seat-24" r="9" cy="252.557" cx="258.729" />,
|
||||
<circle key="senate-seat-25" id="senate-seat-25" r="9" cy="170.401" cx="311.791" transform="matrix(0.986454, -0.16404, 0.16404, 0.986454, -49.543, 55.556)" />,
|
||||
<circle key="senate-seat-26" id="senate-seat-26" r="9" cy="217.294" cx="284.726" />,
|
||||
<circle key="senate-seat-27" id="senate-seat-27" r="9" cy="184.514" cx="327.2" transform="matrix(0.986454, -0.16404, 0.16404, 0.986454, -42.892, 52.164)" />,
|
||||
<circle key="senate-seat-28" id="senate-seat-28" r="9" cy="184.514" cx="327.2" transform="matrix(0.986454, -0.16404, 0.16404, 0.986454, -21.946, 65.569)" />,
|
||||
<circle key="senate-seat-29" id="senate-seat-29" r="9" cy="229.407" cx="302.134" />,
|
||||
<circle key="senate-seat-30" id="senate-seat-30" r="9" cy="268.057" cx="277.228" />,
|
||||
<circle key="senate-seat-31" id="senate-seat-31" r="9" cy="184.514" cx="327.2" transform="matrix(0.986454, -0.16404, 0.16404, 0.986454, -2.353, 84.436)" />,
|
||||
<circle key="senate-seat-32" id="senate-seat-32" r="9" cy="246.521" cx="315.591" />,
|
||||
<circle key="senate-seat-33" id="senate-seat-33" r="9" cy="184.514" cx="327.2" transform="matrix(0.986454, -0.16404, 0.16404, 0.986454, 8.933, 107.941)" />,
|
||||
<circle key="senate-seat-34" id="senate-seat-34" r="9" cy="269.241" cx="319.968" />,
|
||||
<circle key="senate-seat-35" id="senate-seat-35" r="9" cy="292.358" cx="279.228" />,
|
||||
<circle key="senate-seat-36" id="senate-seat-36" r="9" cy="261.241" cx="363.968" />,
|
||||
<circle key="senate-seat-37" id="senate-seat-37" r="9" cy="292.358" cx="320.968" />,
|
||||
<circle key="senate-seat-38" id="senate-seat-38" r="9" cy="285.358" cx="363.968" />,
|
||||
<circle key="senate-seat-39" id="senate-seat-39" r="9" cy="312.598" cx="320.968" />,
|
||||
<circle key="senate-seat-40" id="senate-seat-40" r="9" cy="307.598" cx="363.968" />,
|
||||
<circle key="senate-seat-41" id="senate-seat-41" r="9" cy="333.318" cx="320.968" />,
|
||||
<circle key="senate-seat-42" id="senate-seat-42" r="9" cy="331.318" cx="363.968" />,
|
||||
<circle key="senate-seat-43" id="senate-seat-43" r="9" cy="354.956" cx="320.968" />,
|
||||
<circle key="senate-seat-44" id="senate-seat-44" r="9" cy="354.956" cx="363.968" />,
|
||||
<circle key="senate-seat-45" id="senate-seat-45" r="9" cy="347.619" cx="243.841" />,
|
||||
];
|
||||
|
||||
// Creamos una copia mutable de los datos de asientos para poder modificarla.
|
||||
const finalSeatData = [...seatData];
|
||||
|
||||
// Si hay un presidente y su partido tiene bancas, le quitamos una para asignarla.
|
||||
if (presidenteBancada && presidenteBancada.color) {
|
||||
const lastSeatIndex = finalSeatData.map(s => s.color).lastIndexOf(presidenteBancada.color);
|
||||
if (lastSeatIndex !== -1) {
|
||||
finalSeatData.splice(lastSeatIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const renderedElements = seatElements.map((child, index) => {
|
||||
// --- CASO ESPECIAL: ASIENTO PRESIDENCIAL ---
|
||||
if (presidenteBancada && index === PRESIDENTE_SEAT_INDEX) {
|
||||
return React.cloneElement(child, {
|
||||
fill: presidenteBancada.color || '#A9A9A9',
|
||||
stroke: '#000000',
|
||||
strokeWidth: 2,
|
||||
'data-tooltip-id': 'seat-tooltip'
|
||||
});
|
||||
}
|
||||
|
||||
// --- 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: 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 || `${assetBaseUrl}/default-avatar.png`}" alt="${seat.ocupante.nombreOcupante}" /><p>${seat.ocupante.nombreOcupante}</p></div>`
|
||||
: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<svg viewBox="73.512 141.174 338.86 280.338" width={size} height={size * (280.338 / 338.86)} style={{ display: 'block', margin: 'auto' }}>
|
||||
<defs>
|
||||
{uniqueColors.map(color => {
|
||||
const patternId = `stripes-${color.replace('#', '')}`;
|
||||
return (
|
||||
<pattern key={patternId} id={patternId} patternUnits="userSpaceOnUse" width="4" height="4" patternTransform="rotate(45)">
|
||||
<rect width="4" height="4" fill={color}></rect>
|
||||
<path d="M-1,1 l2,-2 M0,4 l4,-4 M3,5 l2,-2" stroke="rgba(255,255,255,0.7)" strokeWidth="3"></path>
|
||||
</pattern>
|
||||
);
|
||||
})}
|
||||
</defs>
|
||||
<g>
|
||||
{renderedElements}
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
// src/components/common/imageFallback.ts
|
||||
|
||||
export function handleImageFallback(selector: string, fallbackImageUrl: string) {
|
||||
// Le decimos a TypeScript que el resultado será una lista de elementos de imagen HTML
|
||||
const images: NodeListOf<HTMLImageElement> = document.querySelectorAll(selector);
|
||||
|
||||
images.forEach(img => {
|
||||
// Ahora que 'img' es de tipo HTMLImageElement, TypeScript sabe que 'onerror' y 'src' son válidos.
|
||||
img.onerror = () => {
|
||||
img.src = fallbackImageUrl;
|
||||
};
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user