208 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			208 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| // src/services/apiService.ts
 | |
| import axios from 'axios';
 | |
| import { triggerLogout } from '../context/authUtils';
 | |
| import type {
 | |
|   CandidatoOverride, AgrupacionPolitica,
 | |
|   UpdateAgrupacionData, Bancada, LogoAgrupacionCategoria,
 | |
|   MunicipioSimple, BancaPrevia, ProvinciaSimple
 | |
| } from '../types';
 | |
| 
 | |
| /**
 | |
|  * URL base para las llamadas a la API.
 | |
|  */
 | |
| const API_URL_BASE = import.meta.env.DEV
 | |
|   ? 'http://localhost:5217/api'
 | |
|   : 'https://elecciones2025.eldia.com/api';
 | |
| 
 | |
| /**
 | |
|  * URL completa para el endpoint de autenticación.
 | |
|  */
 | |
| export const AUTH_API_URL = `${API_URL_BASE}/auth`;
 | |
| 
 | |
| /**
 | |
|  * URL completa para los endpoints de administración.
 | |
|  */
 | |
| export const ADMIN_API_URL = `${API_URL_BASE}/admin`;
 | |
| 
 | |
| // Cliente de API para endpoints de administración (requiere token)
 | |
| const adminApiClient = axios.create({
 | |
|   baseURL: ADMIN_API_URL,
 | |
| });
 | |
| 
 | |
| // Cliente de API para endpoints públicos (no envía token)
 | |
| const apiClient = axios.create({
 | |
|   baseURL: API_URL_BASE,
 | |
|   headers: { 'Content-Type': 'application/json' },
 | |
| });
 | |
| 
 | |
| 
 | |
| // --- INTERCEPTORES (Solo para el cliente de admin) ---
 | |
| adminApiClient.interceptors.request.use(
 | |
|   (config) => {
 | |
|     const token = localStorage.getItem('admin-jwt-token');
 | |
|     if (token) {
 | |
|       config.headers['Authorization'] = `Bearer ${token}`;
 | |
|     }
 | |
|     return config;
 | |
|   },
 | |
|   (error) => Promise.reject(error)
 | |
| );
 | |
| 
 | |
| adminApiClient.interceptors.response.use(
 | |
|   (response) => response,
 | |
|   (error) => {
 | |
|     if (axios.isAxiosError(error) && error.response?.status === 401) {
 | |
|       console.log("Token expirado o inválido. Deslogueando...");
 | |
|       triggerLogout();
 | |
|     }
 | |
|     return Promise.reject(error);
 | |
|   }
 | |
| );
 | |
| 
 | |
| 
 | |
| // --- INTERFACES PARA COMPOSICIÓN NACIONAL (NECESARIAS PARA EL NUEVO MÉTODO) ---
 | |
| 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;
 | |
| }
 | |
| export interface ComposicionNacionalData {
 | |
|   diputados: CamaraComposicionNacional;
 | |
|   senadores: CamaraComposicionNacional;
 | |
| }
 | |
| 
 | |
| 
 | |
| // --- SERVICIOS DE API ---
 | |
| 
 | |
| // 1. Autenticación
 | |
| export interface LoginCredentials { username: string; password: string; }
 | |
| 
 | |
| export const loginUser = async (credentials: LoginCredentials): Promise<string | null> => {
 | |
|   try {
 | |
|     const response = await axios.post(`${AUTH_API_URL}/login`, credentials);
 | |
|     return response.data.token;
 | |
|   } catch (error) {
 | |
|     console.error("Error during login request:", error);
 | |
|     throw error;
 | |
|   }
 | |
| };
 | |
| 
 | |
| // 2. Agrupaciones
 | |
| export const getAgrupaciones = async (): Promise<AgrupacionPolitica[]> => {
 | |
|   const response = await adminApiClient.get('/agrupaciones');
 | |
|   return response.data;
 | |
| };
 | |
| 
 | |
| export const updateAgrupacion = async (id: string, data: UpdateAgrupacionData): Promise<void> => {
 | |
|   await adminApiClient.put(`/agrupaciones/${id}`, data);
 | |
| };
 | |
| 
 | |
| // 3. Ordenamiento de Agrupaciones
 | |
| export const updateOrden = async (camara: 'diputados' | 'senadores' | 'diputados-nacionales' | 'senadores-nacionales', ids: string[]): Promise<void> => {
 | |
|   await adminApiClient.put(`/agrupaciones/orden-${camara}`, ids);
 | |
| };
 | |
| 
 | |
| // 4. Gestión de Bancas
 | |
