Files
vans-diy-bastelbedarf/src/scripts/cart.ts
T
qcigano 677104d4a6 Warenkorb: Artikel einzeln zum Kauf auswählen, andere bleiben unverbindlich liegen
Jeder Artikel im Warenkorb hat jetzt eine Checkbox "Jetzt kaufen". Nur
angehakte Artikel zählen zur Zwischensumme, zum Versand, zum Gutschein
und zum Checkout — abgewählte Artikel bleiben sichtbar (leicht
abgedunkelt, mit "Bleibt im Warenkorb, wird noch nicht gekauft"-Hinweis)
im Warenkorb liegen, ohne mitgekauft zu werden. Die Auswahl wird pro
Artikel gespeichert (localStorage) und bleibt bis zur nächsten Änderung
bestehen. Der Checkout übernimmt automatisch nur die ausgewählten
Artikel.

Verifiziert per Puppeteer: Abwählen eines Artikels reduziert Summe/
Rechnungsliste sofort korrekt, Checkout zeigt nur den ausgewählten
Artikel, keine Konsolenfehler.
2026-08-02 20:21:30 +02:00

123 lines
4.1 KiB
TypeScript

// Rein clientseitiger Warenkorb (Phase 1, kein Backend). Speichert im localStorage.
// TODO Phase 2: durch echten Cloudflare-Worker-Warenkorb/Checkout ersetzen.
import { getProduct } from "../data/products";
import { effektiverZeilenpreis } from "../data/rabatt";
import { findeGutschein, gutscheinRabatt, type Gutschein } from "../data/gutscheine";
export interface CartItem {
slug: string;
name: string;
preis: number;
menge: number;
// Ob dieser Artikel gerade gekauft werden soll oder nur "im Warenkorb liegen bleibt" für
// später. Fehlt das Feld (ältere, bereits gespeicherte Warenkörbe), gilt es als ausgewählt —
// siehe istAusgewaehlt().
ausgewaehlt?: boolean;
}
/** true, sofern nicht explizit auf false gesetzt — hält ältere localStorage-Warenkörbe ohne
* dieses Feld weiterhin vollständig "ausgewählt" (kein Verhaltensbruch für Bestandsbesucher). */
export function istAusgewaehlt(item: CartItem): boolean {
return item.ausgewaehlt !== false;
}
const KEY = "vandiy_cart_v1";
export function getCart(): CartItem[] {
if (typeof localStorage === "undefined") return [];
try {
return JSON.parse(localStorage.getItem(KEY) || "[]");
} catch {
return [];
}
}
export function saveCart(items: CartItem[]) {
localStorage.setItem(KEY, JSON.stringify(items));
window.dispatchEvent(new CustomEvent("cart:changed", { detail: items }));
}
export function addToCart(item: Omit<CartItem, "menge">, menge = 1) {
const cart = getCart();
const existing = cart.find((i) => i.slug === item.slug);
if (existing) {
existing.menge += menge;
} else {
cart.push({ ...item, menge });
}
saveCart(cart);
}
export function updateQuantity(slug: string, menge: number) {
let cart = getCart();
if (menge <= 0) {
cart = cart.filter((i) => i.slug !== slug);
} else {
const item = cart.find((i) => i.slug === slug);
if (item) item.menge = menge;
}
saveCart(cart);
}
export function removeFromCart(slug: string) {
saveCart(getCart().filter((i) => i.slug !== slug));
}
/** Legt fest, ob ein Artikel jetzt gekauft werden soll (true) oder nur im Warenkorb liegen
* bleibt, ohne mitgekauft zu werden (false) — z.B. wenn man sich noch nicht sicher ist. */
export function setAusgewaehlt(slug: string, ausgewaehlt: boolean) {
const cart = getCart();
const item = cart.find((i) => i.slug === slug);
if (item) item.ausgewaehlt = ausgewaehlt;
saveCart(cart);
}
export function cartCount(): number {
return getCart().reduce((sum, i) => sum + i.menge, 0);
}
// Zwischensumme inkl. Produkt-Rabatt (Prozent/Betrag) UND Mengenrabatt-Staffel — schaut sich
// dafür live die aktuellen Produktdaten an (nicht den bei addToCart gespeicherten Preis), damit
// ein nachträglich geänderter/abgelaufener Rabatt sich sofort korrekt auswirkt. Zählt NUR
// Artikel, die gerade zum Kauf ausgewählt sind — abgewählte Artikel bleiben im Warenkorb liegen,
// fließen aber nicht in Summe/Checkout ein.
export function cartTotal(): number {
return getCart()
.filter(istAusgewaehlt)
.reduce((sum, i) => {
const produkt = getProduct(i.slug);
return sum + (produkt ? effektiverZeilenpreis(produkt, i.menge) : i.menge * i.preis);
}, 0);
}
const COUPON_KEY = "vandiy_coupon_v1";
export function getCouponCode(): string {
if (typeof localStorage === "undefined") return "";
return localStorage.getItem(COUPON_KEY) || "";
}
export function setCouponCode(code: string) {
localStorage.setItem(COUPON_KEY, code.trim());
window.dispatchEvent(new CustomEvent("cart:changed", { detail: getCart() }));
}
export function clearCoupon() {
localStorage.removeItem(COUPON_KEY);
window.dispatchEvent(new CustomEvent("cart:changed", { detail: getCart() }));
}
/** Der aktuell eingelöste Gutschein, falls der gespeicherte Code (noch) gültig ist. */
export function appliedCoupon(): Gutschein | undefined {
const code = getCouponCode();
if (!code) return undefined;
return findeGutschein(code);
}
/** Rabatt-Betrag in Euro, den der eingelöste Gutschein auf die gegebene Zwischensumme gibt. */
export function couponDiscount(subtotal: number): number {
const g = appliedCoupon();
return g ? gutscheinRabatt(g, subtotal) : 0;
}