Initial commit: Proyecto Portal ePromos completo con documentación unificada y seguridad base

This commit is contained in:
Isaac Aracena
2026-05-09 12:46:24 -04:00
commit c44f1a69f1
65 changed files with 7223 additions and 0 deletions
+160
View File
@@ -0,0 +1,160 @@
(function () {
const ruleta = document.getElementById("ruleta");
const puntero = document.getElementById("puntero");
// Modal confirmación
const confirmModal = document.getElementById("confirm-modal");
const confirmYes = document.getElementById("confirm-yes");
const confirmNo = document.getElementById("confirm-no");
// Modal agradecimiento
const thankModal = document.getElementById("thank-you-modal");
const thankTitle = document.getElementById("thank-you-message");
const thankDetails = document.getElementById("thank-you-details");
const thankCloseBtn = document.getElementById("redirect-button");
// Fullscreen
const fullscreenBtn = document.getElementById("fullscreen-btn");
let gira = 0;
let articuloGanador = "";
let estaGirando = false;
const params = new URLSearchParams(window.location.search);
const ruletaId = parseInt(params.get("ruleta_id") || "1", 10) || 1;
// Fallback local (solo si backend no manda ángulos)
const rangosFallback = [
{ articulo: "Freidora de aire", inicio: 330, final: 16 },
{ articulo: "Articulo plastico", inicio: 15, final: 16 },
{ articulo: "Sandwichera", inicio: 150, final: 196 },
{ articulo: "Bandana", inicio: 170, final: 16 },
{ articulo: "Cubeta", inicio: 20, final: 52 },
{ articulo: "Bandana1", inicio: 42, final: 88 },
{ articulo: "Beggin'", inicio: 130, final: 160 },
{ articulo: "Sobre Pro Plan", inicio: 220, final: 232 },
{ articulo: "Plancha", inicio: 150, final: 232 },
{ articulo: "Caldero", inicio: 30, final: 194 },
{ articulo: "Abanico de piso", inicio: 296, final: 328 },
];
function normaliza(a){ return ((a % 360) + 360) % 360; }
function centro(inicio, fin){
const i = normaliza(inicio), f = normaliza(fin);
if (i === f) return i;
if (i < f) return i + (f - i)/2;
const span = 360 - i + f;
return normaliza(i + span/2);
}
function buscarRangoLocal(nombre){
return rangosFallback.find(r => r.articulo.toLowerCase() === String(nombre).toLowerCase());
}
function mostrarConfirmacion(){ confirmModal.style.display = "block"; }
function cerrarConfirmacion(){ confirmModal.style.display = "none"; }
function mostrarAgradecimiento(nombre){
thankTitle.textContent = "🎊🎉¡Felicidades!🎉🎊";
thankDetails.textContent = `🎁 Has ganado "${nombre}" 🎁`;
thankModal.style.display = "flex";
}
function ocultarAgradecimiento(){ thankModal.style.display = "none"; }
function girarA(angulo){
gira = 1440 + normaliza(angulo); // 4 vueltas + objetivo
estaGirando = true;
puntero.style.pointerEvents = "none";
ruleta.style.transition = "all 5s ease-out";
ruleta.style.transform = `rotate(${gira}deg)`;
}
ruleta.addEventListener("transitionend", function () {
ruleta.style.transition = "none";
ruleta.style.transform = `rotate(${normaliza(gira)}deg)`;
estaGirando = false;
puntero.style.pointerEvents = "auto";
lanzarConfeti();
mostrarAgradecimiento(articuloGanador);
});
async function obtenerIP() {
try {
const r = await fetch("https://api.ipify.org?format=json");
const d = await r.json();
return d.ip || "0.0.0.0";
} catch { return "0.0.0.0"; }
}
async function obtenerArticuloGanadorYSpin() {
const userAgent = navigator.userAgent || "unknown";
const ip = await obtenerIP();
try {
const resp = await fetch("api/seleccionar_premio.php", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
user_agent: userAgent,
ip_address: ip,
ruleta_id: ruletaId,
}),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const data = await resp.json();
// data esperado:
// { ok:true, nombre:"X", inicio:120, fin:160 } (inicio/fin opcionales)
articuloGanador = data.nombre || "Premio";
let angulo = null;
if (typeof data.inicio === "number" && typeof data.fin === "number") {
angulo = centro(data.inicio, data.fin);
} else {
const rango = buscarRangoLocal(articuloGanador);
angulo = rango ? centro(rango.inicio, rango.final) : Math.floor(Math.random() * 360);
}
girarA(angulo);
} catch (err) {
console.error("Error al obtener el artículo ganador:", err);
estaGirando = false;
puntero.style.pointerEvents = "auto";
alert("Hubo un problema al obtener el premio. Intenta de nuevo.");
}
}
// Interacciones
puntero.addEventListener("mousedown", function () {
if (estaGirando) return;
mostrarConfirmacion();
});
confirmYes.addEventListener("click", function () {
cerrarConfirmacion();
if (estaGirando) return;
obtenerArticuloGanadorYSpin();
});
confirmNo.addEventListener("click", function () {
cerrarConfirmacion();
});
thankCloseBtn.addEventListener("click", ocultarAgradecimiento);
// Fullscreen
fullscreenBtn.addEventListener("click", () => {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen().catch(console.error);
} else {
document.exitFullscreen().catch(console.error);
}
});
// Confeti
function lanzarConfeti() {
const duration = 4000;
const end = Date.now() + duration;
(function frame() {
confetti({ particleCount: 7, angle: 60, spread: 55, origin: { x: 0 }, scalar: 1.2 });
confetti({ particleCount: 7, angle: 120, spread: 55, origin: { x: 1 }, scalar: 1.2 });
if (Date.now() < end) requestAnimationFrame(frame);
})();
}
})();