| export const getBancadas = async (camara: 'diputados' | 'senadores', eleccionId: number): Promise<Bancada[]> => {
 | |
|   const camaraId = (camara === 'diputados') ? 0 : 1;
 | |
|   const response = await adminApiClient.get(`/bancadas/${camaraId}?eleccionId=${eleccionId}`);
 | |
|   return response.data;
 | |
| };
 | |
| 
 | |
| export interface UpdateBancadaData {
 | |
|   agrupacionPoliticaId: string | null;
 | |
|   nombreOcupante: string | null;
 | |
|   fotoUrl: string | null;
 | |
|   periodo: string | null;
 | |
| }
 | |
| 
 | |
| export const updateBancada = async (bancadaId: number, data: UpdateBancadaData): Promise<void> => {
 | |
|   await adminApiClient.put(`/bancadas/${bancadaId}`, data);
 | |
| };
 | |
| 
 | |
| // 5. Configuración General
 | |
| export type ConfiguracionResponse = Record<string, string>;
 | |
| 
 | |
| export const getConfiguracion = async (): Promise<ConfiguracionResponse> => {
 | |
|   const response = await adminApiClient.get('/configuracion');
 | |
|   return response.data;
 | |
| };
 | |
| 
 | |
| export const updateConfiguracion = async (data: Record<string, string>): Promise<void> => {
 | |
|   await adminApiClient.put('/configuracion', data);
 | |
| };
 | |
| 
 | |
| // 6. Logos y Candidatos
 | |
| export const getLogos = async (eleccionId: number): Promise<LogoAgrupacionCategoria[]> => {
 | |
|   const response = await adminApiClient.get(`/logos?eleccionId=${eleccionId}`);
 | |
|   return response.data;
 | |
| };
 | |
| export const updateLogos = async (data: LogoAgrupacionCategoria[]): Promise<void> => {
 | |
|   await adminApiClient.put('/logos', data);
 | |
| };
 | |
| export const getCandidatos = async (eleccionId: number): Promise<CandidatoOverride[]> => {
 | |
|   const response = await adminApiClient.get(`/candidatos?eleccionId=${eleccionId}`);
 | |
|   return response.data;
 | |
| };
 | |
| export const updateCandidatos = async (data: CandidatoOverride[]): Promise<void> => {
 | |
|   await adminApiClient.put('/candidatos', data);
 | |
| };
 | |
| 
 | |
| // 7. Catálogos
 | |
| export const getMunicipiosForAdmin = async (): Promise<MunicipioSimple[]> => {
 | |
|   const response = await adminApiClient.get('/catalogos/municipios');
 | |
|   return response.data;
 | |
| };
 | |
| 
 | |
| // 8. Logging
 | |
| export interface UpdateLoggingLevelData { level: string; }
 | |
| export const updateLoggingLevel = async (data: UpdateLoggingLevelData): Promise<void> => {
 | |
|   await adminApiClient.put(`/logging-level`, data);
 | |
| };
 | |
| 
 | |
| // 9. Bancas Previas
 | |
| export const getBancasPrevias = async (eleccionId: number): Promise<BancaPrevia[]> => {
 | |
|   const response = await adminApiClient.get(`/bancas-previas/${eleccionId}`);
 | |
|   return response.data;
 | |
| };
 | |
| export const updateBancasPrevias = async (eleccionId: number, data: BancaPrevia[]): Promise<void> => {
 | |
|   await adminApiClient.put(`/bancas-previas/${eleccionId}`, data);
 | |
| };
 | |
| 
 | |
| // 10. Obtener Composición Nacional (Endpoint Público)
 | |
| export const getComposicionNacional = async (eleccionId: number): Promise<ComposicionNacionalData> => {
 | |
|   // Este es un endpoint público, por lo que usamos el cliente sin token de admin.
 | |
|   const response = await apiClient.get(`/elecciones/${eleccionId}/composicion-nacional`);
 | |
|   return response.data;
 | |
| };
 | |
| 
 | |
| // Obtenemos las provincias para el selector de ámbito
 | |
| export const getProvinciasForAdmin = async (): Promise<ProvinciaSimple[]> => {
 | |
|   const response = await adminApiClient.get('/catalogos/provincias');
 | |
|   return response.data;
 | |
| };
 | |
| 
 | |
| export interface CreateAgrupacionData {
 | |
|   nombre: string;
 | |
|   nombreCorto: string | null;
 | |
|   color: string | null;
 | |
| }
 | |
| 
 | |
| // Servicio para crear una nueva agrupación
 | |
| export const createAgrupacion = async (data: CreateAgrupacionData): Promise<AgrupacionPolitica> => {
 | |
|   const response = await adminApiClient.post('/agrupaciones', data);
 | |
|   return response.data;
 | |
| }; |