Skip to main content

Spin & Win 🎁

Enter your details, spin the wheel, and claim your reward.

(() => { const API_URL = "https://bliss-spin-api.abednassar665.workers.dev"; const KEY_USER = "bliss_user_v1"; const KEY_SPIN = "bliss_spin_v1"; const KEY_SESSION = "bliss_session_id_v1"; const COOLDOWN_MS = 24 * 60 * 60 * 1000; const leadForm = document.getElementById("leadForm"); const formMsg = document.getElementById("formMsg"); const wheelCard = document.getElementById("wheelCard"); const wheel = document.getElementById("wheel"); const spinBtn = document.getElementById("spinBtn"); const spinMsg = document.getElementById("spinMsg"); const cooldownMsg = document.getElementById("cooldownMsg"); if (!leadForm || !wheelCard || !wheel || !spinBtn) return; // stops silent blank screens const prizes = [ { name: "Free Coffee", weight: 1 }, { name: "Free Refill", weight: 4 }, { name: "50% Off", weight: 2 }, { name: "20% Off", weight: 6 }, { name: "10% Off", weight: 10 }, { name: "5% Off", weight: 20 } ]; const labelsEl = document.getElementById("wheelLabels"); const sliceDeg = 360 / prizes.length; function buildLabels() { if (!labelsEl) return; labelsEl.innerHTML = ""; for (let i = 0; i < prizes.length; i++) { const angle=i * sliceDeg + sliceDeg/ 2; const el=document.createElement("div"); el.className="wheelLabel" ; el.textContent=prizes[i].name; el.style.maxWidth="120px" ; el.style.textAlign="center" ; el.style.transform=`rotate(${angle}deg) translate(95px, -10px) translate(-50%, -50%)`; labelsEl.appendChild(el); } } function loadJSON(k) { try { return JSON.parse(localStorage.getItem(k) || "null"); } catch { return null; } } function saveJSON(k, v) { localStorage.setItem(k, JSON.stringify(v)); } function pickWeighted(items) { const total=items.reduce((a, b)=> a + b.weight, 0); let r = Math.random() * total; for (const it of items) { r -= it.weight; if (r <= 0) return it.name; } return items[0].name; } function formatTimeLeft(ms) { const mins=Math.ceil(ms/ 60000); const hrs=Math.floor(mins/ 60); const rem=mins % 60; if (hrs<= 0) return `${mins} min`; return rem=== 0 ? `${hrs} hr` : `${hrs} hr ${rem} min`; } function getSessionId() { let v=localStorage.getItem(KEY_SESSION); if (!v) { v=(crypto && crypto.randomUUID) ? crypto.randomUUID() : ("sess_" + Math.random().toString(16).slice(2)); localStorage.setItem(KEY_SESSION, v); } return v; } async function saveSpinToDB(user, prize) { await fetch(API_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ first_name: user.first_name, last_name: user.last_name || null, phone: user.phone, prize, sessionId: getSessionId() }) }); } function refreshUI() { const user=loadJSON(KEY_USER); const last=loadJSON(KEY_SPIN); if (user) { wheelCard.style.display="block" ; formMsg.textContent=`Saved βœ… Welcome, ${user.first_name}.`; } else { wheelCard.style.display="none" ; formMsg.textContent="" ; return; } spinMsg.textContent="" ; cooldownMsg.textContent="" ; spinBtn.disabled=false; if (last && last.ts) { const elapsed=Date.now() - last.ts; if (elapsed< COOLDOWN_MS) { spinBtn.disabled=true; cooldownMsg.textContent=`Already played. Come back in ${formatTimeLeft(COOLDOWN_MS - elapsed)}.`; spinMsg.textContent=`Last win: ${last.prize}`; } } } leadForm.addEventListener("submit", (e)=> { e.preventDefault(); formMsg.textContent = ""; const fd = new FormData(leadForm); const first = (fd.get("first_name") || "").trim(); const last = (fd.get("last_name") || "").trim(); const phone = (fd.get("phone") || "").trim(); if (!first) { formMsg.textContent = "First name is required."; return; } if (!phone) { formMsg.textContent = "Phone number is required."; return; } saveJSON(KEY_USER, { first_name: first, last_name: last, phone, created_at: Date.now() }); refreshUI(); wheelCard.scrollIntoView({ behavior: "smooth", block: "start" }); }); let spinning = false; spinBtn.addEventListener("click", () => { if (spinning) return; const user = loadJSON(KEY_USER); if (!user) return; const last = loadJSON(KEY_SPIN); if (last && last.ts && (Date.now() - last.ts) < COOLDOWN_MS) { refreshUI(); return; } spinning=true; spinBtn.disabled=true; spinMsg.textContent="Spinning…" ; const prize=pickWeighted(prizes); const extraTurns=6; const randomDeg=Math.floor(Math.random() * 360); wheel.style.transform=`rotate(${extraTurns * 360 + randomDeg}deg)`; setTimeout(async ()=> { saveJSON(KEY_SPIN, { prize, ts: Date.now() }); spinMsg.textContent = `You won: ${prize} πŸŽ‰`; try { await saveSpinToDB(user, prize); } catch (err) { console.error("DB save failed:", err); } spinning = false; refreshUI(); }, 4100); }); buildLabels(); refreshUI(); })();