Treuebonus-System: 10 abgeschlossene Bestellungen = 20% Rabatt auf einen frei wählbaren Artikel

Neue eigene Kiste "Treuebonus" im Kundenkonto (5. Nav-Tab, grüner Akzent)
zeigt den Fortschritt ("X von 10 Bestellungen") mit Fortschrittsbalken und
Restanzahl-Hinweis, nach Freischaltung eine Erfolgsmeldung mit Link zum
Warenkorb. Es zählen ausschließlich erfolgreich abgeschickte, bezahlte
Bestellungen (in Phase 1: jede erfolgreich abgeschlossene Demo-Bestellung
im Checkout) — abgebrochene Bestellungen zählen nie mit.

Sobald der Bonus aktiv ist, erscheint im Warenkorb ein Hinweis-Banner und
bei jedem Artikel eine Auswahl ("Für 20% Treuebonus auswählen") — es kann
immer nur EIN Artikel gewählt werden (Radiobutton-Verhalten über alle
Positionen hinweg). Der Rabatt fließt automatisch in Warenkorb- und
Checkout-Summe ein (neue treuebonusDiscount()-Funktion in scripts/cart.ts,
in totalDiscount() eingerechnet). Nach erfolgreichem Bestellabschluss wird
die Belohnung als eingelöst markiert und der Fortschrittszähler beginnt
wieder bei 0 — beides dauerhaft im Konto (localStorage, Phase 1) gespeichert
und eindeutig diesem Kundenkonto zugeordnet.

Neue Funktionen in scripts/account.ts: registriereAbgeschlosseneBestellung(),
setTreuebonusArtikel(), treuebonusEinloesen(), treueFortschritt(). Beide
Zustandsübergänge (Fortschritt zählen vs. Belohnung einlösen) end-to-end
über den echten Checkout-Ablauf getestet und verifiziert.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
qcigano
2026-08-03 15:03:48 +02:00
co-authored by Claude Sonnet 5
parent d7ba1b9bff
commit 0cb7d3ca65
16 changed files with 769 additions and 63 deletions
+61
View File
@@ -1476,6 +1476,67 @@ a:focus-visible, button:focus-visible {
.account-nav-open { --nav-color: var(--c-accent); --nav-delay: 0.4s; }
.account-nav-wishlist { --nav-color: var(--c-sale); --nav-delay: 0.8s; }
.account-nav-data { --nav-color: #e3b23c; --nav-delay: 1.2s; }
.account-nav-loyalty { --nav-color: #6ecb8f; --nav-delay: 1.6s; }
/* Sobald der Treuebonus wirklich freigeschaltet ist (10/10), bekommt sein Knopf zusätzlich zur
normalen "Premium"-Optik noch einen kräftigeren, schneller pulsierenden Rahmen — soll auf
keinen Fall übersehen werden, wenn die Belohnung bereit ist. */
.account-nav-loyalty.is-ready { animation-duration: 1.4s, 1.1s; }
.account-nav-loyalty.is-ready::after { height: 4px; }
/* Treuebonus-Fortschrittskarte im Inhaltsbereich — eigener grüner Farbton, sonst dieselbe
"besondere" Formsprache wie die anderen Konto-Karten (siehe .profile-card). */
.loyalty-card { position: relative; overflow: hidden; display: flex; flex-direction: column; gap: 0.9rem; }
.loyalty-progress-bar {
width: 100%;
height: 12px;
border-radius: 999px;
background: rgba(244, 241, 247, 0.1);
overflow: hidden;
border: 1px solid rgba(244, 241, 247, 0.14);
}
.loyalty-progress-fill {
height: 100%;
width: 0%;
border-radius: 999px;
background: linear-gradient(90deg, #6ecb8f, #5fd3ec);
transition: width 0.5s var(--ease);
}
.loyalty-progress-text { font-weight: 700; font-size: 1.05rem; margin: 0; }
.loyalty-explainer { color: var(--c-text-muted); margin: 0.4rem 0 0; }
.loyalty-card-sparkle { position: absolute; font-size: 0.85rem; pointer-events: none; z-index: 1; }
.loyalty-card-sparkle-1 { top: 1.1rem; right: 1.3rem; animation: account-nav-sparkle-twinkle 2.7s ease-in-out infinite; }
.loyalty-card-sparkle-2 { bottom: 1.2rem; left: 1.3rem; font-size: 0.7rem; animation: account-nav-sparkle-twinkle 3.5s ease-in-out infinite 0.5s; }
@media (prefers-reduced-motion: reduce) {
.loyalty-card-sparkle-1, .loyalty-card-sparkle-2 { animation: none; }
}
/* Warenkorb: Treuebonus-Banner + Auswahl direkt an der betroffenen Zeile. */
.loyalty-banner {
display: flex;
align-items: center;
gap: 0.9rem;
border-radius: var(--radius-m);
border: 1.5px solid color-mix(in srgb, #6ecb8f 45%, transparent);
background: linear-gradient(120deg, color-mix(in srgb, #6ecb8f 20%, transparent), color-mix(in srgb, #5fd3ec 14%, transparent));
padding: 1rem 1.2rem;
margin-bottom: 1rem;
}
.loyalty-banner-icon { font-size: 1.6rem; flex-shrink: 0; }
.loyalty-banner strong { display: block; margin-bottom: 0.15em; }
.loyalty-banner p { margin: 0; color: var(--c-text-muted); font-size: 0.9rem; }
.loyalty-select {
display: inline-flex;
align-items: center;
gap: 0.4em;
font-size: 0.82rem;
font-weight: 600;
color: var(--c-text-muted);
cursor: pointer;
white-space: nowrap;
}
.loyalty-select input { accent-color: #6ecb8f; width: auto; }
.cart-item.loyalty-selected { box-shadow: inset 0 0 0 1.5px color-mix(in srgb, #6ecb8f 60%, transparent); border-radius: var(--radius-s); }
.loyalty-selected-badge { color: #6ecb8f; font-weight: 700; font-size: 0.82rem; white-space: nowrap; }
.account-nav-sparkle {
position: absolute;
top: 0.55rem;