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