https://www.clubhipico.cl/carreras/wp-content/themes/chs/assets/js/helpers/pronosticos-api-helper.js
1/** 2 * HELPER: Integración API de Pronósticos 3 * ====================================== 4 * 5 * Este helper gestiona la integración con: 6 * - API NUEVA: /pronosticadores/api/pronosticos/jornada-por-pronosticador 7 * - API LEGACY: /v1/pronosticos/{fecha} (fallback automático) 8 * 9 * CaracterÃsticas: 10 * - Soporta 3-8 pronosticadores dinámicos 11 * - Fallback transparente a API legacy 12 * - Normalización de estructuras de datos 13 * - Manejo de errores robusto 14 * 15 * @version 1.0.0 16 * @author CHS Portal Team 17 */ 18 19(function(window) { 20 'use strict'; 21 22 /** 23 * URL base de la nueva API de pronosticadores 24 */ 25 const API_BASE_URL = 'https://apiweb.clubhipico.cl/pronosticadores/api/pronosticos'; 26 27 /** 28 * URL base de la API legacy (fallback) 29 */ 30 const LEGACY_API_URL = serviceUrl + 'v1/pronosticos'; 31 32 /** 33 * Obtiene pronósticos de toda la jornada 34 * 35 * @param {string} fecha - Fecha en formato YYYY-MM-DD 36 * @returns {Promise<{exito: boolean, datos: Array, esNuevaApi: boolean, error?: string}>} 37 */ 38 async function obtenerPronosticosJornada(fecha) { 39 console.log(`[PronosticosAPI] Obteniendo pronósticos para jornada: ${fecha}`); 40 41 try { 42 // Intentar con la nueva API primero 43 const datosNuevos = await intentarNuevaApi(fecha); 44 45 if (datosNuevos) { 46 console.log('â Pronósticos cargados desde nueva API'); 47 return { 48 exito: true, 49 datos: datosNuevos, 50 esNuevaApi: true 51 }; 52 } 53 54 // Si falla, usar API legacy 55 console.warn('â Intentando con API antigua...'); 56 const datosLegacy = await intentarApiLegacy(fecha); 57 58 console.log('â Pronósticos cargados desde API antigua'); 59 return { 60 exito: true, 61 datos: datosLegacy, 62 esNuevaApi: false 63 }; 64 65 } catch (error) { 66 console.error('â Error al obtener pronósticos:', error); 67 return { 68 exito: false, 69 datos: [], 70 esNuevaApi: false, 71 error: error.message 72 }; 73 } 74 } 75 76 /** 77 * Obtiene pronósticos de una carrera especÃfica 78 * 79 * @param {string} fecha - Fecha en formato YYYY-MM-DD 80 * @param {number} numeroCarrera - Número de carrera 81 * @returns {Promise<{exito: boolean, datos: Array, esNuevaApi: boolean, error?: string}>} 82 */ 83 async function obtenerPronosticosCarrera(fecha, numeroCarrera) { 84 console.log(`[PronosticosAPI] Obteniendo pronósticos para carrera ${numeroCarrera} del ${fecha}`); 85 86 try { 87 // Intentar con la nueva API primero 88 const datosNuevos = await intentarNuevaApi(fecha, numeroCarrera); 89 90 if (datosNuevos) { 91 console.log('â Pronósticos cargados desde nueva API'); 92 return { 93 exito: true, 94 datos: datosNuevos, 95 esNuevaApi: true 96 }; 97 } 98 99 // Si falla, usar API legacy 100 console.warn('â Intentando con API antigua...'); 101 const datosLegacy = await intentarApiLegacy(fecha, numeroCarrera); 102 103 console.log('â Pronósticos cargados desde API antigua'); 104 return { 105 exito: true, 106 datos: datosLegacy, 107 esNuevaApi: false 108 }; 109 110 } catch (error) { 111 console.error('â Error al obtener pronósticos:', error); 112 return { 113 exito: false, 114 datos: [], 115 esNuevaApi: false, 116 error: error.message 117 }; 118 } 119 } 120 121 /** 122 * Intenta obtener datos de la nueva API 123 * @private 124 */ 125 async function intentarNuevaApi(fecha, numeroCarrera = null) { 126 try { 127 const url = `${API_BASE_URL}
127/jornada-por-pronosticador?fecha=${fecha}`; 128 const response = await fetch(url, { 129 method: 'GET', 130 headers: { 131 'Content-Type': 'application/json', 132 'Accept': 'application/json' 133 } 134 }); 135 136 if (!response.ok) { 137 throw new Error(`HTTP ${response.status}: ${response.statusText}`); 138 } 139 140 const resultado = await response.json(); 141 142 // Validar estructura de respuesta 143 if (!resultado.success || !Array.isArray(resultado.data)) { 144 throw new Error('Estructura de respuesta inválida'); 145 } 146 147 // Normalizar y filtrar si es carrera especÃfica 148 return normalizarPronosticos(resultado, numeroCarrera); 149 150 } catch (error) { 151 console.warn('[PronosticosAPI] Nueva API no disponible:', error.message); 152 return null; 153 } 154 } 155 156 /** 157 * Intenta obtener datos de la API legacy 158 * @private 159 */ 160 async function intentarApiLegacy(fecha, numeroCarrera = null) { 161 const url = numeroCarrera 162 ? `${LEGACY_API_URL}/${fecha}/${numeroCarrera}` 163 : `${LEGACY_API_URL}/${fecha}`; 164 165 return new Promise((resolve, reject) => { 166 $.ajax({ 167 type: 'GET', 168 url: url, 169 success: function(response) { 170 try { 171 const datosNormalizados = normalizarPronosticosLegacy(response, numeroCarrera); 172 resolve(datosNormalizados); 173 } catch (error) { 174 reject(error); 175 } 176 }, 177 error: function(xhr, status, error) { 178 reject(new Error(`Error API Legacy: ${error}`)); 179 } 180 }); 181 }); 182 } 183 184 /** 185 * Normaliza datos de la nueva API al formato esperado 186 * @private 187 */ 188 function normalizarPronosticos(resultado, numeroCarrera = null) { 189 if (!resultado.data || !Array.isArray(resultado.data)) { 190 return []; 191 } 192 193 return resultado.data.map(pronosticador => { 194 // Filtrar pronósticos si es carrera especÃfica 195 let pronosticosFiltrados = pronosticador.pronosticos || []; 196 197 if (numeroCarrera) { 198 pronosticosFiltrados = pronosticosFiltrados.filter( 199 p => parseInt(p.nroCarrera) === parseInt(numeroCarrera) 200 ); 201 } 202 203 return { 204 nombre: pronosticador.nombre || '', 205 alias: pronosticador.alias || '', 206 foto: pronosticador.fotoUrl || '', 207 pronosticos: pronosticosFiltrados.map(p => ({ 208 nroCarrera: parseInt(p.nroCarrera), 209 cab1: String(p.cab1), 210 cab2: String(p.cab2), 211 nombreCab1: p.nombreCab1 || '', 212 nombreCab2: p.nombreCab2 || '' 213 })) 214 }; 215 }).filter(p => p.pronosticos.length > 0); 216 } 217 218 /** 219 * Normaliza datos de la API legacy al formato esperado 220 * @private 221 */ 222 function normalizarPronosticosLegacy(response, numeroCarrera = null) { 223 const pronosticadores = []; 224 225 // Mapeo de nombres legacy a formato nuevo 226 const mapeoPronosticadores = { 227 'pronosticos_ariel': { 228 nombre: 'Ariel Gómez', 229 alias: 'ariel', 230 foto: directory_uri + '/web/assets/images/club/ariel.png' 231 }, 232 'pronosticos_felipe': { 233 nombre: 'Felipe Ogrodnik', 234 alias: 'felipe', 235 foto: directory_uri + '/web/assets/images/club/felipe.png' 236 }, 237 'pronosticos_mario': { 238 nombre: 'Mario Valdés', 239 alias: 'mario', 240 foto: directory_uri + '/web/assets/images/club/mario.png' 241 }, 242 'pronosticos_nacho_pacheco': { 243 nombre: 'Ignacio Pacheco', 244 alias: 'nacho_pacheco', 245 foto: 'http://pronosticos.clubhipico.cl/wp-content/uploads/2026/04/WhatsApp-Image-2026-04-22-at-13.37.52-2-242x300.jpeg' 246 }, 247 }; 248 249 // Procesar cada pronosticador
250 Object.keys(mapeoPronosticadores).forEach(key => { 251 if (response[key] && Array.isArray(response[key])) { 252 let pronosticosList = response[key]; 253 254 // Filtrar si es carrera especÃfica 255 if (numeroCarrera) { 256 pronosticosList = pronosticosList.filter( 257 p => parseInt(p.numero_carrera) === parseInt(numeroCarrera) 258 ); 259 } 260 261 if (pronosticosList.length > 0) { 262 pronosticadores.push({ 263 nombre: mapeoPronosticadores[key].nombre, 264 alias: mapeoPronosticadores[key].alias, 265 foto: mapeoPronosticadores[key].foto, 266 pronosticos: pronosticosList.map(p => ({ 267 nroCarrera: parseInt(p.numero_carrera), 268 cab1: String(p.cab1), 269 cab2: String(p.cab2), 270 nombreCab1: p.nombre_cab1 || '', 271 nombreCab2: p.nombre_cab2 || '' 272 })) 273 }); 274 } 275 } 276 }); 277 278 return pronosticadores; 279 } 280 281 /** 282 * Exportar API pública 283 */ 284 window.PronosticosAPI = { 285 obtenerJornada: obtenerPronosticosJornada, 286 obtenerCarrera: obtenerPronosticosCarrera 287 }; 288 289 console.log('[PronosticosAPI] Helper cargado correctamente'); 290 291})(window);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.