Treuebonus nur noch mit aktivem Abo nutzbar

Der Treuebonus (10 Bestellungen → 20% Rabatt) sammelt jetzt nur noch, solange
ein aktives, bezahltes Abo besteht — ohne Abo bleibt der Fortschritt einfach
stehen, statt weiterzuzählen (account.ts: registriereAbgeschlosseneBestellung()).
Ebenso greift ein bereits freigeschalteter Rabatt im Warenkorb/Checkout nur,
solange das Abo aktiv ist (cart.ts: treuebonusDiscount()).

Im Kundenkonto wird die Treuebonus-Karte ohne aktives Abo nicht einfach
ausgeblendet, sondern zeigt bewusst einen einladenden gesperrten Zustand
("🔒 Nur mit aktivem Abo verfügbar" + Button "Zum Abo →") statt der üblichen
Fortschrittsanzeige — soll als klarer Anreiz fürs Abo wirken, nicht als totes
Feature. Dieselbe Sperre greift auch im Warenkorb: das Auswahl-Radio/Badge für
den Treuebonus-Artikel erscheint nur noch bei tatsächlich aktivem Abo, damit
nie ein Rabatt suggeriert wird, der beim Checkout dann doch nicht greift.

Alles in 4 Sprachen (DE/EN/CH/FR).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
qcigano
2026-08-03 17:23:41 +02:00
co-authored by Claude Sonnet 5
parent 64110484de
commit 902516753d
12 changed files with 154 additions and 34 deletions
+26 -7
View File
@@ -324,11 +324,18 @@ const angekommeneBestellungen = beispielBestellungen.filter((b) => b.status ===
<div class="card loyalty-card">
<span class="loyalty-card-sparkle loyalty-card-sparkle-1" aria-hidden="true">✨</span>
<span class="loyalty-card-sparkle loyalty-card-sparkle-2" aria-hidden="true">✨</span>
<div class="loyalty-progress-bar"><div class="loyalty-progress-fill" id="loyalty-bar-fill"></div></div>
<p class="loyalty-progress-text" id="loyalty-progress-text"></p>
<p id="loyalty-status-text"></p>
<a class="btn btn-primary btn-sm" id="loyalty-cart-link" href="/warenkorb/" style="display:none; align-self:flex-start;">{t.accountDash.loyaltyGoToCart}</a>
<p class="small loyalty-explainer">{t.accountDash.loyaltyExplainer}</p>
<div class="loyalty-inner" id="loyalty-locked-content" style="display:none;">
<p class="loyalty-locked-title">{t.accountDash.loyaltyLockedTitle}</p>
<p class="small">{t.accountDash.loyaltyLockedText}</p>
<button type="button" class="btn btn-primary btn-sm" id="loyalty-locked-abo-btn" style="align-self:flex-start;">{t.accountDash.loyaltyLockedBtn}</button>
</div>
<div class="loyalty-inner" id="loyalty-unlocked-content">
<div class="loyalty-progress-bar"><div class="loyalty-progress-fill" id="loyalty-bar-fill"></div></div>
<p class="loyalty-progress-text" id="loyalty-progress-text"></p>
<p id="loyalty-status-text"></p>
<a class="btn btn-primary btn-sm" id="loyalty-cart-link" href="/warenkorb/" style="display:none; align-self:flex-start;">{t.accountDash.loyaltyGoToCart}</a>
<p class="small loyalty-explainer">{t.accountDash.loyaltyExplainer}</p>
</div>
</div>
</div>
</section>
@@ -545,8 +552,14 @@ const angekommeneBestellungen = beispielBestellungen.filter((b) => b.status ===
function renderLoyalty() {
const f = treueFortschritt(getAccount());
const navValue = document.getElementById("loyalty-nav-value");
if (navValue) navValue.textContent = `${f.aktuelle}/${f.ziel}`;
document.querySelector(".account-nav-loyalty")?.classList.toggle("is-ready", f.aktiv);
if (navValue) navValue.textContent = f.gesperrt ? "🔒" : `${f.aktuelle}/${f.ziel}`;
document.querySelector(".account-nav-loyalty")?.classList.toggle("is-ready", f.aktiv && !f.gesperrt);
const lockedContent = document.getElementById("loyalty-locked-content");
const unlockedContent = document.getElementById("loyalty-unlocked-content");
if (lockedContent) lockedContent.style.display = f.gesperrt ? "flex" : "none";
if (unlockedContent) unlockedContent.style.display = f.gesperrt ? "none" : "flex";
if (f.gesperrt) return;
const fill = document.getElementById("loyalty-bar-fill") as HTMLElement | null;
if (fill) fill.style.width = `${Math.min(100, (f.aktuelle / f.ziel) * 100)}%`;
@@ -573,6 +586,12 @@ const angekommeneBestellungen = beispielBestellungen.filter((b) => b.status ===
renderLoyalty();
window.addEventListener("account:changed", renderLoyalty);
// Im gesperrten Treuebonus-Zustand direkt zum Abo-Bereich springen.
document.getElementById("loyalty-locked-abo-btn")?.addEventListener("click", () => {
setActiveTab("abo");
document.getElementById("abo")?.scrollIntoView({ behavior: "smooth", block: "start" });
});
// Abosystem: Pläne, Status, Fortschritt, Prämien und Benachrichtigungen live aus dem Konto
// rendern (Nav-Kachel + Planvergleich + Statuskarte + Benachrichtigungsliste).
const aboNameMap: Record<string, string> = { klein: aboLabels.nameKlein, mittel: aboLabels.nameMittel, gross: aboLabels.nameGross };
+2 -1
View File
@@ -117,7 +117,8 @@ import { getAccount, treueFortschritt, setTreuebonusArtikel } from "../../../scr
// Treuebonus: nur relevant, wenn im Konto gerade eine Belohnung auf Einlösung wartet — dann
// darf hier EIN Artikel frei ausgewählt werden, auf den die -20% angewendet werden.
const konto = getAccount();
const treueAktiv = treueFortschritt(konto).aktiv;
const treueFortschrittKonto = treueFortschritt(konto);
const treueAktiv = treueFortschrittKonto.aktiv && !treueFortschrittKonto.gesperrt;
const gewaehlterSlug = konto.treuebonusArtikelSlug;
const loyaltyBanner = document.getElementById("loyalty-banner");
if (loyaltyBanner) loyaltyBanner.style.display = treueAktiv ? "flex" : "none";
+26 -7
View File
@@ -324,11 +324,18 @@ const angekommeneBestellungen = beispielBestellungen.filter((b) => b.status ===
<div class="card loyalty-card">
<span class="loyalty-card-sparkle loyalty-card-sparkle-1" aria-hidden="true">✨</span>
<span class="loyalty-card-sparkle loyalty-card-sparkle-2" aria-hidden="true">✨</span>
<div class="loyalty-progress-bar"><div class="loyalty-progress-fill" id="loyalty-bar-fill"></div></div>
<p class="loyalty-progress-text" id="loyalty-progress-text"></p>
<p id="loyalty-status-text"></p>
<a class="btn btn-primary btn-sm" id="loyalty-cart-link" href="/warenkorb/" style="display:none; align-self:flex-start;">{t.accountDash.loyaltyGoToCart}</a>
<p class="small loyalty-explainer">{t.accountDash.loyaltyExplainer}</p>
<div class="loyalty-inner" id="loyalty-locked-content" style="display:none;">
<p class="loyalty-locked-title">{t.accountDash.loyaltyLockedTitle}</p>
<p class="small">{t.accountDash.loyaltyLockedText}</p>
<button type="button" class="btn btn-primary btn-sm" id="loyalty-locked-abo-btn" style="align-self:flex-start;">{t.accountDash.loyaltyLockedBtn}</button>
</div>
<div class="loyalty-inner" id="loyalty-unlocked-content">
<div class="loyalty-progress-bar"><div class="loyalty-progress-fill" id="loyalty-bar-fill"></div></div>
<p class="loyalty-progress-text" id="loyalty-progress-text"></p>
<p id="loyalty-status-text"></p>
<a class="btn btn-primary btn-sm" id="loyalty-cart-link" href="/warenkorb/" style="display:none; align-self:flex-start;">{t.accountDash.loyaltyGoToCart}</a>
<p class="small loyalty-explainer">{t.accountDash.loyaltyExplainer}</p>
</div>
</div>
</div>
</section>
@@ -545,8 +552,14 @@ const angekommeneBestellungen = beispielBestellungen.filter((b) => b.status ===
function renderLoyalty() {
const f = treueFortschritt(getAccount());
const navValue = document.getElementById("loyalty-nav-value");
if (navValue) navValue.textContent = `${f.aktuelle}/${f.ziel}`;
document.querySelector(".account-nav-loyalty")?.classList.toggle("is-ready", f.aktiv);
if (navValue) navValue.textContent = f.gesperrt ? "🔒" : `${f.aktuelle}/${f.ziel}`;
document.querySelector(".account-nav-loyalty")?.classList.toggle("is-ready", f.aktiv && !f.gesperrt);
const lockedContent = document.getElementById("loyalty-locked-content");
const unlockedContent = document.getElementById("loyalty-unlocked-content");
if (lockedContent) lockedContent.style.display = f.gesperrt ? "flex" : "none";
if (unlockedContent) unlockedContent.style.display = f.gesperrt ? "none" : "flex";
if (f.gesperrt) return;
const fill = document.getElementById("loyalty-bar-fill") as HTMLElement | null;
if (fill) fill.style.width = `${Math.min(100, (f.aktuelle / f.ziel) * 100)}%`;
@@ -573,6 +586,12 @@ const angekommeneBestellungen = beispielBestellungen.filter((b) => b.status ===
renderLoyalty();
window.addEventListener("account:changed", renderLoyalty);
// Im gesperrten Treuebonus-Zustand direkt zum Abo-Bereich springen.
document.getElementById("loyalty-locked-abo-btn")?.addEventListener("click", () => {
setActiveTab("abo");
document.getElementById("abo")?.scrollIntoView({ behavior: "smooth", block: "start" });
});
// Abosystem: Pläne, Status, Fortschritt, Prämien und Benachrichtigungen live aus dem Konto
// rendern (Nav-Kachel + Planvergleich + Statuskarte + Benachrichtigungsliste).
const aboNameMap: Record<string, string> = { klein: aboLabels.nameKlein, mittel: aboLabels.nameMittel, gross: aboLabels.nameGross };
+2 -1
View File
@@ -117,7 +117,8 @@ import { getAccount, treueFortschritt, setTreuebonusArtikel } from "../../../scr
// Treuebonus: nur relevant, wenn im Konto gerade eine Belohnung auf Einlösung wartet — dann
// darf hier EIN Artikel frei ausgewählt werden, auf den die -20% angewendet werden.
const konto = getAccount();
const treueAktiv = treueFortschritt(konto).aktiv;
const treueFortschrittKonto = treueFortschritt(konto);
const treueAktiv = treueFortschrittKonto.aktiv && !treueFortschrittKonto.gesperrt;
const gewaehlterSlug = konto.treuebonusArtikelSlug;
const loyaltyBanner = document.getElementById("loyalty-banner");
if (loyaltyBanner) loyaltyBanner.style.display = treueAktiv ? "flex" : "none";
+26 -7
View File
@@ -324,11 +324,18 @@ const angekommeneBestellungen = beispielBestellungen.filter((b) => b.status ===
<div class="card loyalty-card">
<span class="loyalty-card-sparkle loyalty-card-sparkle-1" aria-hidden="true">✨</span>
<span class="loyalty-card-sparkle loyalty-card-sparkle-2" aria-hidden="true">✨</span>
<div class="loyalty-progress-bar"><div class="loyalty-progress-fill" id="loyalty-bar-fill"></div></div>
<p class="loyalty-progress-text" id="loyalty-progress-text"></p>
<p id="loyalty-status-text"></p>
<a class="btn btn-primary btn-sm" id="loyalty-cart-link" href="/warenkorb/" style="display:none; align-self:flex-start;">{t.accountDash.loyaltyGoToCart}</a>
<p class="small loyalty-explainer">{t.accountDash.loyaltyExplainer}</p>
<div class="loyalty-inner" id="loyalty-locked-content" style="display:none;">
<p class="loyalty-locked-title">{t.accountDash.loyaltyLockedTitle}</p>
<p class="small">{t.accountDash.loyaltyLockedText}</p>
<button type="button" class="btn btn-primary btn-sm" id="loyalty-locked-abo-btn" style="align-self:flex-start;">{t.accountDash.loyaltyLockedBtn}</button>
</div>
<div class="loyalty-inner" id="loyalty-unlocked-content">
<div class="loyalty-progress-bar"><div class="loyalty-progress-fill" id="loyalty-bar-fill"></div></div>
<p class="loyalty-progress-text" id="loyalty-progress-text"></p>
<p id="loyalty-status-text"></p>
<a class="btn btn-primary btn-sm" id="loyalty-cart-link" href="/warenkorb/" style="display:none; align-self:flex-start;">{t.accountDash.loyaltyGoToCart}</a>
<p class="small loyalty-explainer">{t.accountDash.loyaltyExplainer}</p>
</div>
</div>
</div>
</section>
@@ -545,8 +552,14 @@ const angekommeneBestellungen = beispielBestellungen.filter((b) => b.status ===
function renderLoyalty() {
const f = treueFortschritt(getAccount());
const navValue = document.getElementById("loyalty-nav-value");
if (navValue) navValue.textContent = `${f.aktuelle}/${f.ziel}`;
document.querySelector(".account-nav-loyalty")?.classList.toggle("is-ready", f.aktiv);
if (navValue) navValue.textContent = f.gesperrt ? "🔒" : `${f.aktuelle}/${f.ziel}`;
document.querySelector(".account-nav-loyalty")?.classList.toggle("is-ready", f.aktiv && !f.gesperrt);
const lockedContent = document.getElementById("loyalty-locked-content");
const unlockedContent = document.getElementById("loyalty-unlocked-content");
if (lockedContent) lockedContent.style.display = f.gesperrt ? "flex" : "none";
if (unlockedContent) unlockedContent.style.display = f.gesperrt ? "none" : "flex";
if (f.gesperrt) return;
const fill = document.getElementById("loyalty-bar-fill") as HTMLElement | null;
if (fill) fill.style.width = `${Math.min(100, (f.aktuelle / f.ziel) * 100)}%`;
@@ -573,6 +586,12 @@ const angekommeneBestellungen = beispielBestellungen.filter((b) => b.status ===
renderLoyalty();
window.addEventListener("account:changed", renderLoyalty);
// Im gesperrten Treuebonus-Zustand direkt zum Abo-Bereich springen.
document.getElementById("loyalty-locked-abo-btn")?.addEventListener("click", () => {
setActiveTab("abo");
document.getElementById("abo")?.scrollIntoView({ behavior: "smooth", block: "start" });
});
// Abosystem: Pläne, Status, Fortschritt, Prämien und Benachrichtigungen live aus dem Konto
// rendern (Nav-Kachel + Planvergleich + Statuskarte + Benachrichtigungsliste).
const aboNameMap: Record<string, string> = { klein: aboLabels.nameKlein, mittel: aboLabels.nameMittel, gross: aboLabels.nameGross };
+2 -1
View File
@@ -117,7 +117,8 @@ import { getAccount, treueFortschritt, setTreuebonusArtikel } from "../../../scr
// Treuebonus: nur relevant, wenn im Konto gerade eine Belohnung auf Einlösung wartet — dann
// darf hier EIN Artikel frei ausgewählt werden, auf den die -20% angewendet werden.
const konto = getAccount();
const treueAktiv = treueFortschritt(konto).aktiv;
const treueFortschrittKonto = treueFortschritt(konto);
const treueAktiv = treueFortschrittKonto.aktiv && !treueFortschrittKonto.gesperrt;
const gewaehlterSlug = konto.treuebonusArtikelSlug;
const loyaltyBanner = document.getElementById("loyalty-banner");
if (loyaltyBanner) loyaltyBanner.style.display = treueAktiv ? "flex" : "none";
+31 -7
View File
@@ -325,11 +325,21 @@ const angekommeneBestellungen = beispielBestellungen.filter((b) => b.status ===
<div class="card loyalty-card">
<span class="loyalty-card-sparkle loyalty-card-sparkle-1" aria-hidden="true">✨</span>
<span class="loyalty-card-sparkle loyalty-card-sparkle-2" aria-hidden="true">✨</span>
<div class="loyalty-progress-bar"><div class="loyalty-progress-fill" id="loyalty-bar-fill"></div></div>
<p class="loyalty-progress-text" id="loyalty-progress-text"></p>
<p id="loyalty-status-text"></p>
<a class="btn btn-primary btn-sm" id="loyalty-cart-link" href="/warenkorb/" style="display:none; align-self:flex-start;">{t.accountDash.loyaltyGoToCart}</a>
<p class="small loyalty-explainer">{t.accountDash.loyaltyExplainer}</p>
{/* Treuebonus ist an ein aktives Abo gekoppelt (soll als Zusatzanreiz fürs Abo wirken) —
ohne aktives Abo wird dieser gesperrte Hinweis statt des Fortschritts gezeigt (siehe
renderLoyalty() im Skript unten, treueFortschritt().gesperrt). */}
<div class="loyalty-inner" id="loyalty-locked-content" style="display:none;">
<p class="loyalty-locked-title">{t.accountDash.loyaltyLockedTitle}</p>
<p class="small">{t.accountDash.loyaltyLockedText}</p>
<button type="button" class="btn btn-primary btn-sm" id="loyalty-locked-abo-btn" style="align-self:flex-start;">{t.accountDash.loyaltyLockedBtn}</button>
</div>
<div class="loyalty-inner" id="loyalty-unlocked-content">
<div class="loyalty-progress-bar"><div class="loyalty-progress-fill" id="loyalty-bar-fill"></div></div>
<p class="loyalty-progress-text" id="loyalty-progress-text"></p>
<p id="loyalty-status-text"></p>
<a class="btn btn-primary btn-sm" id="loyalty-cart-link" href="/warenkorb/" style="display:none; align-self:flex-start;">{t.accountDash.loyaltyGoToCart}</a>
<p class="small loyalty-explainer">{t.accountDash.loyaltyExplainer}</p>
</div>
</div>
</div>
</section>
@@ -543,11 +553,19 @@ const angekommeneBestellungen = beispielBestellungen.filter((b) => b.status ===
window.addEventListener("account:changed", renderProfil);
// Treuebonus: Fortschritt/Status live aus dem Konto rendern (Nav-Kachel + Inhaltsbereich).
// Ist an ein aktives Abo gekoppelt (siehe treueFortschritt().gesperrt in account.ts) — ohne
// aktives Abo zeigt die Karte nur den gesperrten Hinweis samt Sprung zum Abo-Bereich.
function renderLoyalty() {
const f = treueFortschritt(getAccount());
const navValue = document.getElementById("loyalty-nav-value");
if (navValue) navValue.textContent = `${f.aktuelle}/${f.ziel}`;
document.querySelector(".account-nav-loyalty")?.classList.toggle("is-ready", f.aktiv);
if (navValue) navValue.textContent = f.gesperrt ? "🔒" : `${f.aktuelle}/${f.ziel}`;
document.querySelector(".account-nav-loyalty")?.classList.toggle("is-ready", f.aktiv && !f.gesperrt);
const lockedContent = document.getElementById("loyalty-locked-content");
const unlockedContent = document.getElementById("loyalty-unlocked-content");
if (lockedContent) lockedContent.style.display = f.gesperrt ? "flex" : "none";
if (unlockedContent) unlockedContent.style.display = f.gesperrt ? "none" : "flex";
if (f.gesperrt) return;
const fill = document.getElementById("loyalty-bar-fill") as HTMLElement | null;
if (fill) fill.style.width = `${Math.min(100, (f.aktuelle / f.ziel) * 100)}%`;
@@ -574,6 +592,12 @@ const angekommeneBestellungen = beispielBestellungen.filter((b) => b.status ===
renderLoyalty();
window.addEventListener("account:changed", renderLoyalty);
// Im gesperrten Treuebonus-Zustand direkt zum Abo-Bereich springen.
document.getElementById("loyalty-locked-abo-btn")?.addEventListener("click", () => {
setActiveTab("abo");
document.getElementById("abo")?.scrollIntoView({ behavior: "smooth", block: "start" });
});
// Abosystem: Pläne, Status, Fortschritt, Prämien und Benachrichtigungen live aus dem Konto
// rendern (Nav-Kachel + Planvergleich + Statuskarte + Benachrichtigungsliste).
const aboNameMap: Record<string, string> = { klein: aboLabels.nameKlein, mittel: aboLabels.nameMittel, gross: aboLabels.nameGross };
+4 -1
View File
@@ -117,7 +117,10 @@ import { getAccount, treueFortschritt, setTreuebonusArtikel } from "../../script
// Treuebonus: nur relevant, wenn im Konto gerade eine Belohnung auf Einlösung wartet — dann
// darf hier EIN Artikel frei ausgewählt werden, auf den die -20% angewendet werden.
const konto = getAccount();
const treueAktiv = treueFortschritt(konto).aktiv;
// Treuebonus ist an ein aktives Abo gekoppelt (siehe account.ts) — ohne aktives Abo bleibt
// die Auswahl/Anzeige hier ausgeblendet, auch wenn intern noch eine Belohnung "wartet".
const treueFortschrittKonto = treueFortschritt(konto);
const treueAktiv = treueFortschrittKonto.aktiv && !treueFortschrittKonto.gesperrt;
const gewaehlterSlug = konto.treuebonusArtikelSlug;
const loyaltyBanner = document.getElementById("loyalty-banner");
if (loyaltyBanner) loyaltyBanner.style.display = treueAktiv ? "flex" : "none";