QUINIELA TRG
APP JUGADORES

Validando credenciales...
// ========================================================================= // 🔗 CONEXIÓN CON EL BACKEND (URL INYECTADA) // ========================================================================= const API_URL = "https://script.google.com/macros/s/AKfycbzAMhnZvqvBJbZnlMxRh6uaKXmIHlqptyhdXaFFjhN2j5D4u3W4_M78s_bzny-DhZ5V/exec"; let usuarioActual = ""; let saldoActual = 0; let apuestasLocal = ["","","","","","","","","","","","","","",""]; let partidosGlobal = []; // ========================================================================= // ⚙️ UTILIDADES DE UI // ========================================================================= function loading(show, text="Cargando...") { const l = document.getElementById('loader'); const t = document.getElementById('loaderText'); if (show) { l.classList.remove('hidden'); t.innerText = text; } else { l.classList.add('hidden'); } } async function doFetch(action, payload={}) { payload.action = action; try { let res = await fetch(API_URL, { method: 'POST', body: JSON.stringify(payload) }); return await res.json(); } catch (e) { console.error("Fallo de red:", e); return { error: true, mensaje: "Error de conexión con el servidor." }; } } function switchAppTab(tabId) { document.querySelectorAll('.section').forEach(s => s.classList.remove('active')); document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active')); document.getElementById(tabId).classList.add('active'); if(document.getElementById('nav-' + tabId)) { document.getElementById('nav-' + tabId).classList.add('active'); } } // ========================================================================= // 🔐 SISTEMA DE LOGIN Y ARRANQUE // ========================================================================= window.onload = async function() { let res = await doFetch('obtenerListaJugadores'); let sel = document.getElementById('usuario'); if (res && !res.error && res.jugadores) { sel.innerHTML = ''; res.jugadores.forEach(j => { sel.innerHTML += ``; }); } else { sel.innerHTML = ''; } }; async function intentarLogin() { let user = document.getElementById('usuario').value; let pin = document.getElementById('pin').value; if(!user || !pin) return Swal.fire('Error', 'Selecciona tu usuario e introduce el PIN', 'warning'); loading(true, "Verificando credenciales..."); let res = await doFetch('loginJugador', { usuario: user, pin: pin }); loading(false); if(res && res.exito) { usuarioActual = res.usuario; saldoActual = res.saldo || 0; document.getElementById('loginSec').classList.remove('active'); document.getElementById('mainApp').style.display = 'block'; document.getElementById('bottomNavLiga').style.display = 'flex'; document.getElementById('lblUsuario').innerText = usuarioActual; document.getElementById('lblPerfilNombre').innerText = usuarioActual; document.getElementById('lblPerfilSaldo').innerText = saldoActual; // Cargar datos en 2º plano doFetch('notificarTelegramGranHermano', { usuario: usuarioActual, seccion: 'LOGIN' }); cargarParrilla(); } else { Swal.fire('Acceso Denegado', res.mensaje || 'PIN incorrecto', 'error'); } } // ========================================================================= // ⚽ MOTOR DE QUINIELA Y RENDERIZADO // ========================================================================= async function cargarParrilla() { loading(true, "Cargando partidos de la jornada..."); let res = await doFetch('obtenerEstadoYPartidos', { usuario: usuarioActual }); loading(false); if(res && !res.error) { document.getElementById('lblEstadoJornada').innerText = "ESTADO: " + res.estado; if(res.estado === 'CERRADO') { document.getElementById('lblEstadoJornada').style.color = 'var(--danger)'; document.getElementById('btnSellar').style.display = 'none'; } else { document.getElementById('lblEstadoJornada').style.color = 'var(--success)'; document.getElementById('btnSellar').style.display = 'block'; } partidosGlobal = res.partidos || []; if(res.apuesta) apuestasLocal = res.apuesta; dibujarPartidos(res.estado === 'CERRADO'); } else { Swal.fire('Error', 'No se pudo cargar la jornada', 'error'); } } function dibujarPartidos(bloqueado) { let container = document.getElementById('contenedorPartidos'); let html = ""; let imgDefault = "https://cdn-icons-png.flaticon.com/512/861/861512.png"; for(let i=0; i<14; i++) { let p = partidosGlobal[i]; if(!p) continue; let ap = apuestasLocal[i] || ""; let fch = p.fecha ? p.fecha.replace('T', ' a las ') : "Fecha por definir"; let btnClass1 = (ap==='1') ? 'btn-option selected' : 'btn-option'; let btnClassX = (ap==='X') ? 'btn-option selected' : 'btn-option'; let btnClass2 = (ap==='2') ? 'btn-option selected' : 'btn-option'; let ev = bloqueado ? "" : `onclick="seleccionar(${i},'1')"`; let evX = bloqueado ? "" : `onclick="seleccionar(${i},'X')"`; let ev2 = bloqueado ? "" : `onclick="seleccionar(${i},'2')"`; html += `
Partido ${i+1}${fch}
${p.local}
VS
${p.visitante}
`; } // PLENO AL 15 let p15 = partidosGlobal[14]; if (p15) { let p15_ap = apuestasLocal[14] || ""; let valL = p15_ap.length === 2 ? p15_ap.charAt(0) : "0"; let valV = p15_ap.length === 2 ? p15_ap.charAt(1) : "0"; let fch15 = p15.fecha ? p15.fecha.replace('T', ' a las ') : ""; html += `
⭐ PLENO AL 15 ⭐
${fch15}
${p15.local}
-
${p15.visitante}
GOLES
`; } container.innerHTML = html; } function seleccionar(indice, valor) { apuestasLocal[indice] = valor; document.getElementById(`btn_${indice}_1`).classList.remove('selected'); document.getElementById(`btn_${indice}_X`).classList.remove('selected'); document.getElementById(`btn_${indice}_2`).classList.remove('selected'); document.getElementById(`btn_${indice}_${valor}`).classList.add('selected'); } function actualizarPleno() { let vl = document.getElementById('sel_15_L').value; let vv = document.getElementById('sel_15_V').value; apuestasLocal[14] = vl + vv; } async function sellarBoleto() { let faltan = 0; for(let i=0; i<14; i++) { if(!apuestasLocal[i]) faltan++; } if(!apuestasLocal[14] || apuestasLocal[14].length < 2) faltan++; if(faltan > 0) { let conf = await Swal.fire({ title: 'Boleto Incompleto', text: `Te faltan ${faltan} partidos por pronosticar. ¿Sellar de todos modos?`, icon: 'warning', showCancelButton: true }); if(!conf.isConfirmed) return; } loading(true, "Registrando pronósticos en la base de datos..."); let res = await doFetch('guardarApuesta', { usuario: usuarioActual, apuesta: apuestasLocal }); loading(false); if(res && res.exito) { Swal.fire('¡Boleto Sellado!', 'Tus pronósticos están guardados y seguros.', 'success'); } else { Swal.fire('Error', res.mensaje || 'Hubo un problema al sellar.', 'error'); } } // ========================================================================= // 🔔 NOTIFICACIONES PUSH (FIREBASE HTTP v1) // ========================================================================= const firebaseConfig = { apiKey: "AIzaSyD2LwW...", // Rellenado interno del SDK projectId: "quiniela-trg", messagingSenderId: "123456789", appId: "1:1234:web:abcd" }; firebase.initializeApp(firebaseConfig); const messaging = firebase.messaging(); async function activarCampanitaPush() { try { const permission = await Notification.requestPermission(); if (permission === 'granted') { loading(true, "Enlazando dispositivo..."); const token = await messaging.getToken({ vapidKey: 'BABaTpvVsS1M2Wzq7DvTO_cXf2JqGcziiV8ccUSrJhZz1DaGB_uJoCXBPHquWlvsTF4j0AA8qliCQHr8sMqkt2Y' }); if (token) { let res = await doFetch('registrarTokenPush', { usuario: usuarioActual, token: token }); loading(false); if(res && !res.error) { document.getElementById('btnPush').style.display = 'none'; document.getElementById('msgPushOk').style.display = 'block'; Swal.fire('Activadas', 'Recibirás los avisos de la Liga.', 'success'); } } else { loading(false); Swal.fire('Error', 'Fallo al generar el token.', 'error'); } } else { Swal.fire('Permiso Denegado', 'Debes permitir las notificaciones en tu navegador.', 'warning'); } } catch (error) { loading(false); Swal.fire('No Soportado', 'Tu navegador o dispositivo bloquea esta función nativa.', 'info'); } } window.cargarDirectos = async function() { let container = document.getElementById('contenedor-enlaces-directos'); container.innerHTML = '
Cargando señal...
'; let res = await doFetch('obtenerEnlacesDirectos'); if(res && res.enlaces && res.enlaces.length > 0) { let html = ""; res.enlaces.forEach(lnk => { html += `
${lnk.partido} VER DIRECTO
`; }); container.innerHTML = html; } else { container.innerHTML = '
No hay emisiones en directo en este momento.
'; } }