From 91b57c228075fd68ea91462262b935938baa99f7 Mon Sep 17 00:00:00 2001 From: Ben de Roo Date: Wed, 24 Jun 2026 21:11:21 +0200 Subject: [PATCH] Add domme-converters/assets/js/store.js --- domme-converters/assets/js/store.js | 110 ++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 domme-converters/assets/js/store.js diff --git a/domme-converters/assets/js/store.js b/domme-converters/assets/js/store.js new file mode 100644 index 0000000..666d8a6 --- /dev/null +++ b/domme-converters/assets/js/store.js @@ -0,0 +1,110 @@ +"use strict"; + +/** + * Winkelmandje-store met persistentie in localStorage en een eenvoudig + * publish/subscribe-mechanisme. Alle pagina's delen dezelfde toestand, zodat + * het mandje behouden blijft tijdens het navigeren. + */ +(function () { + const STORAGE_KEY = "converterland.cart.v1"; + const TAX_RATE = 0.21; + + const CL = (window.CL = window.CL || {}); + const products = window.PRODUCTS || []; + const findProduct = (id) => products.find((p) => p.id === id); + + /** @type {Map} product-id -> aantal */ + const cart = new Map(); + const listeners = new Set(); + + function load() { + try { + const raw = localStorage.getItem(STORAGE_KEY); + if (!raw) return; + const entries = JSON.parse(raw); + if (Array.isArray(entries)) { + for (const [id, qty] of entries) { + if (findProduct(id) && Number.isFinite(qty) && qty > 0) { + cart.set(id, Math.floor(qty)); + } + } + } + } catch (err) { + // Beschadigde opslag negeren en met een leeg mandje starten. + } + } + + function persist() { + try { + localStorage.setItem(STORAGE_KEY, JSON.stringify([...cart.entries()])); + } catch (err) { + // Opslag kan geblokkeerd zijn (privémodus); de store werkt dan in-memory. + } + } + + function emit() { + persist(); + for (const fn of listeners) fn(); + } + + const store = { + TAX_RATE, + + subscribe(fn) { + listeners.add(fn); + return () => listeners.delete(fn); + }, + + entries() { + return [...cart.entries()]; + }, + + size() { + return cart.size; + }, + + quantityOf(id) { + return cart.get(id) || 0; + }, + + add(id, amount = 1) { + const product = findProduct(id); + if (!product) return; + cart.set(id, (cart.get(id) || 0) + amount); + emit(); + }, + + setQuantity(id, qty) { + if (!findProduct(id)) return; + if (qty <= 0) cart.delete(id); + else cart.set(id, Math.floor(qty)); + emit(); + }, + + step(id, delta) { + if (!cart.has(id)) return; + this.setQuantity(id, cart.get(id) + delta); + }, + + clear() { + cart.clear(); + emit(); + }, + + totals() { + let count = 0; + let subtotal = 0; + for (const [id, qty] of cart) { + const product = findProduct(id); + if (!product) continue; + count += qty; + subtotal += product.price * qty; + } + const tax = subtotal * TAX_RATE; + return { count, subtotal, tax, total: subtotal + tax }; + }, + }; + + load(); + CL.store = store; +})();