Files
Elecciones-2025/Elecciones-Web/frontend/src/apiService.ts
dmolinari 4dbda0da63 Feat Tabla de Datos Redaccion
- Tabla de Top 2 Conurbano
- Tabla de Top 2 Por Secciones Electorales Bs. As.
2025-10-23 12:31:10 -03:00

350 lines
12 KiB
TypeScript

// src/apiService.ts
import axios from 'axios';
import type {
ApiResponseRankingMunicipio, ApiResponseRankingSeccion,
ApiResponseTablaDetallada, ProyeccionBancas, MunicipioSimple,
TelegramaData, CatalogoItem, CategoriaResumen, ResultadoTicker,
ApiResponseResultadosPorSeccion, PanelElectoralDto, ResumenProvincia,
CategoriaResumenHome, ResultadoFila, ResultadoSeccion
} 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<CategoriaResumen[]> => {
const response = await apiClient.get(`/elecciones/${eleccionId}/provincia/02`);
return response.data;
};
export const getBancasPorSeccion = async (eleccionId: number, seccionId: string, camara: 'diputados' | 'senadores'): Promise<ProyeccionBancas> => {
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<MunicipioSimple[]> => {
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<TelegramaData> => {
const response = await apiClient.get(`/telegramas/${mesaId}`);
return response.data;
};
export const getSecciones = async (): Promise<CatalogoItem[]> => {
const response = await apiClient.get('/catalogos/secciones');
return response.data;
};
export const getMunicipiosPorSeccion = async (seccionId: string): Promise<CatalogoItem[]> => {
const response = await apiClient.get(`/catalogos/municipios/${seccionId}`);
return response.data;
};
export const getCircuitosPorMunicipio = async (municipioId: string): Promise<CatalogoItem[]> => {
const response = await apiClient.get(`/catalogos/circuitos/${municipioId}`);
return response.data;
};
export const getEstablecimientosPorCircuito = async (circuitoId: string): Promise<CatalogoItem[]> => {
const response = await apiClient.get(`/catalogos/establecimientos/${circuitoId}`);
return response.data;
};
export const getMesasPorEstablecimiento = async (establecimientoId: string): Promise<CatalogoItem[]> => {
const response = await apiClient.get(`/catalogos/mesas/${establecimientoId}`);
return response.data;
};
export const getComposicionCongreso = async (eleccionId: number): Promise<ComposicionData> => {
const response = await apiClient.get(`/elecciones/${eleccionId}/composicion-congreso`);
return response.data;
};
export const getBancadasDetalle = async (eleccionId: number): Promise<BancadaDetalle[]> => {
const response = await apiClient.get(`/elecciones/${eleccionId}/bancadas-detalle`);
return response.data;
};
export const getConfiguracionPublica = async (): Promise<ConfiguracionPublica> => {
const response = await apiClient.get('/resultados/configuracion-publica');
return response.data;
};
export const getResultadosPorSeccion = async (eleccionId: number, seccionId: string, categoriaId: number): Promise<ApiResponseResultadosPorSeccion> => {
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<ResultadoDetalleSeccion[]> => {
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<ResultadoTicker[]> => {
const response = await apiClient.get(`/elecciones/${eleccionId}/partido/${municipioId}?categoriaId=${categoriaId}`);
return response.data.resultados;
};
export const getMunicipios = async (categoriaId?: number): Promise<MunicipioSimple[]> => {
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<MunicipioSimple[]> => {
// Hacemos la petición al nuevo endpoint del backend
const { data } = await apiClient.get<MunicipioSimple[]>('/resultados/secciones-electorales-con-cargos');
return data;
};
export const getResultadosTablaDetallada = async (seccionId: string): Promise<ApiResponseTablaDetallada> => {
const { data } = await apiClient.get(`/resultados/tabla-ranking-seccion/${seccionId}`);
return data;
};
export const getRankingResultadosPorSeccion = async (seccionId: string): Promise<ApiResponseRankingSeccion> => {
const { data } = await apiClient.get(`/resultados/ranking-por-seccion/${seccionId}`);
return data;
};
export const getRankingMunicipiosPorSeccion = async (seccionId: string): Promise<ApiResponseRankingMunicipio> => {
const { data } = await apiClient.get(`/resultados/ranking-municipios-por-seccion/${seccionId}`);
return data;
};
export const getEstablecimientosPorMunicipio = async (municipioId: string): Promise<CatalogoItem[]> => {
const response = await apiClient.get(`/catalogos/establecimientos-por-municipio/${municipioId}`);
return response.data;
};
export const getPanelElectoral = async (
eleccionId: number,
ambitoId: string | null,
categoriaId: number,
nivel: 'pais' | 'provincia' | 'municipio'
): Promise<PanelElectoralDto> => {
let url: string;
// Construimos la URL con el prefijo correcto.
if (nivel === 'pais' || !ambitoId) {
url = `/elecciones/${eleccionId}/panel`;
} else if (nivel === 'provincia') {
url = `/elecciones/${eleccionId}/panel/distrito:${ambitoId}`;
} else { // nivel === 'municipio'
url = `/elecciones/${eleccionId}/panel/municipio:${ambitoId}`;
}
url += `?categoriaId=${categoriaId}`;
try {
const { data } = await apiClient.get(url);
return data;
} catch (error) {
if (axios.isAxiosError(error) && error.response?.status === 404) {
console.warn(`API devolvió 404 para ${url}. Devolviendo un estado vacío.`);
return {
ambitoNombre: 'Sin Datos',
mapaData: [],
resultadosPanel: [],
estadoRecuento: { participacionPorcentaje: 0, mesasTotalizadasPorcentaje: 0 },
sinDatos: true,
};
}
throw error;
}
};
export const getComposicionNacional = async (eleccionId: number): Promise<ComposicionNacionalData> => {
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<ResumenProvincia[]> => {
// 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 getMunicipiosPorDistrito = async (distritoId: string): Promise<CatalogoItem[]> => {
const response = await apiClient.get(`/catalogos/municipios-por-distrito/${distritoId}`);
return response.data;
};
export const getHomeResumen = async (eleccionId: number, distritoId: string, categoriaId: number): Promise<CategoriaResumenHome> => {
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;
};
export const getHomeResumenNacional = async (eleccionId: number, categoriaId: number): Promise<CategoriaResumenHome> => {
const queryParams = new URLSearchParams({
eleccionId: eleccionId.toString(),
categoriaId: categoriaId.toString(),
});
const url = `/elecciones/home-resumen-nacional?${queryParams.toString()}`;
const { data } = await apiClient.get(url);
return data;
};
export const getTablaConurbano = async (eleccionId: number): Promise<ResultadoFila[]> => {
const { data } = await apiClient.get(`/elecciones/${eleccionId}/tabla-conurbano`);
return data;
};
export const getTablaSecciones = async (eleccionId: number): Promise<ResultadoSeccion[]> => {
const { data } = await apiClient.get(`/elecciones/${eleccionId}/tabla-secciones`);
return data;
};