Cart timer script

User
create 20 min timer when ever user visit on buy.php and afater 20 min complete all local storgae should clear Even if user closed the broswer and come agai and if 20 min complete then clear the previous cart in js
Assistant
Got it—here’s a drop-in JS snippet that:

– starts a **20-minute cart timer** every time someone lands on `buy.php`
– shows how to **update a countdown** (optional)
– **clears localStorage (your cart keys)** the moment 20 min elapse
– also clears on **re-open** after 20 min or across **multiple tabs** (via `storage` event)

<script>
/**
 * Cart Timer (20 minutes) for buy.php
 * - Creates a deadline on first visit (persists in localStorage).
 * - Clears cart/localStorage immediately when 20 minutes pass.
 * - Works across browser close/reopen and across tabs.
 */

(function () {
  // Only run on buy.php (safety guard if this script is global)
  if (!//buy.php(?|$)/i.test(location.pathname + location.search)) return;

  // ---- CONFIG ----
  const DURATION_MS = 20 * 60 * 1000; // 20 minutes
  const DEADLINE_KEY = 'fos_cart_deadline_ts';
  // Add your cart/localStorage keys here:
  const CART_KEYS = [
    'orderData',
    'cart',
    'tickets',
    'addOns',
    'selectedEventDateString',
    // add any other keys you use…
  ];

  // OPTIONAL: Provide a selector to show countdown text (e.g., "#cart-timer")
  const COUNTDOWN_EL_SELECTOR = '#cart-timer';

  // ---- HELPERS ----
  function now() { return Date.now(); }

  function readDeadline() {
    const v = localStorage.getItem(DEADLINE_KEY);
    const n = v ? parseInt(v, 10) : NaN;
    return Number.isFinite(n) ? n : null;
  }

  function writeDeadline(ts) {
    localStorage.setItem(DEADLINE_KEY, String(ts));
  }

  function clearCartAndDeadline(reason = '') {
    try {
      // Clear your cart-related keys only (safer than wiping all localStorage)
      CART_KEYS.forEach(k => localStorage.removeItem(k));
      localStorage.removeItem(DEADLINE_KEY);
      // If you really want to nuke ALL localStorage on this origin, uncomment:
      // localStorage.clear();

      // Also broadcast a signal for other tabs (optional)
      localStorage.setItem('fos_cart_last_clear', String(Date.now()));
      console.log('[CartTimer] Cleared cart due to:', reason || 'deadline reached');
    } catch (e) {
      console.warn('[CartTimer] Clear error:', e);
    }
  }

  function ensureDeadline() {
    let dl = readDeadline();
    if (!dl) {
      dl = now() + DURATION_MS;
      writeDeadline(dl);
      console.log('[CartTimer] New deadline set:', new Date(dl).toISOString());
    }
    return dl;
  }

  function timeLeft(deadlineTs) {
    return Math.max(0, deadlineTs - now());
  }

  function scheduleAutoClear(deadlineTs) {
    const ms = timeLeft(deadlineTs);
    if (ms <= 0) {
      clearCartAndDeadline('expired on load');
      return;
    }
    // Clear right at the deadline
    window.setTimeout(() => {
      // Double-check in case user extended or page clock drifted
      const latest = readDeadline();
      if (latest && now() >= latest) {
        clearCartAndDeadline('expired on timeout');
        // (Optionally) refresh page or redirect:
        // location.reload();
      }
    }, ms);
  }

  // OPTIONAL: Simple countdown UI updater (MM:SS)
  function startCountdown(deadlineTs) {
    const el = document.querySelector(COUNTDOWN_EL_SELECTOR);
    if (!el) return;

    const tick = () => {
      const left = timeLeft(deadlineTs);
      const mm = Math.floor(left / 60000);
      const ss = Math.floor((left % 60000) / 1000);
      el.textContent = (mm < 10 ? '0' : '') + mm + ':' + (ss < 10 ? '0' : '') + ss;

      if (left <= 0) {
        // Force clear + update UI once more
        clearCartAndDeadline('expired on countdown');
        el.textContent = '00:00';
        // location.reload(); // optional
        return;
      }
      requestAnimationFrame(() => setTimeout(tick, 250)); // smooth-ish update without hammering
    };
    tick();
  }

  // Keep tabs in sync: if another tab clears, reflect here
  window.addEventListener('storage', (e) => {
    // If deadline changed/removed or we received a clear signal
    if (e.key === DEADLINE_KEY || e.key === 'fos_cart_last_clear') {
      const dl = readDeadline();
      if (!dl || now() >= dl) {
        clearCartAndDeadline('sync from other tab');
        // location.reload(); // optional
      }
    }
  });

  // ---- RUN ----
  const deadline = ensureDeadline();
  scheduleAutoClear(deadline);
  startCountdown(deadline);
})();
</script>

### How it works (quick notes)
– On first visit to `buy.php`, it creates and stores a **deadline timestamp** in `localStorage`.
– Every load checks the timestamp.
– If **already expired** (e.g., you closed the browser for >20 min), it **immediately clears** your cart keys.
– If **not expired**, it sets a `setTimeout` to clear exactly at the deadline.
– A **`storage`** event listener keeps multiple tabs/windows in sync.
– You control **which keys** to clear via `CART_KEYS`.

If you also need to clear a **server-side cart/session**, call your API inside `clearCartAndDeadline()` as well.

User
first give me 20 min timer code
Assistant
Here’s a **simple 20-minute timer in plain JavaScript** 👇

<div id="timer"></div>

<script>
// 20 minutes in milliseconds
const DURATION = 20 * 60 * 1000; 

// Get deadline (20 min from now)
const deadline = Date.now() + DURATION;

function updateTimer() {
  const now = Date.now();
  let remaining = deadline - now;

  if (remaining <= 0) {
    document.getElementById("timer").textContent = "00:00";
    clearInterval(timerInterval);
    alert("⏰ Time's up!"); // action after 20 min
    return;
  }

  const minutes = Math.floor(remaining / 1000 / 60);
  const seconds = Math.floor((remaining / 1000) % 60);

  document.getElementById("timer").textContent =
    `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
}

// update immediately + then every second
updateTimer();
const timerInterval = setInterval(updateTimer, 1000);
</script>

✅ This will show a countdown like **19:59 → 00:00**.
✅ After 20 minutes it runs whatever logic you put in place of `alert(…)`.

Do you want me to extend this so it **persists even if the user closes and reopens the browser** (using `localStorage`), or keep it as a simple on-page timer?

User
make id=timer to class so that can use in several places
Assistant
Got it 👍 — here’s the same **20-minute countdown timer**, but using a **class** (`.timer`) so you can show it in multiple places at once:

<div class="timer"></div>
<div class="timer"></div>
<div class="timer"></div>

<script>
// 20 minutes in milliseconds
const DURATION = 20 * 60 * 1000;

// Create a single deadline for all timers
const deadline = Date.now() + DURATION;

function updateTimers() {
  const now = Date.now();
  let remaining = deadline - now;

  if (remaining <= 0) {
    document.querySelectorAll(".timer").forEach(el => {
      el.textContent = "00:00";
    });
    clearInterval(timerInterval);
    alert("⏰ Time's up!");
    return;
  }

  const minutes = Math.floor(remaining / 1000 / 60);
  const seconds = Math.floor((remaining / 1000) % 60);

  const formatted = `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;

  document.querySelectorAll(".timer").forEach(el => {
    el.textContent = formatted;
  });
}

// Update immediately + every second
updateTimers();
const timerInterval = setInterval(updateTimers, 1000);
</script>

👉 Now every `.timer` element on the page will stay in sync and display the same countdown.

Do you also want me to make this **persist across browser refresh/close** (so if the user reopens `buy.php`, it continues from where it left), or just keep this simple session-only version?

User
once timer start it will stay not restart on page referesh so use localstorage
Assistant
Perfect 👍 — we’ll make the **20-minute countdown persistent** by saving the deadline in `localStorage`.
That way, if the user refreshes or closes/reopens the page, the timer continues from where it left, and when time’s up, all `.timer` elements show `00:00`.

Here’s the code:

<div class="timer"></div>
<div class="timer"></div>

<script>
(function () {
  const DURATION = 20 * 60 * 1000; // 20 minutes
  const DEADLINE_KEY = "cart_deadline"; // localStorage key

  // Get deadline from localStorage or set new
  let deadline = localStorage.getItem(DEADLINE_KEY);
  if (!deadline) {
    deadline = Date.now() + DURATION;
    localStorage.setItem(DEADLINE_KEY, deadline);
  } else {
    deadline = parseInt(deadline, 10);
  }

  function updateTimers() {
    const now = Date.now();
    let remaining = deadline - now;

    if (remaining <= 0) {
      document.querySelectorAll(".timer").forEach(el => {
        el.textContent = "00:00";
      });
      clearInterval(timerInterval);

      // Clear storage after time up
      localStorage.removeItem(DEADLINE_KEY);

      alert("⏰ Time's up!");
      return;
    }

    const minutes = Math.floor(remaining / 1000 / 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const formatted =
      `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;

    document.querySelectorAll(".timer").forEach(el => {
      el.textContent = formatted;
    });
  }

  // Start ticking
  updateTimers();
  const timerInterval = setInterval(updateTimers, 1000);
})();
</script>

✅ On first visit, it sets a deadline (now + 20 min).
✅ On refresh/reopen, it reads the same deadline and resumes countdown.
✅ Once 20 min passes, it clears the deadline from `localStorage`, shows `00:00`, and you can also clear cart keys there.

Do you want me to also plug in the **cart clear logic** right inside this timer (so localStorage cart data is automatically wiped at expiry)?

User
Now we have localStorage.setItem('fossettsOrderData', JSON.stringify(orderData));
also I want to clear fossettsOrderData once 20 min complete and order not procssed give me updated code only I will relace
Assistant
Here’s the **updated timer code** that will also clear
`fossettsOrderData` after 20 minutes (if order not processed):

<script>
(function () {
  const DURATION = 20 * 60 * 1000; // 20 minutes
  const DEADLINE_KEY = "cart_deadline"; // deadline key in storage
  const ORDER_KEY = "fossettsOrderData"; // your order data key

  // Get deadline from localStorage or set new
  let deadline = localStorage.getItem(DEADLINE_KEY);
  if (!deadline) {
    deadline = Date.now() + DURATION;
    localStorage.setItem(DEADLINE_KEY, deadline);
  } else {
    deadline = parseInt(deadline, 10);
  }

  function updateTimers() {
    const now = Date.now();
    let remaining = deadline - now;

    if (remaining <= 0) {
      document.querySelectorAll(".timer").forEach(el => {
        el.textContent = "00:00";
      });
      clearInterval(timerInterval);

      // Clear deadline + order data
      localStorage.removeItem(DEADLINE_KEY);
      localStorage.removeItem(ORDER_KEY);

      console.log("⏰ Time's up — fossettsOrderData cleared");
      return;
    }

    const minutes = Math.floor(remaining / 1000 / 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const formatted =
      `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;

    document.querySelectorAll(".timer").forEach(el => {
      el.textContent = formatted;
    });
  }

  // Start ticking
  updateTimers();
  const timerInterval = setInterval(updateTimers, 1000);
})();
</script>

👉 Just replace your old timer block with this one.
This will **wipe `fossettsOrderData`** from `localStorage` when 20 minutes expire.

Do you also want me to add a safeguard so that if the user **closes the browser and comes back after 20+ minutes**, it immediately clears `fossettsOrderData` on page load (not just after ticking)?

User
when timer complerter after clear everything redirect to home page
Assistant
Here’s the **final version** — clears `fossettsOrderData`, removes the timer, and then redirects the user to the home page after 20 minutes:

<script>
(function () {
  const DURATION = 20 * 60 * 1000; // 20 minutes
  const DEADLINE_KEY = "cart_deadline"; // deadline key
  const ORDER_KEY = "fossettsOrderData"; // order data key

  // Get deadline from localStorage or set new
  let deadline = localStorage.getItem(DEADLINE_KEY);
  if (!deadline) {
    deadline = Date.now() + DURATION;
    localStorage.setItem(DEADLINE_KEY, deadline);
  } else {
    deadline = parseInt(deadline, 10);
  }

  function updateTimers() {
    const now = Date.now();
    let remaining = deadline - now;

    if (remaining <= 0) {
      document.querySelectorAll(".timer").forEach(el => {
        el.textContent = "00:00";
      });
      clearInterval(timerInterval);

      // Clear deadline + order data
      localStorage.removeItem(DEADLINE_KEY);
      localStorage.removeItem(ORDER_KEY);

      console.log("⏰ Time's up — cleared fossettsOrderData and redirecting…");

      // Redirect to home page
      window.location.href = "/";
      return;
    }

    const minutes = Math.floor(remaining / 1000 / 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const formatted =
      `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;

    document.querySelectorAll(".timer").forEach(el => {
      el.textContent = formatted;
    });
  }

  // Start ticking
  updateTimers();
  const timerInterval = setInterval(updateTimers, 1000);
})();
</script>

✅ On first visit, timer starts (20 min).
✅ If user refreshes, it continues from where it left.
✅ When 20 minutes pass:
– `fossettsOrderData` is cleared
– deadline is removed
– user is **redirected to the home page `/`**

Do you want the redirect to happen **instantly at 20 minutes**, or should I add a short delay (like 2–3 seconds) after clearing to let the user see `"00:00"`?

User
User sees "Cart expired" message

Option to refresh and start over

Assistant
<script>
(function () {
  const DURATION = 20 * 60 * 1000; // 20 minutes
  const DEADLINE_KEY = "cart_deadline";
  const ORDER_KEY = "fossettsOrderData";

  // --- UI: show "Cart expired" with restart option ---
  function showExpiryUI() {
    // Set all visible timers to 00:00
    document.querySelectorAll(".timer").forEach(el => (el.textContent = "00:00"));

    // Create a lightweight overlay/banner
    const wrap = document.createElement("div");
    wrap.setAttribute("id", "cart-expired-wrap");
    wrap.style.position = "fixed";
    wrap.style.inset = "0";
    wrap.style.background = "rgba(0,0,0,0.55)";
    wrap.style.display = "flex";
    wrap.style.alignItems = "center";
    wrap.style.justifyContent = "center";
    wrap.style.zIndex = "9999";

    const box = document.createElement("div");
    box.style.background = "#fff";
    box.style.padding = "20px 24px";
    box.style.borderRadius = "12px";
    box.style.maxWidth = "420px";
    box.style.width = "92%";
    box.style.textAlign = "center";
    box.style.boxShadow = "0 10px 30px rgba(0,0,0,0.2)";

    const title = document.createElement("div");
    title.textContent = "Cart expired";
    title.style.fontSize = "20px";
    title.style.fontWeight = "700";
    title.style.marginBottom = "8px";

    const msg = document.createElement("div");
    msg.textContent = "Your 20-minute hold has ended. Refresh to start over.";
    msg.style.fontSize = "14px";
    msg.style.color = "#444";
    msg.style.marginBottom = "16px";

    const btn = document.createElement("button");
    btn.textContent = "Refresh & start over";
    btn.style.padding = "10px 16px";
    btn.style.border = "none";
    btn.style.borderRadius = "8px";
    btn.style.cursor = "pointer";
    btn.style.fontWeight = "600";
    btn.style.fontSize = "14px";
    btn.style.background = "#111";
    btn.style.color = "#fff";
    btn.onclick = function () {
      // on reload, a new deadline will be created
      window.location.reload();
    };

    box.appendChild(title);
    box.appendChild(msg);
    box.appendChild(btn);
    wrap.appendChild(box);
    document.body.appendChild(wrap);
  }

  function clearExpiredCart() {
    try {
      localStorage.removeItem(DEADLINE_KEY);
      localStorage.removeItem(ORDER_KEY);
    } catch (e) {
      console.warn("Failed to clear storage:", e);
    }
  }

  function expireNow() {
    clearExpiredCart();
    showExpiryUI();
  }

  // --- Deadline bootstrapping (persistent across refresh) ---
  let deadline = parseInt(localStorage.getItem(DEADLINE_KEY) || "", 10);
  const nowTs = Date.now();

  if (!Number.isFinite(deadline)) {
    // First visit (no deadline yet)
    deadline = nowTs + DURATION;
    localStorage.setItem(DEADLINE_KEY, String(deadline));
  }

  // If already expired (e.g., user came back after >20 min), expire immediately
  if (nowTs >= deadline) {
    expireNow();
    return;
  }

  // --- Timer tick for all .timer elements ---
  function updateTimers() {
    const now = Date.now();
    const remaining = Math.max(0, deadline - now);

    if (remaining === 0) {
      clearInterval(tick);
      expireNow();
      return;
    }

    const minutes = Math.floor(remaining / 60000);
    const seconds = Math.floor((remaining % 60000) / 1000);
    const formatted =
      `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;

    document.querySelectorAll(".timer").forEach(el => (el.textContent = formatted));
  }

  // Kick off the ticking loop
  updateTimers();
  const tick = setInterval(updateTimers, 1000);
})();
</script>
User
I want timer to persisit even user close the browser and repopen
Assistant
<script>
(function () {
  // Run only on buy.php
  if (!//buy.php(?|$)/i.test(location.pathname + location.search)) return;

  const DURATION = 20 * 60 * 1000; // 20 minutes
  const DEADLINE_KEY = "cart_deadline";
  const ORDER_KEY = "fossettsOrderData";
  const CLEAR_SIGNAL = "fos_cart_last_clear"; // broadcasts to other tabs

  function showExpiryUI() {
    document.querySelectorAll(".timer").forEach(el => (el.textContent = "00:00"));

    const wrap = document.createElement("div");
    wrap.id = "cart-expired-wrap";
    Object.assign(wrap.style, {
      position: "fixed", inset: "0", background: "rgba(0,0,0,0.55)",
      display: "flex", alignItems: "center", justifyContent: "center", zIndex: "9999"
    });

    const box = document.createElement("div");
    Object.assign(box.style, {
      background: "#fff", padding: "20px 24px", borderRadius: "12px",
      maxWidth: "420px", width: "92%", textAlign: "center",
      boxShadow: "0 10px 30px rgba(0,0,0,0.2)"
    });

    const title = document.createElement("div");
    title.textContent = "Cart expired";
    Object.assign(title.style, { fontSize: "20px", fontWeight: "700", marginBottom: "8px" });

    const msg = document.createElement("div");
    msg.textContent = "Your 20-minute hold has ended. Refresh to start over.";
    Object.assign(msg.style, { fontSize: "14px", color: "#444", marginBottom: "16px" });

    const btn = document.createElement("button");
    btn.textContent = "Refresh & start over";
    Object.assign(btn.style, {
      padding: "10px 16px", border: "none", borderRadius: "8px",
      cursor: "pointer", fontWeight: "600", fontSize: "14px",
      background: "#111", color: "#fff"
    });
    btn.onclick = function () { window.location.reload(); };

    box.appendChild(title);
    box.appendChild(msg);
    box.appendChild(btn);
    wrap.appendChild(box);
    document.body.appendChild(wrap);
  }

  function clearExpiredCart() {
    try {
      localStorage.removeItem(DEADLINE_KEY);
      localStorage.removeItem(ORDER_KEY);
      // notify other tabs
      localStorage.setItem(CLEAR_SIGNAL, String(Date.now()));
    } catch (e) {
      console.warn("Failed to clear storage:", e);
    }
  }

  function expireNow() {
    clearExpiredCart();
    showExpiryUI();
  }

  // Bootstrap persistent deadline
  let deadline = parseInt(localStorage.getItem(DEADLINE_KEY) || "", 10);
  const nowTs = Date.now();

  if (!Number.isFinite(deadline)) {
    // First visit: set a deadline that persists across refresh/close/reopen
    deadline = nowTs + DURATION;
    localStorage.setItem(DEADLINE_KEY, String(deadline));
  } else if (nowTs >= deadline) {
    // Already expired while the browser was closed or on another tab
    expireNow();
    return;
  }

  function format(remainingMs) {
    const m = Math.floor(remainingMs / 60000);
    const s = Math.floor((remainingMs % 60000) / 1000);
    return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
  }

  function render() {
    const remaining = Math.max(0, deadline - Date.now());
    if (remaining === 0) {
      clearInterval(tick);
      expireNow();
      return;
    }
    const display = format(remaining);
    document.querySelectorAll(".timer").forEach(el => (el.textContent = display));
  }

  // Start ticking and keep timers in sync
  render();
  const tick = setInterval(render, 1000);

  // Cross-tab sync: if another tab clears or modifies deadline, expire here too
  window.addEventListener("storage", (e) => {
    if (e.key === DEADLINE_KEY || e.key === CLEAR_SIGNAL) {
      const dl = parseInt(localStorage.getItem(DEADLINE_KEY) || "", 10);
      if (!Number.isFinite(dl) || Date.now() >= dl) {
        clearInterval(tick);
        expireNow();
      }
    }
  });
})();
</script>

Leave a Comment

Your email address will not be published. Required fields are marked *