Add domme-converters/assets/js/store.js
This commit is contained in:
@@ -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<string, number>} 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;
|
||||
})();
|
||||
Reference in New Issue
Block a user