// src/features/legislativas/nacionales/components/MapaNacional.tsx import axios from 'axios'; import { Suspense, useState, useEffect, useCallback } from 'react'; // <-- Asegúrate de que useCallback esté importado import { useSuspenseQuery } from '@tanstack/react-query'; import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simple-maps'; import { Tooltip } from 'react-tooltip'; import { API_BASE_URL, assetBaseUrl } from '../../../../apiService'; import type { ResultadoMapaDto, AmbitoGeography } from '../../../../types/types'; import { MapaProvincial } from './MapaProvincial'; const DEFAULT_MAP_COLOR = '#E0E0E0'; const FADED_BACKGROUND_COLOR = '#F0F0F0'; const normalizarTexto = (texto: string = '') => texto.trim().toUpperCase().normalize("NFD").replace(/[\u0300-\u036f]/g, ""); type PointTuple = [number, number]; interface MapaNacionalProps { eleccionId: number; categoriaId: number; nivel: 'pais' | 'provincia' | 'municipio'; nombreAmbito: string; provinciaDistritoId: string | null; onAmbitoSelect: (ambitoId: string, nivel: 'provincia' | 'municipio', nombre: string) => void; onVolver: () => void; } export const MapaNacional = ({ eleccionId, categoriaId, nivel, nombreAmbito, provinciaDistritoId, onAmbitoSelect, onVolver }: MapaNacionalProps) => { const [position, setPosition] = useState({ zoom: 1, center: [-65, -40] as PointTuple }); const { data: mapaDataNacional } = useSuspenseQuery({ queryKey: ['mapaResultados', eleccionId, categoriaId, null], queryFn: async () => { const url = `${API_BASE_URL}/elecciones/${eleccionId}/mapa-resultados?categoriaId=${categoriaId}`; const response = await axios.get(url); return response.data; }, }); const { data: geoDataNacional } = useSuspenseQuery({ queryKey: ['geoDataNacional'], queryFn: () => axios.get(`${assetBaseUrl}/maps/argentina-provincias.topojson`).then(res => res.data), }); const resultadosNacionalesPorNombre = new Map(mapaDataNacional.map(d => [normalizarTexto(d.ambitoNombre), d])); const nombreMunicipioSeleccionado = nivel === 'municipio' ? nombreAmbito : null; // El useEffect para el zoom provincial y nacional sigue siendo correcto. useEffect(() => { if (nivel === 'pais') { setPosition({ zoom: 1, center: [-65, -40] }); } else if (nivel === 'provincia') { setPosition({ zoom: 7, center: [-60.5, -37] }); } // La lógica de centrado en municipio se delega al hijo, que llamará a `handleCalculatedCenter` }, [nivel]); // **LA SOLUCIÓN CLAVE**: Estabilizamos la función que se pasa al hijo. const handleCalculatedCenter = useCallback((center: PointTuple, zoom: number) => { setPosition({ center, zoom }); }, []); // El array de dependencias vacío asegura que la función nunca cambie return (
{nivel !== 'pais' && } false}> {({ geographies }: { geographies: AmbitoGeography[] }) => geographies.map((geo) => { const resultado = resultadosNacionalesPorNombre.get(normalizarTexto(geo.properties.nombre)); const esProvinciaActiva = provinciaDistritoId && resultado?.ambitoId === provinciaDistritoId; return ( resultado && onAmbitoSelect(resultado.ambitoId, 'provincia', resultado.ambitoNombre)} /> ); })} {provinciaDistritoId && ( onAmbitoSelect(ambitoId, 'municipio', nombre)} onCalculatedCenter={handleCalculatedCenter} // Pasamos la función estabilizada nivel={nivel as 'provincia' | 'municipio'} // El cast de tipo sigue siendo necesario y correcto /> )}
); };