// src/apiService.ts import axios from 'axios'; import type { ApiResponseRankingMunicipio, ApiResponseRankingSeccion, ApiResponseTablaDetallada, ProyeccionBancas, MunicipioSimple, TelegramaData, CatalogoItem, CategoriaResumen, ResultadoTicker, ApiResponseResultadosPorSeccion, PanelElectoralDto, ResumenProvincia, CategoriaResumenHome } from './types/types'; /** * URL base para las llamadas a la API. * - En desarrollo, apunta directamente al backend de .NET. * - En producción, apunta al endpoint público de la API. */ export const API_BASE_URL = import.meta.env.DEV ? 'http://localhost:5217/api' : 'https://elecciones2025.eldia.com/api'; /** * URL base para los activos estáticos (imágenes, etc.) de la carpeta `public`. * - En desarrollo, es una ruta relativa a la raíz (servida por Vite). * - En producción, es la URL absoluta del dominio donde se alojan los widgets. */ export const assetBaseUrl = import.meta.env.DEV ? '' : 'https://elecciones2025.eldia.com'; const apiClient = axios.create({ baseURL: API_BASE_URL, headers: { 'Content-Type': 'application/json' }, }); interface PartidoData { id: string; nombre: string; nombreCorto: string | null; bancasTotales: number; color: string | null; } interface CamaraData { camaraNombre: string; totalBancas: number; bancasEnJuego: number; partidos: PartidoData[]; presidenteBancada: { color: string | null } | null; } export interface ComposicionData { diputados: CamaraData; senadores: CamaraData; } export interface OcupanteBanca { id: number; nombreOcupante: string; fotoUrl: string | null; periodo: string | null; } interface PartidoData { id: string; nombre: string; nombreCorto: string | null; bancasTotales: number; color: string | null; ocupantes: OcupanteBanca[]; } export interface BancadaDetalle { id: number; // Este es el ID de la Bancada camara: number; // 0 o 1 numeroBanca: number; agrupacionPoliticaId: string | null; ocupante: OcupanteBanca | null; } export interface ConfiguracionPublica { TickerResultadosCantidad?: string; ConcejalesResultadosCantidad?: string; } export interface ResultadoDetalleSeccion { id: string; // ID de la agrupación para la key nombre: string; votos: number; porcentaje: number; color: string | null; } export interface PartidoComposicionNacional { id: string; nombre: string; nombreCorto: string | null; color: string | null; bancasFijos: number; bancasGanadas: number; bancasTotales: number; ordenDiputadosNacionales: number | null; ordenSenadoresNacionales: number | null; } export interface CamaraComposicionNacional { camaraNombre: string; totalBancas: number; bancasEnJuego: number; partidos: PartidoComposicionNacional[]; presidenteBancada: { color: string | null; tipoBanca: 'ganada' | 'previa' | null } | null; ultimaActualizacion: string; } export interface ComposicionNacionalData { diputados: CamaraComposicionNacional; senadores: CamaraComposicionNacional; } export interface ResumenParams { focoDistritoId?: string; focoCategoriaId?: number; cantidadResultados?: number; } export const getResumenProvincial = async (eleccionId: number): Promise => { const response = await apiClient.get(`/elecciones/${eleccionId}/provincia/02`); return response.data; }; export const getBancasPorSeccion = async (eleccionId: number, seccionId: string, camara: 'diputados' | 'senadores'): Promise => { const { data } = await apiClient.get(`/elecciones/${eleccionId}/bancas-por-seccion/${seccionId}/${camara}`); return data; }; /** * Obtiene la lista de Secciones Electorales desde la API. */ export const getSeccionesElectorales = async (categoriaId?: number): Promise => { let url = '/catalogos/secciones-electorales'; // Si se proporciona una categoría, la añadimos a la URL if (categoriaId) { url += `?categoriaId=${categoriaId}`; } const response = await apiClient.get(url); return response.data; }; /** * Obtiene los datos completos de un telegrama por su ID de mesa. */ export const getTelegramaPorId = async (mesaId: string): Promise => { const response = await apiClient.get(`/telegramas/${mesaId}`); return response.data; }; export const getSecciones = async (): Promise => { const response = await apiClient.get('/catalogos/secciones'); return response.data; }; export const getMunicipiosPorSeccion = async (seccionId: string): Promise => { const response = await apiClient.get(`/catalogos/municipios/${seccionId}`); return response.data; }; export const getCircuitosPorMunicipio = async (municipioId: string): Promise => { const response = await apiClient.get(`/catalogos/circuitos/${municipioId}`); return response.data; }; export const getEstablecimientosPorCircuito = async (circuitoId: string): Promise => { const response = await apiClient.get(`/catalogos/establecimientos/${circuitoId}`); return response.data; }; export const getMesasPorEstablecimiento = async (establecimientoId: string): Promise => { const response = await apiClient.get(`/catalogos/mesas/${establecimientoId}`); return response.data; }; export const getComposicionCongreso = async (eleccionId: number): Promise => { const response = await apiClient.get(`/elecciones/${eleccionId}/composicion-congreso`); return response.data; }; export const getBancadasDetalle = async (eleccionId: number): Promise => { const response = await apiClient.get(`/elecciones/${eleccionId}/bancadas-detalle`); return response.data; }; export const getConfiguracionPublica = async (): Promise => { const response = await apiClient.get('/resultados/configuracion-publica'); return response.data; }; export const getResultadosPorSeccion = async (eleccionId: number, seccionId: string, categoriaId: number): Promise => { const response = await apiClient.get(`/elecciones/${eleccionId}/seccion-resultados/${seccionId}?categoriaId=${categoriaId}`); return response.data; }; export const getDetalleSeccion = async (eleccionId: number, seccionId: string, categoriaId: number): Promise => { const response = await apiClient.get(`/elecciones/${eleccionId}/seccion/${seccionId}?categoriaId=${categoriaId}`); return response.data; }; export const getResultadosPorMunicipio = async (eleccionId: number, municipioId: string, categoriaId: number): Promise => { const response = await apiClient.get(`/elecciones/${eleccionId}/partido/${municipioId}?categoriaId=${categoriaId}`); return response.data.resultados; }; export const getMunicipios = async (categoriaId?: number): Promise => { let url = '/catalogos/municipios'; if (categoriaId) { url += `?categoriaId=${categoriaId}`; } const response = await apiClient.get(url); // --- CORRECCIÓN --- // La API devuelve un array de objetos con las propiedades { id, nombre }. // Ya no es necesario mapear. Simplemente devolvemos los datos como vienen. return response.data; }; export const getSeccionesElectoralesConCargos = async (): Promise => { // Hacemos la petición al nuevo endpoint del backend const { data } = await apiClient.get('/resultados/secciones-electorales-con-cargos'); return data; }; export const getResultadosTablaDetallada = async (seccionId: string): Promise => { const { data } = await apiClient.get(`/resultados/tabla-ranking-seccion/${seccionId}`); return data; }; export const getRankingResultadosPorSeccion = async (seccionId: string): Promise => { const { data } = await apiClient.get(`/resultados/ranking-por-seccion/${seccionId}`); return data; }; export const getRankingMunicipiosPorSeccion = async (seccionId: string): Promise => { const { data } = await apiClient.get(`/resultados/ranking-municipios-por-seccion/${seccionId}`); return data; }; export const getEstablecimientosPorMunicipio = async (municipioId: string): Promise => { const response = await apiClient.get(`/catalogos/establecimientos-por-municipio/${municipioId}`); return response.data; }; export const getPanelElectoral = async (eleccionId: number, ambitoId: string | null, categoriaId: number): Promise => { // Construimos la URL base let url = ambitoId ? `/elecciones/${eleccionId}/panel/${ambitoId}` : `/elecciones/${eleccionId}/panel`; // Añadimos categoriaId como un query parameter url += `?categoriaId=${categoriaId}`; const { data } = await apiClient.get(url); return data; }; export const getComposicionNacional = async (eleccionId: number): Promise => { const { data } = await apiClient.get(`/elecciones/${eleccionId}/composicion-nacional`); return data; }; // 11. Endpoint para el widget de tarjetas nacionales export const getResumenPorProvincia = async (eleccionId: number, params: ResumenParams = {}): Promise => { // Usamos URLSearchParams para construir la query string de forma segura y limpia const queryParams = new URLSearchParams(); if (params.focoDistritoId) { queryParams.append('focoDistritoId', params.focoDistritoId); } if (params.focoCategoriaId) { queryParams.append('focoCategoriaId', params.focoCategoriaId.toString()); } if (params.cantidadResultados) { queryParams.append('cantidadResultados', params.cantidadResultados.toString()); } const queryString = queryParams.toString(); // Añadimos la query string a la URL solo si tiene contenido const url = `/elecciones/${eleccionId}/resumen-por-provincia${queryString ? `?${queryString}` : ''}`; const { data } = await apiClient.get(url); return data; }; export const getHomeResumen = async (eleccionId: number, distritoId: string, categoriaId: number): Promise => { const queryParams = new URLSearchParams({ eleccionId: eleccionId.toString(), distritoId: distritoId, categoriaId: categoriaId.toString(), }); const url = `/elecciones/home-resumen?${queryParams.toString()}`; const { data } = await apiClient.get(url); return data; };