// VIP auto-cycling deal display. // A new discount tier "unlocks" every 48 hours, computed automatically // from the current time -- runs forever, for a month or a year, with no // calendar to maintain. Uses the same HTML block as before, so if you // already set up vip-daily-drop.html, no changes needed there. This // script replaces vip-daily-drop.js. // // SETUP IN CHECKFRONT: create these three as standing discount codes, // ONCE, no date restriction needed. Being visible only on your gated // VIP page is the actual access control here, same as everything else // we discussed -- not a Checkfront date rule. // VRGH-A7K2 - 30% off // VRGH-B4M9 - 40% off // VRGH-C8XQ - 50% off // // HOW IT PICKS: time is divided into 48-hour blocks since the Unix // epoch. Which of the three codes shows is worked out from that block // number using a simple repeatable formula -- not truly random, but it // looks varied, and everyone visiting during the same 48-hour window // sees the same tier, which is what makes the Checkfront code actually // valid for them. (function () { 'use strict'; var BOOKING_BASE_URL = 'https://vrgamehouse.checkfront.com/reserve/'; var CYCLE_HOURS = 48; var CYCLE_MS = CYCLE_HOURS * 60 * 60 * 1000; var TIERS = [ { code: 'VRGH-A7K2', discount: '30% off' }, { code: 'VRGH-B4M9', discount: '40% off' }, { code: 'VRGH-C8XQ', discount: '50% off' } ]; function pad(n) { return String(n).padStart(2, '0'); } function currentCycleIndex() { return Math.floor(Date.now() / CYCLE_MS); } // Deterministic, not cryptographic -- only needs to look varied and // land on the same tier for everyone during the same 48-hour window. function pickTierForCycle(cycleIndex) { var x = Math.sin(cycleIndex * 12.9898) * 43758.5453; var frac = x - Math.floor(x); var index = Math.floor(frac * TIERS.length); return TIERS[index]; } function msUntilNextCycle(cycleIndex) { var cycleEnd = (cycleIndex + 1) * CYCLE_MS; return cycleEnd - Date.now(); } function formatCountdown(ms) { if (ms < 0) ms = 0; var totalSeconds = Math.floor(ms / 1000); var hours = Math.floor(totalSeconds / 3600); var minutes = Math.floor((totalSeconds % 3600) / 60); var seconds = totalSeconds % 60; return pad(hours) + ':' + pad(minutes) + ':' + pad(seconds); } var lastCycleIndex = null; function tick() { var cycleIndex = currentCycleIndex(); if (cycleIndex !== lastCycleIndex) { lastCycleIndex = cycleIndex; var tier = pickTierForCycle(cycleIndex); var codeEl = document.querySelector('[data-vip-code]'); var discountEl = document.querySelector('[data-vip-discount]'); var statusEl = document.querySelector('[data-vip-status]'); var bookLinkEl = document.querySelector('[data-vip-book-link]'); if (codeEl) codeEl.textContent = tier.code; if (discountEl) discountEl.textContent = tier.discount; if (statusEl) statusEl.textContent = 'This deal refreshes automatically'; if (bookLinkEl) { bookLinkEl.href = BOOKING_BASE_URL + '?discount=' + encodeURIComponent(tier.code); } } var timerEl = document.querySelector('[data-vip-timer]'); if (timerEl) timerEl.textContent = formatCountdown(msUntilNextCycle(cycleIndex)); } tick(); setInterval(tick, 1000); })();