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
+56 -4
View File
@@ -175,6 +175,11 @@ export const ui = {
partnerDiscount: "🤝 Partner-Rabatt",
partnerCodeLabel: "🤝 Partner-Rabattcode", partnerCodePlaceholder: "Code eingeben", partnerCodeApply: "Einlösen", partnerCodeRemove: "Entfernen",
partnerCodeInvalid: "Code ungültig oder abgelaufen.", partnerCodeApplied: (code: string) => `Partner-Code „${code}" eingelöst`,
loyaltyDiscount: "🎁 Treuebonus (-20 %)",
loyaltyBannerTitle: "🎁 Dein Treuebonus ist bereit!",
loyaltyBannerText: "Wähle unten den Artikel aus, auf den du 20 % Rabatt erhältst.",
loyaltySelectLabel: "Für 20 % Treuebonus auswählen",
loyaltySelectedLabel: "🎁 -20 % Treuebonus angewendet",
},
checkout: {
eyebrow: "Checkout", title: "Bestellung abschließen",
@@ -224,7 +229,15 @@ export const ui = {
notLoggedIn: "Du bist nicht angemeldet — du wirst zur Anmeldung weitergeleitet …",
logout: "Abmelden",
navLabel: "Kontobereich-Navigation",
statOrders: "Bestellungen", statWishlist: "Wunschliste", statOpen: "Offene Sendungen", statData: "Meine Daten",
statOrders: "Bestellungen", statWishlist: "Wunschliste", statOpen: "Offene Sendungen", statData: "Meine Daten", statLoyalty: "Treuebonus",
loyaltyTitle: "🎁 Mein Treuebonus",
loyaltyProgressTemplate: "Dein Bestellfortschritt: {cur} von {ziel} Bestellungen",
loyaltyRemainingOne: "Dir fehlt noch 1 Bestellung, bis du 20 % Rabatt auf einen Artikel deiner Wahl erhältst.",
loyaltyRemainingOther: "Dir fehlen noch {n} Bestellungen, bis du 20 % Rabatt auf einen Artikel deiner Wahl erhältst.",
loyaltyUnlockedTitle: "🎉 Treuebonus freigeschaltet",
loyaltyUnlockedText: "Du hast zehn Bestellungen abgeschlossen und erhältst bei deiner nächsten Bestellung 20 % Rabatt auf einen Artikel deiner Wahl.",
loyaltyGoToCart: "Artikel im Warenkorb auswählen →",
loyaltyExplainer: "Es zählen nur vollständig abgeschlossene und bezahlte Bestellungen. Nach der Einlösung beginnt dein Fortschritt wieder bei null.",
noOpenOrders: "Aktuell keine offenen Sendungen — alle Bestellungen sind schon angekommen. 🎉",
noArrivedOrders: "Noch keine angekommenen Bestellungen — hier erscheinen deine Bestellungen, sobald sie geliefert wurden.",
ordersTitle: "📦 Meine Bestellungen",
@@ -413,6 +426,11 @@ export const ui = {
partnerDiscount: "🤝 Partner discount",
partnerCodeLabel: "🤝 Partner discount code", partnerCodePlaceholder: "Enter code", partnerCodeApply: "Apply", partnerCodeRemove: "Remove",
partnerCodeInvalid: "Code invalid or expired.", partnerCodeApplied: (code: string) => `Partner code "${code}" applied`,
loyaltyDiscount: "🎁 Loyalty reward (-20%)",
loyaltyBannerTitle: "🎁 Your loyalty reward is ready!",
loyaltyBannerText: "Pick the item below that you'd like 20% off.",
loyaltySelectLabel: "Select for 20% loyalty reward",
loyaltySelectedLabel: "🎁 -20% loyalty reward applied",
},
checkout: {
eyebrow: "Checkout", title: "Complete your order",
@@ -462,7 +480,15 @@ export const ui = {
notLoggedIn: "You're not signed in — redirecting you to sign in …",
logout: "Sign out",
navLabel: "Account section navigation",
statOrders: "Orders", statWishlist: "Wishlist", statOpen: "Open shipments", statData: "My details",
statOrders: "Orders", statWishlist: "Wishlist", statOpen: "Open shipments", statData: "My details", statLoyalty: "Loyalty reward",
loyaltyTitle: "🎁 My loyalty reward",
loyaltyProgressTemplate: "Your order progress: {cur} of {ziel} orders",
loyaltyRemainingOne: "You need 1 more order to get 20% off an item of your choice.",
loyaltyRemainingOther: "You need {n} more orders to get 20% off an item of your choice.",
loyaltyUnlockedTitle: "🎉 Loyalty reward unlocked",
loyaltyUnlockedText: "You've completed ten orders and get 20% off an item of your choice on your next order.",
loyaltyGoToCart: "Choose item in cart →",
loyaltyExplainer: "Only fully completed and paid orders count. After redemption your progress starts again from zero.",
noOpenOrders: "No open shipments right now — every order has already arrived. 🎉",
noArrivedOrders: "No delivered orders yet — your orders will appear here once they've arrived.",
ordersTitle: "📦 My orders",
@@ -651,6 +677,11 @@ export const ui = {
partnerDiscount: "🤝 Partner-Rabatt",
partnerCodeLabel: "🤝 Partner-Rabattcode", partnerCodePlaceholder: "Code igäh", partnerCodeApply: "Ilöse", partnerCodeRemove: "Ewägmache",
partnerCodeInvalid: "Code ungültig oder abgloffe.", partnerCodeApplied: (code: string) => `Partner-Code „${code}" iglöst`,
loyaltyDiscount: "🎁 Treuebonus (-20 %)",
loyaltyBannerTitle: "🎁 Din Treuebonus isch parat!",
loyaltyBannerText: "Wähl unde dr Artikel us, uf dä du 20 % Rabatt übercho.",
loyaltySelectLabel: "Für 20 % Treuebonus uswähle",
loyaltySelectedLabel: "🎁 -20 % Treuebonus aagwändet",
},
checkout: {
eyebrow: "Checkout", title: "Bschtellig abschliesse",
@@ -700,7 +731,15 @@ export const ui = {
notLoggedIn: "Du bisch nid aagmäldet — du wirsch zur Aamäldig wytergleitet …",
logout: "Abmälde",
navLabel: "Kontobereich-Navigation",
statOrders: "Bstellige", statWishlist: "Wunschlischte", statOpen: "Offni Sändige", statData: "Mini Date",
statOrders: "Bstellige", statWishlist: "Wunschlischte", statOpen: "Offni Sändige", statData: "Mini Date", statLoyalty: "Treuebonus",
loyaltyTitle: "🎁 Mis Treuebonus",
loyaltyProgressTemplate: "Din Bstellfortschritt: {cur} vo {ziel} Bstellige",
loyaltyRemainingOne: "Dir fehlt no 1 Bstellig, bis du 20 % Rabatt uf en Artikel dinere Wahl übercho.",
loyaltyRemainingOther: "Dir fehle no {n} Bstellige, bis du 20 % Rabatt uf en Artikel dinere Wahl übercho.",
loyaltyUnlockedTitle: "🎉 Treuebonus freigschaltet",
loyaltyUnlockedText: "Du hesch zäh Bstellige abgschlosse und übercho bi dinere nächschte Bstellig 20 % Rabatt uf en Artikel dinere Wahl.",
loyaltyGoToCart: "Artikel im Warenchorb uswähle →",
loyaltyExplainer: "Es zelle nume vollständig abgschlosseni und bezahlti Bstellige. Nach dr Ilösig fangt din Fortschritt wieder bi null a.",
noOpenOrders: "Momentan kei offni Sändige — alli Bstellige sind scho aacho. 🎉",
noArrivedOrders: "No kei aacho Bstellige — da erschine dini Bstellige, sobald sie glifert worde sind.",
ordersTitle: "📦 Mini Bstellige",
@@ -889,6 +928,11 @@ export const ui = {
partnerDiscount: "🤝 Remise partenaire",
partnerCodeLabel: "🤝 Code partenaire", partnerCodePlaceholder: "Entrer le code", partnerCodeApply: "Valider", partnerCodeRemove: "Retirer",
partnerCodeInvalid: "Code invalide ou expiré.", partnerCodeApplied: (code: string) => `Code partenaire « ${code} » appliqué`,
loyaltyDiscount: "🎁 Récompense fidélité (-20 %)",
loyaltyBannerTitle: "🎁 Votre récompense fidélité est prête !",
loyaltyBannerText: "Choisissez ci-dessous l'article sur lequel vous voulez -20 %.",
loyaltySelectLabel: "Choisir pour la récompense fidélité de 20 %",
loyaltySelectedLabel: "🎁 Récompense fidélité de -20 % appliquée",
},
checkout: {
eyebrow: "Paiement", title: "Finaliser la commande",
@@ -938,7 +982,15 @@ export const ui = {
notLoggedIn: "Vous n'êtes pas connecté(e) — redirection vers la connexion …",
logout: "Se déconnecter",
navLabel: "Navigation de l'espace client",
statOrders: "Commandes", statWishlist: "Liste de souhaits", statOpen: "Envois en cours", statData: "Mes données",
statOrders: "Commandes", statWishlist: "Liste de souhaits", statOpen: "Envois en cours", statData: "Mes données", statLoyalty: "Récompense",
loyaltyTitle: "🎁 Ma récompense fidélité",
loyaltyProgressTemplate: "Votre progression : {cur} sur {ziel} commandes",
loyaltyRemainingOne: "Il vous manque encore 1 commande pour obtenir 20 % de réduction sur l'article de votre choix.",
loyaltyRemainingOther: "Il vous manque encore {n} commandes pour obtenir 20 % de réduction sur l'article de votre choix.",
loyaltyUnlockedTitle: "🎉 Récompense fidélité débloquée",
loyaltyUnlockedText: "Vous avez validé dix commandes et bénéficiez de 20 % de réduction sur l'article de votre choix lors de votre prochaine commande.",
loyaltyGoToCart: "Choisir l'article dans le panier →",
loyaltyExplainer: "Seules les commandes entièrement finalisées et payées comptent. Après utilisation, votre progression repart de zéro.",
noOpenOrders: "Aucun envoi en cours pour le moment — toutes les commandes sont déjà arrivées. 🎉",
noArrivedOrders: "Aucune commande livrée pour le moment — vos commandes apparaîtront ici dès qu'elles seront arrivées.",
ordersTitle: "📦 Mes commandes",