diff --git a/domme-converters/assets/js/ui.js b/domme-converters/assets/js/ui.js new file mode 100644 index 0000000..fcc4723 --- /dev/null +++ b/domme-converters/assets/js/ui.js @@ -0,0 +1,208 @@ +"use strict"; + +/** + * Globale UI die op elke pagina aanwezig is: winkelmandje-lade, afrekenmodal + * en toast-meldingen. Deze module praat uitsluitend met CL.store, zodat de + * mandjestoestand consistent blijft tijdens het navigeren. + */ +(function () { + const CL = (window.CL = window.CL || {}); + const { formatPrice, escapeHtml } = CL.fmt; + const store = CL.store; + const PRODUCTS = window.PRODUCTS || []; + const findProduct = (id) => PRODUCTS.find((p) => p.id === id); + + const els = {}; + let toastTimer; + + function init() { + els.overlay = document.getElementById("overlay"); + els.drawer = document.getElementById("drawer"); + els.closeCart = document.getElementById("closeCart"); + els.cartItems = document.getElementById("cartItems"); + els.cartSub = document.getElementById("cartSub"); + els.cartTax = document.getElementById("cartTax"); + els.cartTotal = document.getElementById("cartTotal"); + els.checkoutBtn = document.getElementById("checkoutBtn"); + els.modalWrap = document.getElementById("modalWrap"); + els.modalContent = document.getElementById("modalContent"); + els.toast = document.getElementById("toast"); + + els.closeCart.addEventListener("click", closeCart); + els.overlay.addEventListener("click", closeCart); + els.checkoutBtn.addEventListener("click", () => { + if (store.size() === 0) return; + closeCart(); + renderCheckoutForm(); + openModal(); + }); + + // Aantal aanpassen in de lade (delegatie). + els.cartItems.addEventListener("click", (e) => { + const btn = e.target.closest("[data-step]"); + if (btn) store.step(btn.dataset.id, Number(btn.dataset.step)); + }); + + // "Toevoegen" werkt overal: catalogus, productpagina, aanbiedingen. + document.addEventListener("click", (e) => { + const add = e.target.closest("[data-add]"); + if (!add) return; + e.preventDefault(); + const product = findProduct(add.dataset.add); + if (!product) return; + store.add(product.id); + showToast(product.name + " toegevoegd aan het mandje."); + }); + + els.modalWrap.addEventListener("click", (e) => { + if (e.target === els.modalWrap) closeModal(); + }); + document.addEventListener("keydown", (e) => { + if (e.key === "Escape") { closeModal(); closeCart(); } + }); + } + + // Koppelt knoppen die per route opnieuw worden gerenderd (in de header). + function bindHeader() { + const openCartBtn = document.getElementById("openCart"); + if (openCartBtn) openCartBtn.addEventListener("click", openCart); + + const toggle = document.getElementById("navToggle"); + const links = document.getElementById("navLinks"); + if (toggle && links) { + toggle.addEventListener("click", () => { + const open = links.classList.toggle("open"); + toggle.setAttribute("aria-expanded", String(open)); + }); + // Sluit het mobiele menu na een keuze. + links.addEventListener("click", (e) => { + if (e.target.closest("a")) { + links.classList.remove("open"); + toggle.setAttribute("aria-expanded", "false"); + } + }); + } + } + + function updateCartCount() { + const { count } = store.totals(); + document.querySelectorAll("[data-cart-count]").forEach((el) => (el.textContent = String(count))); + } + + function renderCart() { + const { count, subtotal, tax, total } = store.totals(); + els.cartSub.innerHTML = formatPrice(subtotal); + els.cartTax.innerHTML = formatPrice(tax); + els.cartTotal.innerHTML = formatPrice(total); + els.checkoutBtn.disabled = count === 0; + + const entries = store.entries(); + if (entries.length === 0) { + els.cartItems.innerHTML = '
Uw winkelmandje is leeg.
'; + return; + } + + const rows = []; + for (const [id, qty] of entries) { + const p = findProduct(id); + if (!p) continue; + const tile = p.image + ? `` + : escapeHtml(p.from); + rows.push(` +
+ +
+ ${escapeHtml(p.name)} + ${formatPrice(p.price)} per stuk +
+ + ${qty} + +
+
+ ${formatPrice(p.price * qty)} +
+ `); + } + els.cartItems.innerHTML = rows.join(""); + } + + function openCart() { els.overlay.classList.add("open"); els.drawer.classList.add("open"); } + function closeCart() { els.overlay.classList.remove("open"); els.drawer.classList.remove("open"); } + function openModal() { els.modalWrap.classList.add("open"); } + function closeModal() { els.modalWrap.classList.remove("open"); } + + function showToast(message) { + els.toast.textContent = message; + els.toast.classList.add("show"); + clearTimeout(toastTimer); + toastTimer = setTimeout(() => els.toast.classList.remove("show"), 2200); + } + + function renderCheckoutForm() { + const { total } = store.totals(); + els.modalContent.innerHTML = ` +

Afrekenen

+

Dit formulier verwerkt geen gegevens. Ingevoerde waarden worden niet opgeslagen of verzonden.

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+ +

Demonstratieformulier. Er wordt geen betaling uitgevoerd.

+
+ `; + document.getElementById("payForm").addEventListener("submit", (event) => { + event.preventDefault(); + const form = event.currentTarget; + if (!form.checkValidity()) { form.reportValidity(); return; } + renderSuccess(); + }); + } + + function renderSuccess() { + const { count } = store.totals(); + const orderId = "CL-" + Math.floor(100000 + Math.random() * 900000); + els.modalContent.innerHTML = ` +
+ +

Bestelling geregistreerd

+

${count} fictief artikel(en) zijn vastgelegd in deze demonstratie.

+
Referentie: ${escapeHtml(orderId)}
+

Verwachte levering: niet van toepassing.

+ +
+ `; + store.clear(); + document.getElementById("doneBtn").addEventListener("click", () => { + closeModal(); + showToast("Winkelmandje geleegd."); + }); + } + + CL.ui = { init, bindHeader, updateCartCount, renderCart, openCart, closeCart, showToast }; +})();