Die Rabattcodes haengen am Konto, nicht mehr am Abo
Filipe: "die partner codes sollen auch schon fuer die leute sichtbar sein die angemeldet sind." Umgestellt, und auf Nachfrage dauerhaft: Rabattcodes sind ab jetzt ein Konto-Vorteil, kein Abo-Vorteil. WARUM DAS MEHR IST ALS EINE BEQUEMLICHKEIT Der alte Riegel verlangte einen Abo-Status. Nachgesehen, statt vermutet: Die Bezahlung auf abonnieren.html steht auf "Coming soon", bis Dogis PayPal-Business-Zugang da ist (der Kommentar dort nennt es beim Namen). Registrieren geht, bezahlen nicht. Der erste echte Partnercode lag damit seit gestern hinter einer Tuer, die sich gar nicht oeffnen laesst -- er waere fuer NIEMANDEN sichtbar gewesen ausser fuer Dogi und VanVan ueber die Rollenvorschau. Entschieden wird jetzt an "supporterToken" (beim Login gesetzt, beim Logout entfernt, supporter.js). Der Abo-Stand wird als Sicherheitsnetz weiter mitgelesen: Niemand soll Zugang verlieren, den er gestern hatte. BEIDE STELLEN, NICHT EINE Die Bedingung steht doppelt im Haus -- an der Kachel auf links.html und an der Seite selbst. Nur eine davon umzustellen erzeugt einen Fehler, den keine der beiden fuer sich zeigt: Man kaeme mit Konto auf die Seite und saehe dort die Sperre. Beide sind umgestellt, tragen den Hinweis aufeinander, und die Pruefung vergleicht sie in jedem Anmeldezustand gegeneinander. TEXTE, DIE SONST GELOGEN HAETTEN "Nur fuer Supporter" auf einer Seite, die ein kostenloses Konto oeffnet, schickt Leute zum Bezahlen fuer etwas, das sie umsonst bekommen. Kopf, Vorspann, Kachelband, Beschreibung und Sperrtext sagen jetzt "Konto", in allen fuenf Sprachen. Die Sperre bietet auf Filipes Wunsch beide Wege an: den kostenlosen zuerst, das Abo daneben -- mit einer Zeile darunter, dass es erst startet, wenn es offiziell live geht. Ohne die waere der zweite Knopf eine Falle. EIN FEHLER, DER SEIT DEM 03.08.2026 DRINSTAND Die Pruefung meldete auf der FREIGESCHALTETEN Kachel weiter "Nur mit Konto" statt "Freigeschaltet". Ursache: Das Skript setzte den Text (`badge.textContent = ...`), aber applyTranslations() schreibt aus dem data-i18n-Attribut zurueck -- und es laeuft danach noch einmal, weil dogiSiteTexteLaden() die Texte aus der Verwaltung holt und dann neu uebersetzt. NACHGEMESSEN STATT HERGELEITET, und die erste Erklaerung war zu schnell: Der Text war schon nach 50 ms falsch, also nicht "irgendwann spaeter ueberschrieben". Der Grund ist, dass TEAM_API_BASIS auf den ECHTEN Worker zeigt -- der Abruf gelingt selbst aus einer lokalen Testseite. Kontroll- versuch mit blockiertem Abruf: derselbe alte Code, und das Band bleibt korrekt. Ursache weg, Fehler weg. Behoben, indem der SCHLUESSEL getauscht wird statt des Textes. Damit schreibt jeder weitere Uebersetzungslauf von selbst das Richtige hin -- auch bei Sprachwechsel, wo die alte Fassung ebenfalls zurueckfiel. Aufgefallen ist es nie, weil bis gestern niemand in den freigeschalteten Zustand kommen konnte. NEBENBEFUND, NICHT ANGEFASST: index.html hat dieselbe Bauart beim Live-Status (#live-text mit data-i18n, Text per Skript gesetzt). Gemessen ist es dort ein Wettlauf zweier Abrufe -- in meinem Lauf gewann der Status um Haaresbreite, und ein Sprachwechsel repariert es dort ohnehin (dogi-sprache-geaendert). Kleiner, aber echt. Auf Ansage. pruef-rabattcodes EXIT=0 (63 Pruefungen, vorher 42). Neu darunter: drei Anmeldezustaende statt zweier -- ausgeloggt, angemeldet ohne Abo, angemeldet mit Abo --, jeder auf BEIDEN Seiten, dazu der Klick auf die Kachel (fuehrt sie wirklich weiter?), die Beschriftung des Bands und als Gegenprobe ein erzwungener Uebersetzungslauf, der den alten Fehler zuverlaessig ausloest. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+22
-14
@@ -24,8 +24,8 @@ window.I18N_PAGE = {
|
|||||||
en: "By request only", fr: "Uniquement sur demande", pt: "Somente mediante solicitação",
|
en: "By request only", fr: "Uniquement sur demande", pt: "Somente mediante solicitação",
|
||||||
},
|
},
|
||||||
lk_rabatt_badge: {
|
lk_rabatt_badge: {
|
||||||
de: "🔒 Nur für Supporter", "de-CH": "🔒 Nur für Supporter",
|
de: "🔒 Nur mit Konto", "de-CH": "🔒 Nur mit Konto",
|
||||||
en: "🔒 Supporters only", fr: "🔒 Réservé aux Supporters", pt: "🔒 Somente para apoiadores",
|
en: "🔒 Account required", fr: "🔒 Compte requis", pt: "🔒 Requer conta",
|
||||||
},
|
},
|
||||||
lk_rabatt_badge_frei: {
|
lk_rabatt_badge_frei: {
|
||||||
de: "✓ Freigeschaltet", "de-CH": "✓ Freigschalte",
|
de: "✓ Freigeschaltet", "de-CH": "✓ Freigschalte",
|
||||||
@@ -36,22 +36,30 @@ window.I18N_PAGE = {
|
|||||||
en: "Discount Codes", fr: "Codes de réduction", pt: "Códigos de desconto",
|
en: "Discount Codes", fr: "Codes de réduction", pt: "Códigos de desconto",
|
||||||
},
|
},
|
||||||
lk_rabatt_desc: {
|
lk_rabatt_desc: {
|
||||||
de: "Codes von Dogis Partnern — exklusiv für Dogfather-Supporter.",
|
de: "Codes von Dogis Partnern — für alle mit einem Konto.",
|
||||||
"de-CH": "Codes vo Dogis Partner — exklusiv für Dogfather-Supporter.",
|
"de-CH": "Codes vo Dogis Partner — für alli mit eme Konto.",
|
||||||
en: "Codes from Dogi's partners — exclusive to Dogfather supporters.",
|
en: "Codes from Dogi's partners — for everyone with an account.",
|
||||||
fr: "Des codes chez les partenaires de Dogi — exclusifs aux Supporters Dogfather.",
|
fr: "Des codes chez les partenaires de Dogi — pour toute personne ayant un compte.",
|
||||||
pt: "Códigos dos parceiros do Dogi — exclusivos para apoiadores do Dogfather.",
|
pt: "Códigos dos parceiros do Dogi — para todos com uma conta.",
|
||||||
},
|
},
|
||||||
|
/* Seit 08.09.2026 hängt die Kachel am Konto, nicht mehr am Abo (siehe
|
||||||
|
den Kommentar im <style>-Kopf von links.html). Der alte Text schickte
|
||||||
|
Ausgeloggte zum Abo — das ist noch gar nicht bezahlbar, und für die
|
||||||
|
Codes reicht ein kostenloses Konto. */
|
||||||
lk_rabatt_gesperrt_hinweis: {
|
lk_rabatt_gesperrt_hinweis: {
|
||||||
de: "🔒 Rabattcodes sind nur für Dogfather-Supporter zugänglich. Werde jetzt Supporter, um sie freizuschalten.",
|
de: "🔒 Die Rabattcodes gibt es für alle mit einem Konto. Melde dich an oder registriere dich kostenlos — dann sind sie da.",
|
||||||
"de-CH": "🔒 Rabattcodes sind nur für Dogfather-Supporter zuegänglich. Wird jetzt Supporter, zum sie freizschalte.",
|
"de-CH": "🔒 D Rabattcodes gits für alli mit eme Konto. Meld di aa oder registrier di gratis — denn sind si da.",
|
||||||
en: "🔒 Discount codes are only available to Dogfather supporters. Become a supporter now to unlock them.",
|
en: "🔒 Discount codes are there for everyone with an account. Sign in or register for free — then they're yours.",
|
||||||
fr: "🔒 Les codes de réduction sont réservés aux Supporters Dogfather. Deviens Supporter dès maintenant pour les débloquer.",
|
fr: "🔒 Les codes de réduction sont là pour toute personne ayant un compte. Connecte-toi ou inscris-toi gratuitement — et ils sont à toi.",
|
||||||
pt: "🔒 Os códigos de desconto são exclusivos para apoiadores do Dogfather. Torne-se apoiador agora para desbloqueá-los.",
|
pt: "🔒 Os códigos de desconto existem para todos com uma conta. Inicia sessão ou regista-te gratuitamente — e são teus.",
|
||||||
|
},
|
||||||
|
lk_rabatt_btn_anmelden: {
|
||||||
|
de: "Anmelden oder registrieren", "de-CH": "Aamelde oder registriere",
|
||||||
|
en: "Sign in or register", fr: "Se connecter ou s'inscrire", pt: "Iniciar sessão ou registar",
|
||||||
},
|
},
|
||||||
lk_rabatt_btn_abo: {
|
lk_rabatt_btn_abo: {
|
||||||
de: "Jetzt Supporter werden 👑", "de-CH": "Jetzt Supporter werde 👑",
|
de: "Supporter werden 👑", "de-CH": "Supporter werde 👑",
|
||||||
en: "Become a supporter now 👑", fr: "Devenir Supporter maintenant 👑", pt: "Tornar-se apoiador agora 👑",
|
en: "Become a supporter 👑", fr: "Devenir Supporter 👑", pt: "Tornar-se apoiador 👑",
|
||||||
},
|
},
|
||||||
lk_shop_hint: {
|
lk_shop_hint: {
|
||||||
de: "Folgt in Kürze", "de-CH": "Chunnt bald",
|
de: "Folgt in Kürze", "de-CH": "Chunnt bald",
|
||||||
|
|||||||
@@ -19,38 +19,62 @@
|
|||||||
|
|
||||||
window.I18N_PAGE = {
|
window.I18N_PAGE = {
|
||||||
rc_eyebrow: {
|
rc_eyebrow: {
|
||||||
de: "🔒 Nur für Supporter", "de-CH": "🔒 Nur für Supporter",
|
de: "🔒 Nur mit Konto", "de-CH": "🔒 Nur mit Konto",
|
||||||
en: "🔒 Supporters only", fr: "🔒 Réservé aux Supporters", pt: "🔒 Somente para apoiadores",
|
en: "🔒 Account required", fr: "🔒 Compte requis", pt: "🔒 Requer conta",
|
||||||
},
|
},
|
||||||
rc_h1: {
|
rc_h1: {
|
||||||
de: "Rabattcodes", "de-CH": "Rabattcodes",
|
de: "Rabattcodes", "de-CH": "Rabattcodes",
|
||||||
en: "Discount Codes", fr: "Codes de réduction", pt: "Códigos de desconto",
|
en: "Discount Codes", fr: "Codes de réduction", pt: "Códigos de desconto",
|
||||||
},
|
},
|
||||||
rc_lead: {
|
rc_lead: {
|
||||||
de: "Codes von Dogis Partnern — exklusiv für Dogfather-Supporter.",
|
de: "Codes von Dogis Partnern — für alle mit einem Konto im DOGFATHER UNIVERSE.",
|
||||||
"de-CH": "Codes vo Dogis Partner — exklusiv für Dogfather-Supporter.",
|
"de-CH": "Codes vo Dogis Partner — für alli mit eme Konto im DOGFATHER UNIVERSE.",
|
||||||
en: "Codes from Dogi's partners — exclusive to Dogfather supporters.",
|
en: "Codes from Dogi's partners — for everyone with a DOGFATHER UNIVERSE account.",
|
||||||
fr: "Des codes chez les partenaires de Dogi — exclusifs aux Supporters Dogfather.",
|
fr: "Des codes chez les partenaires de Dogi — pour toute personne ayant un compte DOGFATHER UNIVERSE.",
|
||||||
pt: "Códigos dos parceiros do Dogi — exclusivos para apoiadores do Dogfather.",
|
pt: "Códigos dos parceiros do Dogi — para todos com uma conta no DOGFATHER UNIVERSE.",
|
||||||
},
|
},
|
||||||
rc_gesperrt_titel: {
|
rc_gesperrt_titel: {
|
||||||
de: "Nur für Dogfather-Supporter", "de-CH": "Nur für Dogfather-Supporter",
|
de: "Melde dich an, dann sind sie da",
|
||||||
en: "Dogfather supporters only", fr: "Réservé aux Supporters Dogfather", pt: "Somente para apoiadores do Dogfather",
|
"de-CH": "Meld di aa, denn sind si da",
|
||||||
|
en: "Sign in and they're right here",
|
||||||
|
fr: "Connecte-toi et ils sont là",
|
||||||
|
pt: "Inicia sessão e estão aqui",
|
||||||
},
|
},
|
||||||
/* Stand 08.09.2026 angepasst: Der Satz endete vorher auf "sobald die
|
/* Zweimal angepasst, beide Male weil der Satz nicht mehr stimmte:
|
||||||
ersten Kooperationen live sind". Seit heute IST die erste live —
|
08.09.2026 früh endete er auf "sobald die ersten Kooperationen live
|
||||||
der alte Text hätte einen Supporter dafür bezahlen lassen, auf etwas
|
sind" — die erste WAR ab da live. Am selben Tag hat Filipe die Sperre
|
||||||
zu warten, das schon hinter der Sperre liegt. */
|
vom Abo auf das Konto umgestellt; seither wäre "exklusiver Vorteil
|
||||||
|
der DogiCrew" schlicht falsch. Der Text nennt jetzt genau die eine
|
||||||
|
Bedingung, die wirklich gilt, und dass sie nichts kostet. */
|
||||||
rc_gesperrt_text: {
|
rc_gesperrt_text: {
|
||||||
de: "Rabattcodes sind ein exklusiver Vorteil der DogiCrew 🩵. Der erste Partnercode ist schon drin — werde jetzt Teil davon, um ihn freizuschalten.",
|
de: "Die Rabattcodes gibt es für alle mit einem Konto bei Dogfather — Registrieren ist kostenlos und dauert eine Minute. Der erste Partnercode wartet schon.",
|
||||||
"de-CH": "Rabattcodes sind e exklusive Vorteil vo dr DogiCrew 🩵. De erst Partnercode isch scho dinn — wird jetzt Teil devo, zum en freizschalte.",
|
"de-CH": "D Rabattcodes gits für alli mit eme Konto bi Dogfather — Registriere isch gratis und duuret e Minute. De erst Partnercode wartet scho.",
|
||||||
en: "Discount codes are an exclusive perk of the DogiCrew 🩵. The first partner code is already in there — join now to unlock it.",
|
en: "Discount codes are there for everyone with a Dogfather account — signing up is free and takes a minute. The first partner code is already waiting.",
|
||||||
fr: "Les codes de réduction sont un avantage exclusif de la DogiCrew 🩵. Le premier code partenaire est déjà là — rejoins-la maintenant pour le débloquer.",
|
fr: "Les codes de réduction sont là pour toute personne ayant un compte Dogfather — l'inscription est gratuite et prend une minute. Le premier code partenaire attend déjà.",
|
||||||
pt: "Os códigos de desconto são um benefício exclusivo da DogiCrew 🩵. O primeiro código de parceiro já lá está — junta-te agora para o desbloquear.",
|
pt: "Os códigos de desconto existem para todos com uma conta Dogfather — registares-te é gratuito e demora um minuto. O primeiro código de parceiro já está à espera.",
|
||||||
|
},
|
||||||
|
rc_btn_anmelden: {
|
||||||
|
de: "Anmelden oder kostenlos registrieren",
|
||||||
|
"de-CH": "Aamelde oder gratis registriere",
|
||||||
|
en: "Sign in or register for free",
|
||||||
|
fr: "Se connecter ou s'inscrire gratuitement",
|
||||||
|
pt: "Iniciar sessão ou registar gratuitamente",
|
||||||
},
|
},
|
||||||
rc_btn_abo: {
|
rc_btn_abo: {
|
||||||
de: "Jetzt Supporter werden 👑", "de-CH": "Jetzt Supporter werde 👑",
|
de: "Supporter werden 👑", "de-CH": "Supporter werde 👑",
|
||||||
en: "Become a supporter now 👑", fr: "Devenir Supporter maintenant 👑", pt: "Tornar-se apoiador agora 👑",
|
en: "Become a supporter 👑", fr: "Devenir Supporter 👑", pt: "Tornar-se apoiador 👑",
|
||||||
|
},
|
||||||
|
/* Ohne diese Zeile wäre der zweite Knopf eine Falle: Das bezahlte Abo
|
||||||
|
ist noch nicht freigeschaltet (abonnieren.html zeigt dort "Coming
|
||||||
|
soon…", bis Dogis PayPal-Business-Zugang steht). Wer ihn drückt,
|
||||||
|
soll vorher wissen, was ihn erwartet — und dass er für die Codes
|
||||||
|
nicht nötig ist. */
|
||||||
|
rc_abo_hinweis: {
|
||||||
|
de: "Fürs Abo brauchst du ebenfalls erst ein Konto — es startet, sobald es offiziell live geht.",
|
||||||
|
"de-CH": "Fürs Abo bruuchsch au zerscht es Konto — es startet, sobald es offiziell live gaht.",
|
||||||
|
en: "The subscription needs an account too — it starts as soon as it officially goes live.",
|
||||||
|
fr: "L'abonnement nécessite lui aussi un compte — il démarre dès son lancement officiel.",
|
||||||
|
pt: "A subscrição também precisa de uma conta — arranca assim que ficar oficialmente disponível.",
|
||||||
},
|
},
|
||||||
|
|
||||||
/* ---- Erster Partner: Van's DIY & Bastelbedarf (DOGI10) ---------- */
|
/* ---- Erster Partner: Van's DIY & Bastelbedarf (DOGI10) ---------- */
|
||||||
|
|||||||
+74
-18
@@ -25,17 +25,34 @@
|
|||||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260828e" />
|
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260828e" />
|
||||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260828e" />
|
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260828e" />
|
||||||
<style>
|
<style>
|
||||||
/* Rabattcodes: an das Supporter-Abo gekoppelt (Nutzer-Feedback
|
/* Rabattcodes: an ein KONTO gekoppelt, seit 08.09.2026.
|
||||||
03.08.2026: "verbinde es mit dem Abo... wenn die Leute drauf drücken
|
|
||||||
wollen es nicht geht"). Eigener Knopf bleibt bestehen (führt weiter
|
Ursprünglich (03.08.2026) hing die Kachel am Abo — Nutzer-Feedback
|
||||||
eigenständig zu rabattcodes.html), wird aber nur für Supporter
|
damals: "verbinde es mit dem Abo... wenn die Leute drauf drücken
|
||||||
tatsächlich anklickbar — sonst erscheint ein Hinweis mit Link zum Abo
|
wollen es nicht geht". Am 08.09.2026 hat Filipe das umgestellt: "die
|
||||||
statt der Navigation. Prüfung ist bewusst rein clientseitig (derselbe
|
partner codes sollen auch schon für die leute sichtbar sein die
|
||||||
zwischengespeicherte Login-Stand wie beim Nav-Abo-Knopf, siehe
|
angemeldet sind". Grund dahinter: Die Bezahlung ist noch nicht
|
||||||
renderAboButton() in main.js) — kein Aufruf-Zwang gegen den Worker bei
|
freigeschaltet (abonnieren.html, "Coming soon…"), der Riegel war
|
||||||
jedem Seitenaufruf, und da hier (noch) keine echten Rabattcodes
|
also für niemanden zu überwinden.
|
||||||
angezeigt werden, ist eine reine Client-Sperre für den jetzigen Stand
|
|
||||||
ausreichend statt eines vollen Server-Gates. */
|
Der Knopf bleibt bestehen und führt weiter eigenständig zu
|
||||||
|
rabattcodes.html, ist aber nur mit Konto wirklich anklickbar — sonst
|
||||||
|
erscheint der Hinweis mit beiden Wegen (anmelden/registrieren, und
|
||||||
|
daneben das Abo) statt der Navigation.
|
||||||
|
|
||||||
|
⚠️ DIESELBE BEDINGUNG STEHT AUCH IN rabattcodes.html. Wer eine der
|
||||||
|
beiden ändert, muss die andere mitändern: Läuft nur diese hier auf,
|
||||||
|
kommt man mit Konto zwar auf die Seite, sieht dort aber die Sperre —
|
||||||
|
und andersherum blockiert die Kachel jemanden, der die Codes sehen
|
||||||
|
dürfte. pruef-rabattcodes.mjs vergleicht beide Seiten deshalb in
|
||||||
|
denselben drei Anmeldezuständen gegeneinander.
|
||||||
|
|
||||||
|
Prüfung ist bewusst rein clientseitig (derselbe zwischengespeicherte
|
||||||
|
Login-Stand wie beim Nav-Abo-Knopf, siehe renderAboButton() in
|
||||||
|
main.js) — kein Aufruf-Zwang gegen den Worker bei jedem Seitenaufruf.
|
||||||
|
Es geht darum, wem etwas angeboten wird, nicht darum, ein Geheimnis
|
||||||
|
zu hüten: Ein Rabattcode steht ohnehin in jedem geteilten
|
||||||
|
Bildschirmfoto. */
|
||||||
.card-rabatt.gesperrt { cursor: not-allowed; }
|
.card-rabatt.gesperrt { cursor: not-allowed; }
|
||||||
.card-rabatt.gesperrt:hover { transform: none; }
|
.card-rabatt.gesperrt:hover { transform: none; }
|
||||||
.rabatt-gesperrt-hinweis {
|
.rabatt-gesperrt-hinweis {
|
||||||
@@ -45,6 +62,10 @@
|
|||||||
}
|
}
|
||||||
.rabatt-gesperrt-hinweis[hidden] { display: none; }
|
.rabatt-gesperrt-hinweis[hidden] { display: none; }
|
||||||
.rabatt-gesperrt-hinweis p { color: #ffe9a8; margin: 0; flex: 1 1 260px; font-size: .95rem; }
|
.rabatt-gesperrt-hinweis p { color: #ffe9a8; margin: 0; flex: 1 1 260px; font-size: .95rem; }
|
||||||
|
/* Zwei Wege nebeneinander (Wunsch 08.09.2026: "beides anbieten") — die
|
||||||
|
eigene Reihe hält sie beim Umbruch zusammen, statt den Abo-Knopf
|
||||||
|
allein in die nächste Zeile rutschen zu lassen. */
|
||||||
|
.rabatt-gesperrt-knoepfe { display: flex; gap: .6rem; flex-wrap: wrap; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-links-seite.jpg');--page-bg-mobile:url('/assets/img/bg-links-seite-mobile.jpg');">
|
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-links-seite.jpg');--page-bg-mobile:url('/assets/img/bg-links-seite-mobile.jpg');">
|
||||||
@@ -70,16 +91,19 @@
|
|||||||
<div style="max-width:1040px;margin:0 auto;">
|
<div style="max-width:1040px;margin:0 auto;">
|
||||||
<a class="card card-brand card-feature card-feature-wide card-rabatt" href="rabattcodes.html" id="card-rabattcodes">
|
<a class="card card-brand card-feature card-feature-wide card-rabatt" href="rabattcodes.html" id="card-rabattcodes">
|
||||||
<span class="card-feature-ring" aria-hidden="true"></span>
|
<span class="card-feature-ring" aria-hidden="true"></span>
|
||||||
<span class="card-feature-badge" id="rabatt-badge" data-i18n="lk_rabatt_badge">🔒 Nur für Supporter</span>
|
<span class="card-feature-badge" id="rabatt-badge" data-i18n="lk_rabatt_badge">🔒 Nur mit Konto</span>
|
||||||
<span class="icon-badge">🏷️</span>
|
<span class="icon-badge">🏷️</span>
|
||||||
<span class="card-feature-text">
|
<span class="card-feature-text">
|
||||||
<h3 data-i18n="lk_rabatt_h3">Rabattcodes</h3>
|
<h3 data-i18n="lk_rabatt_h3">Rabattcodes</h3>
|
||||||
<p class="card-feature-desc" data-i18n="lk_rabatt_desc">Codes von Dogis Partnern — exklusiv für Dogfather-Supporter.</p>
|
<p class="card-feature-desc" data-i18n="lk_rabatt_desc">Codes von Dogis Partnern — für alle mit einem Konto.</p>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="rabatt-gesperrt-hinweis" id="rabatt-gesperrt-hinweis" hidden>
|
<div class="rabatt-gesperrt-hinweis" id="rabatt-gesperrt-hinweis" hidden>
|
||||||
<p data-i18n="lk_rabatt_gesperrt_hinweis">🔒 Rabattcodes sind nur für Dogfather-Supporter zugänglich. Werde jetzt Supporter, um sie freizuschalten.</p>
|
<p data-i18n="lk_rabatt_gesperrt_hinweis">🔒 Die Rabattcodes gibt es für alle mit einem Konto. Melde dich an oder registriere dich kostenlos — dann sind sie da.</p>
|
||||||
<a class="btn btn-primary" href="abonnieren.html" data-i18n="lk_rabatt_btn_abo">Jetzt Supporter werden 👑</a>
|
<span class="rabatt-gesperrt-knoepfe">
|
||||||
|
<a class="btn btn-primary" href="abonnieren.html" data-i18n="lk_rabatt_btn_anmelden">Anmelden oder registrieren</a>
|
||||||
|
<a class="btn btn-outline" href="abonnieren.html" data-i18n="lk_rabatt_btn_abo">Supporter werden 👑</a>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -159,7 +183,7 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<div id="site-footer"></div>
|
<div id="site-footer"></div>
|
||||||
<script src="assets/js/i18n-links.js?v=20260828e"></script>
|
<script src="assets/js/i18n-links.js?v=20260908a"></script>
|
||||||
<script src="assets/js/main.js?v=20260828e"></script>
|
<script src="assets/js/main.js?v=20260828e"></script>
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
@@ -172,12 +196,44 @@
|
|||||||
// Gleicher zwischengespeicherter Login-/Abo-Stand wie beim Nav-Abo-
|
// Gleicher zwischengespeicherter Login-/Abo-Stand wie beim Nav-Abo-
|
||||||
// Knopf (renderAboButton() in main.js) — kein API-Aufruf bei jedem
|
// Knopf (renderAboButton() in main.js) — kein API-Aufruf bei jedem
|
||||||
// Seitenaufruf nötig.
|
// Seitenaufruf nötig.
|
||||||
|
//
|
||||||
|
// Seit 08.09.2026 entscheidet das KONTO ("supporterToken", beim Login
|
||||||
|
// gesetzt, beim Logout entfernt) statt des Abo-Status. Der Abo-Stand
|
||||||
|
// wird als Sicherheitsnetz weiter mitgelesen, damit niemand Zugang
|
||||||
|
// verliert, den er gestern hatte. Begründung im CSS-Kopf oben; DIESELBE
|
||||||
|
// Bedingung steht in rabattcodes.html und muss dort mitgeändert werden.
|
||||||
|
var angemeldet = !!localStorage.getItem("supporterToken");
|
||||||
var status = localStorage.getItem("supporterSubStatus");
|
var status = localStorage.getItem("supporterSubStatus");
|
||||||
var hatAbo = ["active", "pending", "suspended", "cancelled"].indexOf(status) !== -1;
|
var hatAbo = ["active", "pending", "suspended", "cancelled"].indexOf(status) !== -1;
|
||||||
|
var darfSehen = angemeldet || hatAbo;
|
||||||
|
|
||||||
if (hatAbo) {
|
if (darfSehen) {
|
||||||
karte.classList.remove("gesperrt");
|
karte.classList.remove("gesperrt");
|
||||||
if (badge && window.dogiUebersetzen) badge.textContent = window.dogiUebersetzen("lk_rabatt_badge_frei");
|
/* DEN SCHLÜSSEL TAUSCHEN, NICHT DEN TEXT.
|
||||||
|
|
||||||
|
Vorher stand hier nur `badge.textContent = ...`. Das hielt genau
|
||||||
|
so lange, bis applyTranslations() das nächste Mal lief — und es
|
||||||
|
läuft danach noch mindestens einmal: dogiSiteTexteLaden() holt
|
||||||
|
die Texte aus der Verwaltung und übersetzt anschließend erneut
|
||||||
|
(main.js), ebenso jeder Sprachwechsel und jede nahtlose
|
||||||
|
Navigation. applyTranslations() liest den Schlüssel aus dem
|
||||||
|
data-i18n-Attribut — stand dort weiter "lk_rabatt_badge", war
|
||||||
|
das Schloss sofort wieder da.
|
||||||
|
|
||||||
|
Der Fehler war seit dem 03.08.2026 drin und ist nie aufgefallen,
|
||||||
|
weil bis zum 08.09.2026 niemand in den freigeschalteten Zustand
|
||||||
|
kommen KONNTE (das Abo ist noch nicht bezahlbar). Seit die
|
||||||
|
Kachel am Konto hängt, hätte jeder Angemeldete auf einer offenen
|
||||||
|
Kachel ein Schloss gesehen.
|
||||||
|
|
||||||
|
Mit dem getauschten Attribut ist jeder weitere Aufruf von
|
||||||
|
applyTranslations() harmlos — er schreibt jetzt selbst das
|
||||||
|
Richtige hin. Der textContent daneben ist nur dafür da, dass es
|
||||||
|
schon vor dem nächsten Aufruf stimmt. */
|
||||||
|
if (badge) {
|
||||||
|
badge.setAttribute("data-i18n", "lk_rabatt_badge_frei");
|
||||||
|
if (window.dogiUebersetzen) badge.textContent = window.dogiUebersetzen("lk_rabatt_badge_frei");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+143
-34
@@ -1,12 +1,25 @@
|
|||||||
/* Prüft die Rabattcode-Seite mit dem ersten echten Partnercode (DOGI10).
|
/* Prüft die Rabattcodes mit dem ersten echten Partnercode (DOGI10) —
|
||||||
|
auf BEIDEN Seiten, auf denen sie vorkommen.
|
||||||
|
|
||||||
|
WARUM ZWEI SEITEN IN EINER PRÜFUNG
|
||||||
|
|
||||||
|
Die Bedingung "wer darf die Codes sehen" steht doppelt im Haus: in
|
||||||
|
links.html an der Kachel und in rabattcodes.html an der Seite selbst.
|
||||||
|
Ändert jemand nur eine davon, entsteht ein Fehler, den keine der
|
||||||
|
beiden für sich zeigt — man kommt mit Konto zwar auf die Seite und
|
||||||
|
sieht dort die Sperre, oder die Kachel blockiert jemanden, der die
|
||||||
|
Codes sehen dürfte. Geprüft wird deshalb beides gegeneinander.
|
||||||
|
|
||||||
WAS HIER SCHIEFGEHEN KANN, UND WARUM MAN ES NICHT SIEHT
|
WAS HIER SCHIEFGEHEN KANN, UND WARUM MAN ES NICHT SIEHT
|
||||||
|
|
||||||
Die Seite hat zwei Zustände, und man bekommt immer nur einen davon zu
|
Man bekommt immer nur einen Zustand zu sehen. Wer im Browser
|
||||||
sehen: Ohne Supporter-Abo die Sperre, mit Abo die Codekarte. Wer im
|
nachschaut, prüft also ein Drittel. Alle drei stehen hier drin:
|
||||||
Browser nachschaut, prüft also die Hälfte. Beide Richtungen stehen
|
ausgeloggt, angemeldet ohne Abo, angemeldet mit Abo. Der mittlere ist
|
||||||
deshalb hier drin — auch die Gegenprobe, dass die Karte OHNE Abo
|
der, um den es seit dem 08.09.2026 geht (Filipe: "die partner codes
|
||||||
wirklich verschwunden ist und nicht bloss weiter unten steht.
|
sollen auch schon für die leute sichtbar sein die angemeldet sind") —
|
||||||
|
ohne ihn prüfte man weiter nur die zwei, die schon vorher gingen.
|
||||||
|
Dazu jeweils der KLICK: Eine Kachel, die richtig aussieht und
|
||||||
|
trotzdem nicht weiterführt, fällt sonst niemandem auf.
|
||||||
|
|
||||||
Dazu vier Dinge, die im Bild richtig aussehen und trotzdem falsch
|
Dazu vier Dinge, die im Bild richtig aussehen und trotzdem falsch
|
||||||
sein können:
|
sein können:
|
||||||
@@ -62,7 +75,7 @@ const srv = createServer((q, r) => {
|
|||||||
r.writeHead(404).end("");
|
r.writeHead(404).end("");
|
||||||
});
|
});
|
||||||
await new Promise((r) => srv.listen(4331, r));
|
await new Promise((r) => srv.listen(4331, r));
|
||||||
const URL = "http://127.0.0.1:4331/rabattcodes.html";
|
const BASIS = "http://127.0.0.1:4331";
|
||||||
|
|
||||||
/* Erwartungswerte. Sie stammen aus dem Shop, nicht aus dem Codenamen:
|
/* Erwartungswerte. Sie stammen aus dem Shop, nicht aus dem Codenamen:
|
||||||
/home/vandiy/vans-diy-bastelbedarf/src/content/partnercodes.json
|
/home/vandiy/vans-diy-bastelbedarf/src/content/partnercodes.json
|
||||||
@@ -83,10 +96,28 @@ function pruefe(name, ok, zusatz) {
|
|||||||
|
|
||||||
const browser = await chromium.launch();
|
const browser = await chromium.launch();
|
||||||
|
|
||||||
/* Eine Seite im gewünschten Zustand öffnen. `abo` schaltet die Sperre,
|
/* DIE DREI ANMELDEZUSTAENDE, die im Browser wirklich vorkommen.
|
||||||
`zeit` stellt die Uhr (nur Date, die Zeitgeber laufen weiter — sonst
|
|
||||||
stünde main.js still). */
|
supporter.js legt beim Login "supporterToken" an und stellt den
|
||||||
async function seiteOeffnen({ abo = true, zeit = null, sprache = "de", viewport, reducedMotion } = {}) {
|
Abo-Stand als "supporterSubStatus" daneben -- "none", wenn ein Konto
|
||||||
|
besteht, aber nichts bezahlt ist (supporter.html, /supporter/me).
|
||||||
|
Beim Logout verschwinden beide zusammen (clearToken).
|
||||||
|
|
||||||
|
Der MITTLERE Zustand ist der, um den es seit dem 08.09.2026 geht: Wer
|
||||||
|
nur ein Konto hat, muss die Codes sehen. Ohne ihn pruefte man weiter
|
||||||
|
nur die zwei Zustaende, die auch vorher schon funktioniert haben. */
|
||||||
|
const ZUSTAENDE = [
|
||||||
|
{ schluessel: "aus", name: "ausgeloggt", token: null, status: null, darfSehen: false },
|
||||||
|
{ schluessel: "konto", name: "angemeldet, kein Abo", token: "pruef-tok", status: "none", darfSehen: true },
|
||||||
|
{ schluessel: "abo", name: "angemeldet mit Abo", token: "pruef-tok", status: "active", darfSehen: true },
|
||||||
|
];
|
||||||
|
const zustandVon = (k) => ZUSTAENDE.find((z) => z.schluessel === k);
|
||||||
|
|
||||||
|
/* Eine Seite im gewünschten Zustand öffnen. `zeit` stellt die Uhr (nur
|
||||||
|
Date, die Zeitgeber laufen weiter — sonst stünde main.js still). */
|
||||||
|
async function seiteOeffnen({ zustand = "konto", seite = "/rabattcodes.html",
|
||||||
|
zeit = null, sprache = "de", viewport, reducedMotion } = {}) {
|
||||||
|
const z = zustandVon(zustand);
|
||||||
const ctx = await browser.newContext({
|
const ctx = await browser.newContext({
|
||||||
viewport: viewport || { width: 1280, height: 1000 },
|
viewport: viewport || { width: 1280, height: 1000 },
|
||||||
permissions: ["clipboard-read", "clipboard-write"],
|
permissions: ["clipboard-read", "clipboard-write"],
|
||||||
@@ -94,34 +125,112 @@ async function seiteOeffnen({ abo = true, zeit = null, sprache = "de", viewport,
|
|||||||
});
|
});
|
||||||
const p = await ctx.newPage();
|
const p = await ctx.newPage();
|
||||||
if (zeit) await p.clock.setFixedTime(zeit);
|
if (zeit) await p.clock.setFixedTime(zeit);
|
||||||
await p.addInitScript(([a, s]) => {
|
await p.addInitScript(([token, status, spr]) => {
|
||||||
if (a) localStorage.setItem("supporterSubStatus", "active");
|
if (token) localStorage.setItem("supporterToken", token);
|
||||||
|
else localStorage.removeItem("supporterToken");
|
||||||
|
if (status) localStorage.setItem("supporterSubStatus", status);
|
||||||
else localStorage.removeItem("supporterSubStatus");
|
else localStorage.removeItem("supporterSubStatus");
|
||||||
localStorage.setItem("dogi-sprache", s);
|
localStorage.setItem("dogi-sprache", spr);
|
||||||
}, [abo, sprache]);
|
}, [z.token, z.status, sprache]);
|
||||||
await p.goto(URL, { waitUntil: "domcontentloaded" });
|
await p.goto(BASIS + seite, { waitUntil: "domcontentloaded" });
|
||||||
await p.waitForTimeout(700);
|
await p.waitForTimeout(700);
|
||||||
return { ctx, p };
|
return { ctx, p };
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===================================================================
|
/* ===================================================================
|
||||||
1 — Die Sperre, in BEIDE Richtungen
|
1 — Wer die Codes sieht: drei Zustaende, ZWEI Seiten
|
||||||
|
|
||||||
|
Die Bedingung steht doppelt im Haus (links.html und rabattcodes.html)
|
||||||
|
und muss an beiden Stellen gleich lauten. Laeuft nur eine davon auf,
|
||||||
|
entsteht ein Fehler, den keine der beiden Seiten fuer sich zeigt: Man
|
||||||
|
kommt mit Konto zwar auf die Seite, sieht dort aber die Sperre -- oder
|
||||||
|
die Kachel blockiert jemanden, der die Codes sehen duerfte. Deshalb
|
||||||
|
wird hier nicht nur jede Seite geprueft, sondern auch, dass beide
|
||||||
|
dasselbe sagen.
|
||||||
=================================================================== */
|
=================================================================== */
|
||||||
console.log("\n=== Supporter-Sperre ===");
|
console.log("\n=== Wer die Codes sieht (drei Anmeldezustände, beide Seiten) ===");
|
||||||
for (const [abo, sichtbar] of [[true, "Karte"], [false, "Sperre"]]) {
|
for (const z of ZUSTAENDE) {
|
||||||
const { ctx, p } = await seiteOeffnen({ abo });
|
const soll = z.darfSehen;
|
||||||
const z = await p.evaluate(() => ({
|
|
||||||
|
const a = await seiteOeffnen({ zustand: z.schluessel });
|
||||||
|
const r = await a.p.evaluate(() => ({
|
||||||
karte: !document.getElementById("rc-inhalt").hidden,
|
karte: !document.getElementById("rc-inhalt").hidden,
|
||||||
sperre: !document.getElementById("rc-gesperrt").hidden,
|
sperre: !document.getElementById("rc-gesperrt").hidden,
|
||||||
codeSichtbar: !!document.getElementById("rc-code")?.checkVisibility?.(),
|
codeSichtbar: !!document.getElementById("rc-code")?.checkVisibility?.(),
|
||||||
}));
|
}));
|
||||||
const lage = abo ? "Mit Abo" : "Ohne Abo";
|
pruefe(`[${z.name}] rabattcodes.html zeigt ${soll ? "die Codes" : "die Sperre"}`,
|
||||||
pruefe(`${lage}: ${sichtbar} steht da`,
|
r.karte === soll && r.sperre === !soll, `Karte=${r.karte} Sperre=${r.sperre}`);
|
||||||
z.karte === abo && z.sperre === !abo, `Karte=${z.karte} Sperre=${z.sperre}`);
|
/* Gegenprobe: "hidden" ist ein Attribut, kein Beweis. */
|
||||||
/* Gegenprobe: "hidden" ist ein Attribut, kein Beweis. Ohne Abo darf
|
pruefe(`[${z.name}] rabattcodes.html: Code ist ${soll ? "sichtbar" : "unsichtbar"}`,
|
||||||
der Code auch tatsächlich nicht auf dem Schirm sein. */
|
r.codeSichtbar === soll, `sichtbar=${r.codeSichtbar}`);
|
||||||
pruefe(`${lage}: Code ist ${abo ? "sichtbar" : "unsichtbar"}`,
|
await a.ctx.close();
|
||||||
z.codeSichtbar === abo, `sichtbar=${z.codeSichtbar}`);
|
|
||||||
|
const b = await seiteOeffnen({ zustand: z.schluessel, seite: "/links.html" });
|
||||||
|
const l = await b.p.evaluate(() => ({
|
||||||
|
gesperrt: document.getElementById("card-rabattcodes").classList.contains("gesperrt"),
|
||||||
|
band: document.getElementById("rabatt-badge")?.textContent.trim(),
|
||||||
|
}));
|
||||||
|
pruefe(`[${z.name}] links.html: Kachel ist ${soll ? "offen" : "gesperrt"}`,
|
||||||
|
l.gesperrt === !soll, `gesperrt=${l.gesperrt}, Band „${l.band}“`);
|
||||||
|
/* Das BAND muss zur Kachel passen. Ein Schloss auf einer offenen Kachel
|
||||||
|
sagt dem Angemeldeten das Gegenteil von dem, was gilt -- und genau das
|
||||||
|
stand dort: Der Text wurde per Skript gesetzt, aber applyTranslations()
|
||||||
|
schrieb ihn aus dem data-i18n-Attribut wieder zurueck. */
|
||||||
|
pruefe(`[${z.name}] links.html: Band sagt „${soll ? "✓ Freigeschaltet" : "🔒 Nur mit Konto"}“`,
|
||||||
|
l.band === (soll ? "✓ Freigeschaltet" : "🔒 Nur mit Konto"), l.band);
|
||||||
|
/* GEGENPROBE GEGEN GENAU DEN RUECKFALL: eine erneute Uebersetzung.
|
||||||
|
Der Sprachwechsel loest applyTranslations() aus, ohne Netz und ohne
|
||||||
|
Warten -- mit der alten Fassung stand danach wieder das Schloss da.
|
||||||
|
Eine Pruefung, die den Fehler nicht ausloesen kann, haette ihn auch
|
||||||
|
nicht gefunden. */
|
||||||
|
const nachWechsel = await b.p.evaluate(() => {
|
||||||
|
document.querySelector(".sprach-schalter [data-sprache='en']").click();
|
||||||
|
return document.getElementById("rabatt-badge").textContent.trim();
|
||||||
|
});
|
||||||
|
pruefe(`[${z.name}] links.html: Band überlebt eine erneute Übersetzung`,
|
||||||
|
nachWechsel === (soll ? "✓ Unlocked" : "🔒 Account required"), nachWechsel);
|
||||||
|
pruefe(`[${z.name}] beide Seiten sind sich einig`,
|
||||||
|
l.gesperrt === !r.karte, `links gesperrt=${l.gesperrt}, rabattcodes offen=${r.karte}`);
|
||||||
|
|
||||||
|
/* Und was passiert beim KLICK? Das ist die Frage, um die es geht --
|
||||||
|
eine Kachel, die richtig aussieht und trotzdem nicht weiterfuehrt,
|
||||||
|
haetten die Zeilen oben nicht bemerkt. */
|
||||||
|
await b.p.click("#card-rabattcodes");
|
||||||
|
await b.p.waitForTimeout(700);
|
||||||
|
const nach = b.p.url();
|
||||||
|
if (soll) {
|
||||||
|
pruefe(`[${z.name}] Klick auf die Kachel führt zu den Codes`,
|
||||||
|
nach.endsWith("/rabattcodes.html"), nach);
|
||||||
|
} else {
|
||||||
|
const hinweisDa = await b.p.evaluate(() =>
|
||||||
|
!document.getElementById("rabatt-gesperrt-hinweis").hidden);
|
||||||
|
pruefe(`[${z.name}] Klick führt nicht weiter, sondern zeigt den Hinweis`,
|
||||||
|
nach.endsWith("/links.html") && hinweisDa, `${nach}, Hinweis=${hinweisDa}`);
|
||||||
|
}
|
||||||
|
await b.ctx.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===================================================================
|
||||||
|
1b — Die Sperre bietet BEIDE Wege an (Wunsch 08.09.2026)
|
||||||
|
|
||||||
|
Der alte Knopf schickte Ausgeloggte allein aufs Abo. Das ist noch gar
|
||||||
|
nicht bezahlbar ("Coming soon" auf abonnieren.html), und fuer die
|
||||||
|
Codes reicht ein kostenloses Konto -- der Weg dorthin muss deshalb
|
||||||
|
der erste sein.
|
||||||
|
=================================================================== */
|
||||||
|
console.log("\n=== Zwei Wege für Ausgeloggte ===");
|
||||||
|
for (const [seite, wahl] of [["/rabattcodes.html", "#rc-gesperrt .btn"],
|
||||||
|
["/links.html", "#rabatt-gesperrt-hinweis .btn"]]) {
|
||||||
|
const { ctx, p } = await seiteOeffnen({ zustand: "aus", seite });
|
||||||
|
if (seite.endsWith("links.html")) await p.click("#card-rabattcodes");
|
||||||
|
await p.waitForTimeout(400);
|
||||||
|
const knoepfe = await p.$$eval(wahl, (els) =>
|
||||||
|
els.map((e) => ({ text: e.textContent.trim(), href: e.getAttribute("href") })));
|
||||||
|
const zumKonto = knoepfe.filter((k) => k.href === "abonnieren.html");
|
||||||
|
pruefe(`${seite}: Weg zum Konto UND zum Abo vorhanden`, zumKonto.length === 2,
|
||||||
|
knoepfe.map((k) => `${k.text} -> ${k.href}`).join(" | "));
|
||||||
|
pruefe(`${seite}: der erste Weg ist der kostenlose`,
|
||||||
|
/registrier|anmeld/i.test(zumKonto[0] ? zumKonto[0].text : ""), zumKonto[0] && zumKonto[0].text);
|
||||||
await ctx.close();
|
await ctx.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +239,7 @@ for (const [abo, sichtbar] of [[true, "Karte"], [false, "Sperre"]]) {
|
|||||||
=================================================================== */
|
=================================================================== */
|
||||||
console.log("\n=== Partnersiegel ===");
|
console.log("\n=== Partnersiegel ===");
|
||||||
{
|
{
|
||||||
const { ctx, p } = await seiteOeffnen({});
|
const { ctx, p } = await seiteOeffnen();
|
||||||
await p.waitForFunction(() => {
|
await p.waitForFunction(() => {
|
||||||
const i = document.querySelector(".rc-medaillon img");
|
const i = document.querySelector(".rc-medaillon img");
|
||||||
return i && i.complete && i.naturalWidth > 0;
|
return i && i.complete && i.naturalWidth > 0;
|
||||||
@@ -176,7 +285,7 @@ console.log("\n=== Partnersiegel ===");
|
|||||||
=================================================================== */
|
=================================================================== */
|
||||||
console.log("\n=== Code und Konditionen ===");
|
console.log("\n=== Code und Konditionen ===");
|
||||||
{
|
{
|
||||||
const { ctx, p } = await seiteOeffnen({});
|
const { ctx, p } = await seiteOeffnen();
|
||||||
const z = await p.evaluate(() => {
|
const z = await p.evaluate(() => {
|
||||||
const knopf = document.getElementById("rc-code");
|
const knopf = document.getElementById("rc-code");
|
||||||
const link = document.querySelector('.rc-partner a.btn-primary');
|
const link = document.querySelector('.rc-partner a.btn-primary');
|
||||||
@@ -216,7 +325,7 @@ console.log("\n=== Code und Konditionen ===");
|
|||||||
=================================================================== */
|
=================================================================== */
|
||||||
console.log("\n=== Kopieren ===");
|
console.log("\n=== Kopieren ===");
|
||||||
{
|
{
|
||||||
const { ctx, p } = await seiteOeffnen({});
|
const { ctx, p } = await seiteOeffnen();
|
||||||
/* Vorher: die Erfolgsmeldung darf NICHT stehen. Ohne diese Zeile
|
/* Vorher: die Erfolgsmeldung darf NICHT stehen. Ohne diese Zeile
|
||||||
würde eine dauerhaft sichtbare Meldung als Erfolg durchgehen. */
|
würde eine dauerhaft sichtbare Meldung als Erfolg durchgehen. */
|
||||||
const vorher = await p.evaluate(() => !document.getElementById("rc-echo-ok").hidden);
|
const vorher = await p.evaluate(() => !document.getElementById("rc-echo-ok").hidden);
|
||||||
@@ -321,13 +430,13 @@ console.log("\n=== Handy und Bewegungsarmut ===");
|
|||||||
await ctx.close();
|
await ctx.close();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const { ctx, p } = await seiteOeffnen({});
|
const { ctx, p } = await seiteOeffnen();
|
||||||
await p.waitForTimeout(500);
|
await p.waitForTimeout(500);
|
||||||
await p.locator("#rc-partner").screenshot({ path: "pruef-rabattcodes-karte.png" });
|
await p.locator("#rc-partner").screenshot({ path: "pruef-rabattcodes-karte.png" });
|
||||||
await ctx.close();
|
await ctx.close();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const { ctx, p } = await seiteOeffnen({ abo: false });
|
const { ctx, p } = await seiteOeffnen({ zustand: "aus" });
|
||||||
await p.screenshot({ path: "pruef-rabattcodes-gesperrt.png", fullPage: true });
|
await p.screenshot({ path: "pruef-rabattcodes-gesperrt.png", fullPage: true });
|
||||||
await ctx.close();
|
await ctx.close();
|
||||||
}
|
}
|
||||||
@@ -342,7 +451,7 @@ srv.close();
|
|||||||
sondern ein stiller Aussetzer (Erkenntnis 28.08.2026). Die Zahl unten
|
sondern ein stiller Aussetzer (Erkenntnis 28.08.2026). Die Zahl unten
|
||||||
wird beim Erweitern mit angehoben.
|
wird beim Erweitern mit angehoben.
|
||||||
=================================================================== */
|
=================================================================== */
|
||||||
const MINDESTENS = 34;
|
const MINDESTENS = 60;
|
||||||
const fehl = ergebnisse.filter((e) => !e.ok);
|
const fehl = ergebnisse.filter((e) => !e.ok);
|
||||||
console.log(`\n${ergebnisse.length} Prüfungen, ${fehl.length} fehlgeschlagen.`);
|
console.log(`\n${ergebnisse.length} Prüfungen, ${fehl.length} fehlgeschlagen.`);
|
||||||
console.log("Bildschirmfotos: pruef-rabattcodes-karte.png, -handy.png, -gesperrt.png");
|
console.log("Bildschirmfotos: pruef-rabattcodes-karte.png, -handy.png, -gesperrt.png");
|
||||||
|
|||||||
+53
-13
@@ -31,11 +31,13 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gesperrt-Zustand: an das Supporter-Abo gekoppelt (Nutzer-Feedback
|
/* Gesperrt-Zustand. Er hängt seit dem 08.09.2026 am KONTO, nicht mehr
|
||||||
03.08.2026), gleiche Prüfung wie die Karte auf links.html. Direkter
|
am bezahlten Abo (Filipe: "die partner codes sollen auch schon für
|
||||||
Aufruf dieser Seite (Lesezeichen, geteilter Link) soll die Sperre
|
die leute sichtbar sein die angemeldet sind") — die Begründung steht
|
||||||
genauso zeigen wie der Knopf dort — nicht nur auf links.html blockiert
|
ausführlich beim Skript am Seitenende. Unverändert gilt: dieselbe
|
||||||
sein. */
|
Prüfung wie die Kachel auf links.html, damit der direkte Aufruf
|
||||||
|
(Lesezeichen, geteilter Link) genau dasselbe zeigt wie der Knopf
|
||||||
|
dort. Zwei Sperren, die auseinanderlaufen, sind schlimmer als eine. */
|
||||||
.code-gesperrt-siegel {
|
.code-gesperrt-siegel {
|
||||||
width: 96px; height: 96px;
|
width: 96px; height: 96px;
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
@@ -367,6 +369,16 @@
|
|||||||
}
|
}
|
||||||
.rc-partner.ist-abgelaufen .rc-code { cursor: not-allowed; opacity: .75; }
|
.rc-partner.ist-abgelaufen .rc-code { cursor: not-allowed; opacity: .75; }
|
||||||
|
|
||||||
|
/* Steht unter den beiden Knöpfen der Sperrkachel: ohne sie wäre
|
||||||
|
"Supporter werden" eine Falle, weil das Abo noch nicht bezahlbar
|
||||||
|
ist. */
|
||||||
|
.rc-abo-hinweis {
|
||||||
|
max-width: 44ch;
|
||||||
|
margin: 1rem auto 0;
|
||||||
|
font-size: .84rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
.rc-mehr {
|
.rc-mehr {
|
||||||
max-width: 620px;
|
max-width: 620px;
|
||||||
margin: 1.4rem auto 0;
|
margin: 1.4rem auto 0;
|
||||||
@@ -392,9 +404,9 @@
|
|||||||
<section class="hero page-bg">
|
<section class="hero page-bg">
|
||||||
<div class="hero-banner"><img src="/assets/img/bg-links.jpg" alt="" loading="eager" /></div>
|
<div class="hero-banner"><img src="/assets/img/bg-links.jpg" alt="" loading="eager" /></div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<span class="eyebrow" data-i18n="rc_eyebrow">🏷️ Für Team Dogi</span>
|
<span class="eyebrow" data-i18n="rc_eyebrow">🔒 Nur mit Konto</span>
|
||||||
<h1 data-i18n="rc_h1">Rabattcodes</h1>
|
<h1 data-i18n="rc_h1">Rabattcodes</h1>
|
||||||
<p class="lead worlds" data-i18n="rc_lead">Codes von Dogis Partnern — damit deine Community bares Geld spart.</p>
|
<p class="lead worlds" data-i18n="rc_lead">Codes von Dogis Partnern — für alle mit einem Konto im DOGFATHER UNIVERSE.</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -444,13 +456,17 @@
|
|||||||
<p class="rc-mehr" data-i18n="rc_mehr">Weitere Codes folgen, sobald die nächsten Kooperationen stehen.</p>
|
<p class="rc-mehr" data-i18n="rc_mehr">Weitere Codes folgen, sobald die nächsten Kooperationen stehen.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Nur für Nicht-Supporter sichtbar (siehe Skript unten) -->
|
<!-- Nur für Ausgeloggte sichtbar (siehe Skript unten) -->
|
||||||
<div class="card code-platzhalter" id="rc-gesperrt" hidden>
|
<div class="card code-platzhalter" id="rc-gesperrt" hidden>
|
||||||
<div class="code-gesperrt-siegel" aria-hidden="true">🔒</div>
|
<div class="code-gesperrt-siegel" aria-hidden="true">🔒</div>
|
||||||
<h2 data-i18n="rc_gesperrt_titel">Nur für Dogfather-Supporter</h2>
|
<h2 data-i18n="rc_gesperrt_titel">Melde dich an, dann sind sie da</h2>
|
||||||
<p data-i18n="rc_gesperrt_text">Rabattcodes sind ein exklusiver Vorteil der DogiCrew 🩵. Der erste Partnercode ist schon drin — werde jetzt Teil davon, um ihn freizuschalten.</p>
|
<p data-i18n="rc_gesperrt_text">Die Rabattcodes gibt es für alle mit einem Konto bei Dogfather — Registrieren ist kostenlos und dauert eine Minute. Der erste Partnercode wartet schon.</p>
|
||||||
<div class="btn-row" style="justify-content:center;margin-top:1.8rem;">
|
<div class="btn-row" style="justify-content:center;margin-top:1.8rem;">
|
||||||
<a class="btn btn-primary" href="abonnieren.html" data-i18n="rc_btn_abo">Jetzt Supporter werden 👑</a>
|
<a class="btn btn-primary" href="abonnieren.html" data-i18n="rc_btn_anmelden">Anmelden oder kostenlos registrieren</a>
|
||||||
|
<a class="btn btn-outline" href="abonnieren.html" data-i18n="rc_btn_abo">Supporter werden 👑</a>
|
||||||
|
</div>
|
||||||
|
<p class="rc-abo-hinweis" data-i18n="rc_abo_hinweis">Fürs Abo brauchst du ebenfalls erst ein Konto — es startet, sobald es offiziell live geht.</p>
|
||||||
|
<div class="btn-row" style="justify-content:center;margin-top:.6rem;">
|
||||||
<a class="btn btn-outline" href="links.html" data-i18n="rc_btn_zurueck">← Zurück zu allen Links</a>
|
<a class="btn btn-outline" href="links.html" data-i18n="rc_btn_zurueck">← Zurück zu allen Links</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -481,12 +497,36 @@
|
|||||||
var ABLAUF = "2026-09-30";
|
var ABLAUF = "2026-09-30";
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
/* WER DIE CODES SIEHT — seit 08.09.2026 das KONTO, nicht das Abo.
|
||||||
|
|
||||||
|
Anlass (Filipe): "die partner codes sollen auch schon für die leute
|
||||||
|
sichtbar sein die angemeldet sind." Der alte Riegel verlangte einen
|
||||||
|
Abo-Status. Der war zu diesem Zeitpunkt für NIEMANDEN erreichbar:
|
||||||
|
Die Bezahlung auf abonnieren.html steht auf "Coming soon", bis
|
||||||
|
Dogis PayPal-Business-Zugang da ist. Der erste echte Partnercode
|
||||||
|
wäre also hinter einer Tür gelegen, die sich gar nicht öffnen lässt.
|
||||||
|
|
||||||
|
"supporterToken" ist der Nachweis, dass jemand angemeldet ist — er
|
||||||
|
wird beim Login gesetzt und beim Logout wieder entfernt
|
||||||
|
(supporter.js, clearToken). "supporterSubStatus" sagt nur, OB und
|
||||||
|
wie bezahlt wird ("none", wenn ein Konto ohne Abo besteht).
|
||||||
|
|
||||||
|
Warum der Abo-Stand trotzdem noch mit abgefragt wird, obwohl er
|
||||||
|
ohne Token gar nicht vorkommen kann: Es ist ein Sicherheitsnetz.
|
||||||
|
Niemand, der die Codes gestern sehen konnte, soll sie heute
|
||||||
|
verlieren, nur weil ein Speicherstand anders aussieht als gedacht.
|
||||||
|
|
||||||
|
Die Prüfung ist bewusst rein clientseitig (wie vorher schon) — es
|
||||||
|
geht darum, wem etwas angeboten wird, nicht darum, ein Geheimnis zu
|
||||||
|
hüten. Der Code steht ohnehin in jedem geteilten Bildschirmfoto. */
|
||||||
|
var angemeldet = !!localStorage.getItem("supporterToken");
|
||||||
var status = localStorage.getItem("supporterSubStatus");
|
var status = localStorage.getItem("supporterSubStatus");
|
||||||
var hatAbo = ["active", "pending", "suspended", "cancelled"].indexOf(status) !== -1;
|
var hatAbo = ["active", "pending", "suspended", "cancelled"].indexOf(status) !== -1;
|
||||||
|
var darfSehen = angemeldet || hatAbo;
|
||||||
var inhalt = document.getElementById("rc-inhalt");
|
var inhalt = document.getElementById("rc-inhalt");
|
||||||
var gesperrt = document.getElementById("rc-gesperrt");
|
var gesperrt = document.getElementById("rc-gesperrt");
|
||||||
if (inhalt) inhalt.hidden = !hatAbo;
|
if (inhalt) inhalt.hidden = !darfSehen;
|
||||||
if (gesperrt) gesperrt.hidden = hatAbo;
|
if (gesperrt) gesperrt.hidden = darfSehen;
|
||||||
|
|
||||||
var karte = document.getElementById("rc-partner");
|
var karte = document.getElementById("rc-partner");
|
||||||
var knopf = document.getElementById("rc-code");
|
var knopf = document.getElementById("rc-code");
|
||||||
|
|||||||
Reference in New Issue
Block a user