Nutzer-Wunsch 20.08.2026: "eine richtig geile kachel ... wo die leute mit namen und tiktok namen mir eine nachricht schreiben können die ich in die verwaltung kriege, und dann kann ich die ausgewählten über die verwaltungsseite auf die website hinzufügen ... das wird mega persoenlich zu den fans, bitte wirklich krass geil speziell." - Neue, augenschonend gestaltete Einreich-Kachel auf stimmen.html: Name, TikTok-Name (optional), Nachricht -- landet NIE automatisch oeffentlich, sondern immer erst als Entwurf in der Verwaltung. Warmer Babyblau/Rosé-Farbverlauf, wandernder Lichtschein, pulsierendes Herz -- ersetzt die 3 ewigen "Hier steht bald..."-Platzhalterkarten. - Neue Verwaltungs-Sektion "💬 Stimmen verwalten": Warteschlange (offene zuerst), Freigeben/Ablehnen/Löschen pro Eintrag. - Freigegebene Stimmen erscheinen automatisch in einer neuen, spezielleren Zitat-Kartenoptik (großes Anführungszeichen, Name + TikTok-Chip) -- Abschnitt bleibt komplett unsichtbar, solange keine einzige freigegeben wurde. - Backend: neue Tabelle `testimonials` (Migration 0006), routes/ testimonials.js (oeffentliches Einreichen + Lesen freigegebener, admin-Warteschlange + Status/Loeschen mit neuer TESTIMONIALS_MANAGE- Berechtigung). 18 automatisierte Tests gegen eine Fake-DB bestanden. - Alles per Playwright visuell durchgespielt: leerer Zustand, Einreichen -> Erfolgsmeldung, freigegebene Stimmen-Anzeige, Verwaltungs-Warteschlange mit allen Aktionen. Backend-Teil (server-internal/, cloudflare-worker/migrations/) noch ohne Deploy-Zugriff -- Dogi muss ihn manuell auf dogiintern ausrollen. Co-Authored-By: Claude Opus 5 <[email protected]>
725 lines
40 KiB
HTML
725 lines
40 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de" data-theme="dogfather">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>DogiCrew 🩵 — DOGFATHER UNIVERSE</title>
|
|
<meta name="description" content="Unterstütze Dogfather dauerhaft mit der DogiCrew 🩵 und sammle exklusive Treueprämien — die Teddy-Kollektion entsteht in Kooperation mit VanVan." />
|
|
<link rel="icon" type="image/png" href="assets/img/favicon.png" />
|
|
<link rel="manifest" href="/manifest.json" />
|
|
<meta name="theme-color" content="#0b0d10" />
|
|
<meta property="og:type" content="website" />
|
|
<meta property="og:site_name" content="DOGFATHER UNIVERSE" />
|
|
<meta property="og:title" content="DogiCrew 🩵 — DOGFATHER UNIVERSE" />
|
|
<meta property="og:description" content="Unterstütze Dogfather dauerhaft mit der DogiCrew 🩵 und sammle exklusive Treueprämien — die Teddy-Kollektion entsteht in Kooperation mit VanVan." />
|
|
<meta property="og:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
|
<meta property="og:url" content="https://dogfather-universe.com/abonnieren.html" />
|
|
<meta name="twitter:card" content="summary_large_image" />
|
|
<meta name="twitter:title" content="DogiCrew 🩵 — DOGFATHER UNIVERSE" />
|
|
<meta name="twitter:description" content="Unterstütze Dogfather dauerhaft mit der DogiCrew 🩵 und sammle exklusive Treueprämien — die Teddy-Kollektion entsteht in Kooperation mit VanVan." />
|
|
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
|
|
|
<link rel="stylesheet" href="assets/css/main.css?v=20260820k" />
|
|
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820k" />
|
|
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820k" />
|
|
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820k" />
|
|
<style>
|
|
/* =====================================================================
|
|
Preis-/Anmelde-Kiste — komplett neu gestaltet (Nutzer-Feedback
|
|
03.08.2026: "das sieht ja richtig kake aus"). Ziel: dasselbe edle
|
|
Gold-Motiv wie beim Nav-Abo-Knopf/.btn-silver, klare visuelle
|
|
Hierarchie (Preis dominiert, Bedingungen dezent, Formular großzügig),
|
|
spürbar mehr Luft zwischen den Elementen statt der bisherigen dichten
|
|
Textwand. Bewusst KEIN max-width auf der Box selbst — soll exakt so
|
|
breit sein wie der umgebende .container (1180px), siehe Kommentar
|
|
unten bei .abo-preis-box.
|
|
===================================================================== */
|
|
.abo-preis-box {
|
|
width: 100%;
|
|
text-align: center;
|
|
position: relative;
|
|
isolation: isolate;
|
|
overflow: hidden;
|
|
padding: 2.6rem clamp(1.4rem, 5vw, 3.2rem) 3rem;
|
|
border: 1.5px solid rgba(212,175,55,.45);
|
|
background:
|
|
radial-gradient(circle at 22% 0%, rgba(212,175,55,.16), transparent 55%),
|
|
radial-gradient(circle at 82% 100%, rgba(139,92,246,.12), transparent 55%),
|
|
linear-gradient(180deg, rgba(23,27,33,.96), rgba(15,17,21,.98));
|
|
box-shadow: 0 0 0 1px rgba(212,175,55,.06) inset, 0 30px 60px -30px rgba(0,0,0,.6);
|
|
}
|
|
/* Feiner, ruhig schimmernder Goldrand oben — reines Deko-Element, kein
|
|
rotierendes Objekt (siehe dokumentierte Lektion: rotierende Ringe auf
|
|
nicht-runden Formen verzerren sich, deshalb hier nur ein sanftes
|
|
Auf-und-Ab-Glühen statt einer Drehung). */
|
|
.abo-preis-box::before {
|
|
content: "";
|
|
position: absolute; top: 0; left: 10%; right: 10%; height: 1px; z-index: 2;
|
|
background: linear-gradient(90deg, transparent, rgba(255,214,102,.9), transparent);
|
|
animation: abo-goldglanz 4.5s ease-in-out infinite;
|
|
}
|
|
@keyframes abo-goldglanz { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
|
|
|
|
/* Logo als leuchtendes Wasserzeichen im Kartenhintergrund (Nutzer-Wunsch
|
|
03.08.2026: "mein Logo integriert, als Hintergrund, richtig geil,
|
|
soll so geil dass man nicht davon wegkommt"). Freigestelltes Logo
|
|
(logo-dogfather-transparent.png, siehe gate.html-Lektion: Original
|
|
hatte einen weißen Hintergrund eingebrannt, hier bereits freigestellt)
|
|
— groß, mittig, mit pulsierender Gold/Lila-Glut dahinter. Sitzt per
|
|
z-index HINTER dem echten Karteninhalt (Preis/Formular), damit nichts
|
|
an Lesbarkeit verliert; .abo-preis-box hat dafür isolation:isolate +
|
|
overflow:hidden bekommen, damit die Glut nicht über den Kartenrand
|
|
hinausblutet (dieselbe dokumentierte Lektion wie beim TikTok-Button-
|
|
Glow). Bewusst KEINE Rotation des Logos selbst (nur Skalieren/
|
|
Verblassen) — ein Markenlogo, das sich dreht, würde zeitweise auf dem
|
|
Kopf stehen. */
|
|
.abo-preis-box .abo-logo-glut {
|
|
position: absolute; inset: -10%; z-index: -1; pointer-events: none;
|
|
background:
|
|
radial-gradient(circle at 50% 28%, rgba(255,233,168,.4) 0%, rgba(212,175,55,.16) 32%, transparent 62%),
|
|
radial-gradient(circle at 22% 75%, rgba(139,92,246,.22), transparent 55%),
|
|
radial-gradient(circle at 80% 80%, rgba(143,217,234,.16), transparent 55%);
|
|
animation: abo-logo-glut-puls 5s ease-in-out infinite;
|
|
}
|
|
@keyframes abo-logo-glut-puls { 0%, 100% { opacity: .75; } 50% { opacity: 1; } }
|
|
.abo-preis-box .abo-logo-wz {
|
|
/* Bewusst NICHT inset:0 über die ganze (sehr hohe) Karte — dadurch
|
|
wären background-position/mask-Prozentwerte relativ zur kompletten
|
|
Kartenhöhe (inkl. Formular) berechnet und kaum kontrollierbar. Eine
|
|
feste Zone oben (deckt Badge/Preis/Bedingungen ab) macht Position
|
|
und Ausblenden vorhersagbar und garantiert, dass die Eingabefelder
|
|
darunter sauber lesbar bleiben (Nutzer-Feedback: Logo lag vorher
|
|
über dem Namensfeld). */
|
|
position: absolute; top: 0; left: 0; right: 0; height: 420px; z-index: -1; pointer-events: none;
|
|
background-image: url('assets/img/logo-dogfather-transparent.png');
|
|
background-repeat: no-repeat;
|
|
background-position: center 6%;
|
|
background-size: min(62%, 320px) auto;
|
|
opacity: .4;
|
|
filter: drop-shadow(0 0 28px rgba(255,233,168,.65)) drop-shadow(0 0 56px rgba(139,92,246,.4));
|
|
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 45%, transparent 92%);
|
|
mask-image: linear-gradient(to bottom, #000 0%, #000 45%, transparent 92%);
|
|
animation: abo-logo-wz-atem 6s ease-in-out infinite;
|
|
}
|
|
@keyframes abo-logo-wz-atem {
|
|
0%, 100% { opacity: .32; transform: scale(.99); }
|
|
50% { opacity: .48; transform: scale(1.03); }
|
|
}
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.abo-preis-box .abo-logo-glut, .abo-preis-box .abo-logo-wz, .abo-preis-box::before { animation: none; }
|
|
}
|
|
|
|
.abo-preis-box .eyebrow {
|
|
display: inline-flex; align-items: center; gap: .5rem;
|
|
color: #ffe9a8; border-color: rgba(255,214,102,.5);
|
|
font-size: 1.3rem; letter-spacing: .1em;
|
|
}
|
|
.abo-preis-zahl {
|
|
font-size: clamp(2.6rem, 5vw, 3.4rem); font-weight: 800; color: #ffe9a8;
|
|
margin: .6rem 0 .2rem; letter-spacing: -.01em;
|
|
text-shadow: 0 0 28px rgba(255,214,102,.35);
|
|
}
|
|
.abo-preis-zahl small { font-size: 1.05rem; font-weight: 600; color: var(--text-muted); letter-spacing: 0; text-shadow: none; }
|
|
|
|
.abo-bedingungen {
|
|
list-style: none; padding: 0; text-align: left; max-width: 460px;
|
|
margin: 1.6rem auto 0; display: flex; flex-direction: column; gap: .55rem;
|
|
}
|
|
.abo-bedingungen li {
|
|
display: flex; align-items: flex-start; gap: .6rem;
|
|
color: var(--text-muted); font-size: .96rem; line-height: 1.5;
|
|
}
|
|
.abo-bedingungen li::before {
|
|
content: "✓"; flex-shrink: 0; width: 1.35rem; height: 1.35rem; margin-top: .05rem;
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
border-radius: 50%; font-size: .78rem; font-weight: 800;
|
|
color: #0b0d10; background: linear-gradient(135deg, #ffe9a8, #d4af37);
|
|
}
|
|
|
|
/* Widerrufsrecht-Checkbox (siehe agb.html Ziffer 6): NICHT vorausgewählt,
|
|
sperrt die PayPal-Zahlungsoptionen optisch + funktional (pointer-events),
|
|
bis sie aktiv angehakt wurde. */
|
|
.abo-widerruf-check {
|
|
display: flex; align-items: flex-start; gap: .65rem; text-align: left;
|
|
max-width: 460px; margin: 0 auto 1.1rem; padding: .85rem .95rem; border-radius: 12px;
|
|
background: rgba(255,255,255,.03); border: 1.5px solid rgba(139,92,246,.35);
|
|
font-size: .85rem; line-height: 1.5; color: var(--text-muted); cursor: pointer;
|
|
}
|
|
.abo-widerruf-check input[type="checkbox"] {
|
|
flex-shrink: 0; width: 1.15rem; height: 1.15rem; margin-top: .15rem; cursor: pointer; accent-color: #8b5cf6;
|
|
}
|
|
.abo-widerruf-check a { color: var(--accent); }
|
|
#paypal-button-container.paypal-gesperrt { opacity: .35; filter: grayscale(1); pointer-events: none; min-height: 45px; }
|
|
#paypal-gesperrt-hinweis { text-align: center; margin-top: .5rem; }
|
|
|
|
.abo-panel { max-width: 440px; margin: 2.2rem auto 0; }
|
|
.abo-panel[hidden] { display: none; }
|
|
|
|
.abo-field { margin-bottom: 1.2rem; text-align: left; }
|
|
.abo-field label {
|
|
display: block; font-size: .82rem; font-weight: 600; letter-spacing: .02em;
|
|
color: var(--text-muted); margin-bottom: .45rem;
|
|
}
|
|
.abo-field input {
|
|
display: block; width: 100%; box-sizing: border-box;
|
|
padding: .9rem 1.05rem; border-radius: 12px;
|
|
background: rgba(255,255,255,.035); border: 1.5px solid var(--border); color: var(--text);
|
|
font-size: 1.02rem; transition: border-color .15s ease, box-shadow .15s ease, background .15s ease;
|
|
}
|
|
.abo-field input::placeholder { color: rgba(154,164,178,.55); }
|
|
.abo-field input:focus {
|
|
outline: none; border-color: rgba(212,175,55,.7); background: rgba(255,255,255,.055);
|
|
box-shadow: 0 0 0 4px rgba(212,175,55,.12);
|
|
}
|
|
|
|
/* Registrieren/Login-Knöpfe: eigener Gold-Foil-Stil statt des generischen
|
|
.btn-primary (Nutzer-Feedback 03.08.2026: "viel spezieller" + Text
|
|
zentriert). Gleiche sichere Technik wie überall im Projekt — die
|
|
Fläche schimmert per background-position, NICHT per rotierendem Ring
|
|
(der würde auf dieser Pillenform verzerren, siehe dokumentierte
|
|
TikTok-Button-Lektion). */
|
|
.abo-panel .btn {
|
|
position: relative; isolation: isolate; overflow: hidden;
|
|
display: flex; align-items: center; justify-content: center;
|
|
padding: 1rem 1.4rem; border-radius: 14px; font-weight: 800; font-size: 1.04rem;
|
|
color: #1a1408; text-decoration: none; cursor: pointer;
|
|
border: 1.5px solid rgba(255,233,168,.65);
|
|
background: linear-gradient(120deg, #ffe9a8 0%, #d4af37 30%, #ffe9a8 55%, #fff2c9 78%, #d4af37 100%);
|
|
background-size: 280% 100%;
|
|
animation: abo-btn-shine 6s ease-in-out infinite;
|
|
box-shadow: 0 10px 26px -12px rgba(212,175,55,.55);
|
|
transition: transform .2s ease, box-shadow .2s ease;
|
|
}
|
|
.abo-panel .btn::before { content: none; }
|
|
.abo-panel .btn::after {
|
|
content: ""; position: absolute; inset: 0; z-index: 1;
|
|
background: linear-gradient(100deg, transparent 30%, rgba(255,255,255,.85) 48%, transparent 66%);
|
|
background-size: 240% 100%;
|
|
mix-blend-mode: overlay;
|
|
animation: abo-btn-glare 3.2s ease-in-out infinite;
|
|
pointer-events: none;
|
|
}
|
|
.abo-panel .btn:hover {
|
|
transform: translateY(-3px) scale(1.015);
|
|
box-shadow: 0 16px 34px -10px rgba(212,175,55,.65), 0 0 26px rgba(212,175,55,.4);
|
|
}
|
|
@keyframes abo-btn-shine { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } }
|
|
@keyframes abo-btn-glare { 0% { background-position: -80% 0; } 100% { background-position: 180% 0; } }
|
|
@media (prefers-reduced-motion: reduce) { .abo-panel .btn { animation: none; } .abo-panel .btn::after { animation: none; } }
|
|
|
|
.abo-fehler { color: #ff9a9a; font-size: .88rem; margin: .8rem 0 0; display: none; }
|
|
.abo-fehler.zeige { display: block; }
|
|
.abo-erfolg { color: #baf7d6; font-size: .88rem; margin: .8rem 0 0; display: none; }
|
|
.abo-erfolg.zeige { display: block; }
|
|
|
|
.abo-switch { text-align: center; margin-top: 1.4rem; font-size: .92rem; color: var(--text-muted); }
|
|
.abo-switch a { color: var(--accent); cursor: pointer; font-weight: 600; }
|
|
.abo-switch a:hover { text-decoration: underline; }
|
|
|
|
.abo-oder {
|
|
display: flex; align-items: center; gap: .8rem;
|
|
color: var(--text-muted); font-size: .78rem; text-transform: uppercase; letter-spacing: .08em;
|
|
margin: .3rem 0 1.4rem;
|
|
}
|
|
.abo-oder::before, .abo-oder::after { content: ""; flex: 1; height: 1px; background: var(--border); }
|
|
|
|
/* Google liefert seinen Knopf als eigenes iframe aus — die Innenfarben
|
|
(Schwarz/Weiß/Blau) lassen sich aus Sicherheitsgründen NICHT per CSS
|
|
umfärben. "Größer und passend zur Seite" wird deshalb über einen
|
|
eigenen Goldrahmen drumherum gelöst (derselbe Schimmer-Trick wie beim
|
|
Preis-Rahmen) plus einer Vergrößerung des Google-Knopfs selbst per
|
|
transform:scale — der Knopf bleibt dabei voll funktionsfähig, es wird
|
|
nur optisch skaliert. */
|
|
.abo-google-frame {
|
|
display: flex; justify-content: center; margin: 0 auto 1.3rem; padding: .55rem 0;
|
|
border-radius: 999px; border: 1.5px solid transparent;
|
|
background: linear-gradient(rgba(20,23,29,.5), rgba(20,23,29,.5)) padding-box,
|
|
linear-gradient(120deg, #d4af37, #ffe9a8, #d4af37, #fff2c9) border-box;
|
|
background-size: 100% 100%, 260% 100%;
|
|
animation: abo-btn-shine 6s ease-in-out infinite;
|
|
box-shadow: 0 10px 26px -12px rgba(212,175,55,.5);
|
|
}
|
|
.abo-google-frame > div { transform: scale(1.18); transform-origin: center; }
|
|
|
|
.abo-vorteile { max-width: 520px; margin: 1.6rem auto 0; display: flex; flex-direction: column; gap: .6rem; }
|
|
.abo-vorteile li { display: flex; gap: .65rem; align-items: baseline; color: var(--text-muted); font-size: .97rem; line-height: 1.5; }
|
|
.abo-vorteile li::before { content: "👑"; flex-shrink: 0; }
|
|
</style>
|
|
</head>
|
|
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-abonnieren.jpg');--page-bg-mobile:url('/assets/img/bg-abonnieren-mobile.jpg');">
|
|
<div id="site-header"></div>
|
|
|
|
<main>
|
|
<section class="hero page-bg">
|
|
<div class="hero-banner"><img src="/assets/img/bg-abonnieren.jpg" alt="Dogfather Supporter-Abo" loading="eager" /></div>
|
|
<div class="container">
|
|
<span class="eyebrow" data-i18n="ab_eyebrow">👑 DogiCrew 🩵</span>
|
|
<h1 data-i18n="ab_h1">Mehr als ein Abo — deine Unterstützung wird Teil unserer Geschichte</h1>
|
|
<p class="lead worlds" data-i18n="ab_lead">Kein gewöhnlicher Shop. Ein exklusives Dankeschön- und Treueprogramm für alle, die Dogfather dauerhaft unterstützen.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="section-tight">
|
|
<div class="container">
|
|
<div class="card abo-preis-box">
|
|
<div class="abo-logo-glut" aria-hidden="true"></div>
|
|
<div class="abo-logo-wz" aria-hidden="true"></div>
|
|
<span class="eyebrow" data-i18n="ab_preis_eyebrow">DogiCrew 🩵</span>
|
|
<!-- Bugfix/Nutzer-Wunsch 20.08.2026: Preis noch NICHT zeigen, solange die
|
|
Registrierung gesperrt ist (siehe .btn-gold-locked weiter unten) — sonst
|
|
wäre der Preis schon öffentlich, bevor überhaupt jemand abschließen kann.
|
|
Gleicher Chrome-Gold-Schimmer-Text wie beim gesperrten Knopf
|
|
(.btn-gold-locked-text), hier freistehend statt in einem Knopf. -->
|
|
<div class="abo-preis-zahl"><span class="btn-gold-locked-text" style="font-size:1em;" data-i18n="ab_kollektion_coming_soon">Coming soon…</span></div>
|
|
<p class="small muted" style="margin-top:-.6rem;margin-bottom:1rem;">Keine gesondert ausgewiesene MwSt. gemäß Kleinunternehmerregelung (Art. 57 des luxemburgischen TVA-Gesetzes) — keine weiteren Kosten.</p>
|
|
<ul class="abo-bedingungen">
|
|
<li data-i18n="ab_bed1">Monatliche automatische Zahlung über PayPal</li>
|
|
<li data-i18n="ab_bed2">Keine Mindestlaufzeit, jederzeit kündbar</li>
|
|
<li data-i18n="ab_bed3">Kündigung zum Ende des bereits bezahlten Zeitraums</li>
|
|
<li data-i18n="ab_bed4">Keine versteckten Zusatzkosten</li>
|
|
</ul>
|
|
|
|
<!-- Zustand 1: lädt (kurz, bis localStorage/Session geprüft ist) -->
|
|
<div class="abo-panel" id="panel-lade">
|
|
<p class="small" data-i18n="ab_laedt">Einen Moment …</p>
|
|
</div>
|
|
|
|
<!-- Professioneller Login: Google, sitzt über Registrierung/Login und
|
|
wird zusammen mit ihnen ein-/ausgeblendet (siehe Skript unten).
|
|
Ohne konfigurierte GOOGLE_CLIENT_ID bleibt der Bereich leer/
|
|
unsichtbar — der normale E-Mail-Code-Weg funktioniert immer. -->
|
|
<div class="abo-panel" id="panel-social-login" hidden>
|
|
<!-- Datenschutz: Googles Skript (und damit eine Verbindung/IP-Übertragung
|
|
zu Google) wird bewusst NICHT automatisch beim Seitenaufruf geladen,
|
|
sondern erst nach explizitem Klick hier — echtes Opt-in statt
|
|
versteckter Drittanbieter-Verbindung vor jeder Zustimmung. -->
|
|
<div id="google-consent-wrap" style="text-align:center;margin-bottom:1.1rem;" hidden>
|
|
<button type="button" id="google-consent-btn" class="btn btn-primary" style="width:100%;display:inline-flex;align-items:center;justify-content:center;gap:.6rem;">
|
|
<svg width="20" height="20" viewBox="0 0 48 48" aria-hidden="true" style="flex-shrink:0;">
|
|
<path fill="#FFC107" d="M43.611,20.083H42V20H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12s5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24s8.955,20,20,20s20-8.955,20-20C44,22.659,43.862,21.35,43.611,20.083z"/>
|
|
<path fill="#FF3D00" d="M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C16.318,4,9.656,8.337,6.306,14.691z"/>
|
|
<path fill="#4CAF50" d="M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z"/>
|
|
<path fill="#1976D2" d="M43.611,20.083H42V20H24v8h11.303c-0.792,2.237-2.231,4.166-4.087,5.571c0.001-0.001,0.002-0.001,0.003-0.002l6.19,5.238C36.971,39.205,44,34,44,24C44,22.659,43.862,21.35,43.611,20.083z"/>
|
|
</svg>
|
|
<span data-i18n="ab_google_consent_btn">Mit Google anmelden</span>
|
|
</button>
|
|
<p class="small muted" style="margin-top:.5rem;" data-i18n="ab_google_consent_hint">Beim Klick wird eine Verbindung zu Google hergestellt (deine IP-Adresse wird dabei übertragen).</p>
|
|
</div>
|
|
<div class="abo-google-frame" id="google-frame-wrap" hidden>
|
|
<div id="google-signin-button"></div>
|
|
</div>
|
|
<div class="abo-oder" data-i18n="ab_oder_email">oder mit E-Mail</div>
|
|
</div>
|
|
|
|
<!-- Zustand 2: Registrierung -->
|
|
<div class="abo-panel" id="panel-register" hidden>
|
|
<!-- Bugfix/Nutzer-Wunsch 20.08.2026 (Nachpruefung): Nur der Knopf war
|
|
gesperrt, die drei Felder ließen sich trotzdem antippen und
|
|
beschreiben ("ich kann immer nur was rein tippen, soll garnicht
|
|
möglich sein"). Jetzt wie das E-Mail-Feld im Login-Panel: disabled
|
|
statt nur readonly, damit auch Tastatur-/Screenreader-Nutzung
|
|
korrekt "nicht bedienbar" meldet. -->
|
|
<div class="abo-field">
|
|
<label for="reg-name" data-i18n="ab_feld_name">Name oder Anzeigename</label>
|
|
<input type="text" id="reg-name" maxlength="60" disabled />
|
|
</div>
|
|
<div class="abo-field">
|
|
<label for="reg-tiktok" data-i18n="ab_feld_tiktok">TikTok-Benutzername</label>
|
|
<input type="text" id="reg-tiktok" placeholder="@benutzername" maxlength="40" disabled />
|
|
</div>
|
|
<div class="abo-field">
|
|
<label for="reg-email" data-i18n="ab_feld_email">E-Mail-Adresse</label>
|
|
<input type="email" id="reg-email" maxlength="120" disabled />
|
|
</div>
|
|
<!-- Bugfix/Nutzer-Wunsch 20.08.2026: Die DogiCrew-Registrierung ist
|
|
technisch fertig, aber ohne Dogis echte PayPal-Business-Zugangsdaten
|
|
kann niemand wirklich zahlen (siehe DogFather Website - Offene
|
|
Punkte.md). Bis die stehen: Knopf bleibt sichtbar (Teaser, "soll
|
|
alles bleiben"), aber NICHT bedienbar — natives disabled-Attribut
|
|
(nicht nur optisch/pointer-events, damit es auch für Tastatur/
|
|
Screenreader korrekt gesperrt ist). main.js hängt weiterhin
|
|
unverändert einen Klick-Listener an dieselbe ID — disabled-Buttons
|
|
feuern in allen Browsern keine Click-Events, daher hier bewusst
|
|
KEINE JS-Änderung nötig. Eigener Gold/Schloss-Stil (.btn-gold-locked,
|
|
siehe main.css) statt des generischen .btn-silver, der auf dieser
|
|
Seite schon für die Teddy-Kollektion vergeben ist. -->
|
|
<button type="button" class="btn-gold-locked" style="width:100%;margin-top:.2rem;" id="btn-register"
|
|
disabled aria-disabled="true">
|
|
<span class="btn-gold-locked-lock" aria-hidden="true">🔒</span>
|
|
<span class="btn-gold-locked-text" data-i18n="ab_kollektion_coming_soon">Coming soon…</span>
|
|
</button>
|
|
<p class="abo-fehler" id="register-fehler"></p>
|
|
<p class="abo-switch"><a id="switch-to-login" data-i18n="ab_switch_login">Schon Supporter? Hier einloggen</a></p>
|
|
</div>
|
|
|
|
<!-- Zustand 3: Login (E-Mail-Code anfordern) -->
|
|
<!-- Bugfix/Nutzer-Wunsch 20.08.2026: War die einzige noch offene Lücke, nachdem
|
|
der Registrieren-Knopf gesperrt wurde — über "Schon Supporter? Hier
|
|
einloggen" kam man hierher und konnte trotzdem einen echten Login-Code
|
|
anfordern, obwohl die DogiCrew noch gar nicht live ist. Jetzt genauso
|
|
gesperrt: E-Mail-Feld disabled (nicht eintippbar, wie gewünscht), Knopf
|
|
derselbe .btn-gold-locked-Stil wie beim Registrieren-Knopf. Betrifft NUR
|
|
diesen öffentlichen Anmelde-Einstieg — bereits eingeloggte Supporter
|
|
(Dogi/VanVan als Test-Accounts) merken nichts davon, ihr Zugang läuft
|
|
weiterhin über den gespeicherten Token/supporter.html. -->
|
|
<div class="abo-panel" id="panel-login" hidden>
|
|
<div class="abo-field">
|
|
<label for="login-email" data-i18n="ab_feld_email">E-Mail-Adresse</label>
|
|
<input type="email" id="login-email" maxlength="120" disabled />
|
|
</div>
|
|
<button type="button" class="btn-gold-locked" style="width:100%;margin-top:.2rem;" id="btn-login-request"
|
|
disabled aria-disabled="true">
|
|
<span class="btn-gold-locked-lock" aria-hidden="true">🔒</span>
|
|
<span class="btn-gold-locked-text" data-i18n="ab_kollektion_coming_soon">Coming soon…</span>
|
|
</button>
|
|
<p class="abo-fehler" id="login-fehler"></p>
|
|
<p class="abo-switch"><a id="switch-to-register" data-i18n="ab_switch_register">Noch kein Konto? Jetzt registrieren</a></p>
|
|
</div>
|
|
|
|
<!-- Zustand 4: Code-Eingabe (nach Registrierung ODER Login-Anfrage) -->
|
|
<div class="abo-panel" id="panel-code" hidden>
|
|
<p class="small" id="code-hinweis" data-i18n="ab_code_hinweis">Wir haben dir einen 6-stelligen Code per E-Mail geschickt.</p>
|
|
<div class="abo-field">
|
|
<label for="code-input" data-i18n="ab_feld_code">Code</label>
|
|
<input type="text" id="code-input" inputmode="numeric" maxlength="6" style="letter-spacing:4px;font-size:1.3rem;text-align:center;" />
|
|
</div>
|
|
<button type="button" class="btn btn-primary" style="width:100%;" id="btn-code-verify" data-i18n="ab_btn_code_verify">Bestätigen</button>
|
|
<p class="abo-fehler" id="code-fehler"></p>
|
|
</div>
|
|
|
|
<!-- Zustand 5: eingeloggt, noch kein Abo -> PayPal Smart Buttons.
|
|
Zeigt automatisch alle für die Käuferin/den Käufer verfügbaren
|
|
Zahlarten (PayPal-Konto, Kreditkarte als Gast, je nach Land) —
|
|
das Geld landet dabei direkt auf Dogis eigenem PayPal-Konto. -->
|
|
<div class="abo-panel" id="panel-subscribe" hidden>
|
|
<p class="abo-erfolg zeige" data-i18n="ab_eingeloggt_als">Eingeloggt.</p>
|
|
|
|
<!-- Button-Lösung (§ 312j BGB / entspr. Regelung): Preis- und
|
|
Zahlungspflicht-Hinweis unmittelbar vor der Zahlung. -->
|
|
<p class="small" style="text-align:center;font-weight:700;margin-bottom:.8rem;">4,99 € / Monat · zahlungspflichtiges Abo · monatlich kündbar</p>
|
|
|
|
<!-- Widerrufsrecht bei digitalen Inhalten (§ 356 Abs. 5 BGB /
|
|
entspr. Regelung, siehe agb.html Ziffer 6): ohne aktives
|
|
Ankreuzen bleibt der Zahlungsbereich gesperrt, es gibt keine
|
|
Zahlung ohne diese ausdrückliche, nicht vorausgewählte
|
|
Zustimmung. -->
|
|
<label class="abo-widerruf-check" for="widerruf-consent">
|
|
<input type="checkbox" id="widerruf-consent" />
|
|
<span>Ich wünsche ausdrücklich, dass der Zugang zum Supporter-Bereich sofort mit Vertragsschluss beginnt, und weiß, dass mein 14-tägiges Widerrufsrecht dadurch erlischt, sobald der Zugang vollständig bereitgestellt ist (Details in den <a href="agb.html" target="_blank" rel="noopener">AGB</a>, Ziffer 6).</span>
|
|
</label>
|
|
|
|
<div id="paypal-button-container" class="paypal-gesperrt"></div>
|
|
<p class="small muted" id="paypal-gesperrt-hinweis">Bitte bestätige oben die Checkbox, um die Zahlungsoptionen freizuschalten.</p>
|
|
<p class="small" id="paypal-laedt" data-i18n="ab_paypal_laedt" hidden>Zahlungsoptionen werden geladen …</p>
|
|
<p class="abo-fehler" id="subscribe-fehler"></p>
|
|
</div>
|
|
|
|
<!-- Zustand 6: bereits Supporter -->
|
|
<div class="abo-panel" id="panel-already" hidden>
|
|
<p class="abo-erfolg zeige" data-i18n="ab_bereits_supporter">Du bist bereits Supporter! 🩵</p>
|
|
<a class="btn btn-primary" style="width:100%;" href="supporter.html" data-i18n="ab_btn_zum_bereich">Zum Supporter-Bereich</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="section-tight">
|
|
<div class="container grid grid-2">
|
|
<div class="card">
|
|
<p data-i18n="ab_text1">Dieses Abonnement ist kein gewöhnlicher Shop und kein einfacher Kauf. Es ist für die Menschen gedacht, die Dogfather dauerhaft unterstützen und ein besonderer Teil dieser gemeinsamen Reise sein möchten.</p>
|
|
<!-- Bugfix/Nutzer-Wunsch 20.08.2026: "4,99 €" hier entfernt (nur die Zahl, Rest
|
|
des Satzes unverändert) — sonst hätte der eigentlich gesperrte Preis
|
|
weiter oben in der Preis-Box hier im Fließtext trotzdem gestanden. -->
|
|
<p data-i18n="ab_text2">Mit deinem monatlichen Beitrag erhältst du Zugang zu einem exklusiven Supporter-Bereich, besonderen Inhalten und einer persönlichen Treuekollektion. Mit jedem erfolgreich bezahlten Meilenstein wächst deine Sammlung: vom kleinen Hasen-Teddy über besondere Jubiläumsprämien bis zum exklusiven Hoodie nach 30 Monaten. Danach beginnt für dich eine neue Kollektion — mit neuen Designs, neuen Erinnerungen und derselben Bedeutung.</p>
|
|
<ul class="abo-vorteile">
|
|
<li data-i18n="ab_vorteil1">Exklusiver Supporter-Bereich</li>
|
|
<li data-i18n="ab_vorteil2">Kleiner Hasen-Teddy nach 6 bezahlten Monaten</li>
|
|
<li data-i18n="ab_vorteil3">Mittelgroßer Hasen-Teddy nach 12 bezahlten Monaten</li>
|
|
<li data-i18n="ab_vorteil4">Großer Hasen-Teddy nach 18 bezahlten Monaten</li>
|
|
<li data-i18n="ab_vorteil5">Tasse & Autogrammkarte nach 24 bezahlten Monaten</li>
|
|
<li data-i18n="ab_vorteil6">Exklusiver Hoodie nach 30 bezahlten Monaten</li>
|
|
<li data-i18n="ab_vorteil7">Neue Supporter-Kollektion nach jedem abgeschlossenen Zyklus</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2 data-i18n="ab_vanvan_h2">Die Teddy-Kollektion — in Kooperation mit VanVan</h2>
|
|
<p data-i18n="ab_vanvan_text">Die DogiCrew 🩵 gehört Dogfather. Die Hasen-Teddys und die dazugehörigen Sammlerkollektionen entstehen jedoch in Zusammenarbeit mit VanVan — der rechten Hand von Dogfather, seiner wichtigsten Vertrauensperson und einem festen Bestandteil der Team-Dogi-Familie. Sie stehen für ihre besondere Rolle, den Zusammenhalt innerhalb der Community und die Verbindung zwischen Dogfather, VanVan und allen Menschen, die diesen gemeinsamen Weg dauerhaft unterstützen.</p>
|
|
<div style="display:flex;justify-content:flex-end;margin-top:1.4rem;">
|
|
<a class="btn-silver" href="#" aria-disabled="true" onclick="return false;"><span class="btn-silver-spark" aria-hidden="true">✨</span><span class="btn-silver-text" data-i18n="ab_kollektion_coming_soon">Coming soon…</span><span class="btn-silver-spark" aria-hidden="true">✨</span></a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<div id="site-footer"></div>
|
|
<script src="assets/js/i18n-abonnieren.js?v=20260820k"></script>
|
|
<script src="assets/js/supporter.js?v=20260820k"></script>
|
|
<script src="assets/js/main.js?v=20260820k"></script>
|
|
<script>
|
|
(function () {
|
|
const S = window.DogiSupporter;
|
|
const panels = ["panel-lade", "panel-register", "panel-login", "panel-code", "panel-subscribe", "panel-already"];
|
|
// panel-social-login (Google-Button) hängt sich an register/login dran,
|
|
// ist aber kein "richtiger" exklusiver Zustand — separat gesteuert.
|
|
const SOCIAL_LOGIN_PANELS = ["panel-register", "panel-login"];
|
|
let publicConfig = {
|
|
googleClientId: null,
|
|
paypalClientId: null, paypalPlanId: null,
|
|
};
|
|
|
|
function irgendeinSocialLoginAktiv() {
|
|
return !!publicConfig.googleClientId;
|
|
}
|
|
|
|
function zeige(id) {
|
|
panels.forEach((p) => { document.getElementById(p).hidden = p !== id; });
|
|
const socialArea = document.getElementById("panel-social-login");
|
|
socialArea.hidden = !(irgendeinSocialLoginAktiv() && SOCIAL_LOGIN_PANELS.includes(id));
|
|
// Bugfix/Rechts-Update 04.08.2026: PayPal-Zahlungsoptionen werden NICHT
|
|
// mehr automatisch beim Anzeigen dieser Kiste geladen — erst nach
|
|
// aktivem Ankreuzen der Widerrufsrecht-Checkbox (siehe
|
|
// widerrufCheckbox-Listener unten). Bei jedem erneuten Aufruf dieser
|
|
// Kiste wird die Checkbox zurückgesetzt, die Zustimmung gilt immer nur
|
|
// für den jeweils aktuellen Besuch.
|
|
if (id === "panel-subscribe") {
|
|
const check = document.getElementById("widerruf-consent");
|
|
if (check) check.checked = false;
|
|
document.getElementById("paypal-button-container").classList.add("paypal-gesperrt");
|
|
document.getElementById("paypal-gesperrt-hinweis").hidden = false;
|
|
}
|
|
}
|
|
function fehlerZeigen(el, msg) {
|
|
el.textContent = msg;
|
|
el.classList.add("zeige");
|
|
}
|
|
function fehlerVerstecken(el) {
|
|
el.classList.remove("zeige");
|
|
}
|
|
|
|
let codePurpose = "verify_email"; // oder "login"
|
|
let codeEmail = "";
|
|
|
|
async function pruefeStatus() {
|
|
if (!S.getToken()) {
|
|
zeige("panel-register");
|
|
return;
|
|
}
|
|
try {
|
|
const data = await S.apiFetch("/supporter/me", {}, true);
|
|
const status = data.subscription?.status || "none";
|
|
S.cacheSubStatus(status);
|
|
S.cacheDisplayName(data.profile?.displayName || "");
|
|
if (["active", "pending", "suspended", "cancelled"].includes(status)) {
|
|
zeige("panel-already");
|
|
} else {
|
|
zeige("panel-subscribe");
|
|
}
|
|
} catch (err) {
|
|
// Token ungültig/abgelaufen -> zurück zur Registrierung/Login
|
|
S.clearToken();
|
|
zeige("panel-register");
|
|
}
|
|
}
|
|
|
|
/* ---------- "Mit Google anmelden" (professioneller Login, Abschnitt
|
|
"screen1" Feedback vom 03.08.2026) — komplett optional, taucht nur
|
|
auf, wenn der Websitebetreiber eine GOOGLE_CLIENT_ID hinterlegt hat.
|
|
Datenschutz (Nachtrag 04.08.2026): Googles Skript wird NICHT mehr
|
|
automatisch beim Seitenaufruf nachgeladen — das würde eine Verbindung
|
|
zu Google (inkl. IP-Übertragung) herstellen, bevor der/die Besucher:in
|
|
überhaupt zugestimmt hat. Stattdessen zeigt initGoogleConsent() nur
|
|
einen eigenen, klar beschrifteten Button; erst der echte Klick darauf
|
|
lädt Googles Skript und rendert deren echten Button (initGoogleSignIn). */
|
|
function initGoogleConsent() {
|
|
const wrap = document.getElementById("google-consent-wrap");
|
|
const btn = document.getElementById("google-consent-btn");
|
|
if (!publicConfig.googleClientId || !wrap || !btn) return;
|
|
wrap.hidden = false;
|
|
btn.addEventListener("click", () => {
|
|
wrap.hidden = true;
|
|
document.getElementById("google-frame-wrap").hidden = false;
|
|
initGoogleSignIn();
|
|
}, { once: true });
|
|
}
|
|
|
|
function initGoogleSignIn() {
|
|
if (!publicConfig.googleClientId) return;
|
|
const script = document.createElement("script");
|
|
script.src = "https://accounts.google.com/gsi/client";
|
|
script.async = true;
|
|
script.defer = true;
|
|
script.onload = () => {
|
|
window.google.accounts.id.initialize({
|
|
client_id: publicConfig.googleClientId,
|
|
callback: handleGoogleCredential,
|
|
});
|
|
window.google.accounts.id.renderButton(document.getElementById("google-signin-button"), {
|
|
type: "standard", theme: "filled_black", size: "large", shape: "pill", text: "continue_with", width: 340,
|
|
});
|
|
};
|
|
document.head.appendChild(script);
|
|
}
|
|
|
|
async function handleGoogleCredential(response) {
|
|
const el = document.getElementById("register-fehler");
|
|
fehlerVerstecken(el);
|
|
try {
|
|
const data = await S.apiFetch("/supporter/google-login", { credential: response.credential });
|
|
S.setToken(data.token);
|
|
await pruefeStatus();
|
|
} catch (err) {
|
|
fehlerZeigen(el, err.message);
|
|
}
|
|
}
|
|
|
|
/* ---------- PayPal Smart Payment Buttons (Abschnitt "screen2" Feedback
|
|
vom 03.08.2026: alle in Deutschland üblichen Zahlarten anzeigen — das
|
|
übernimmt PayPal automatisch, sobald die echten Buttons statt einer
|
|
reinen Weiterleitung genutzt werden). ---------- */
|
|
let paypalSdkGeladen = false;
|
|
// Zeitpunkt der Widerrufsrecht-Zustimmung (siehe Checkbox-Listener weiter
|
|
// unten) — wird beim Abschluss an den Server mitgegeben, damit ein
|
|
// Zeitstempel-Nachweis existiert (siehe Datenschutzerklärung Ziffer 7).
|
|
let widerrufConsentAt = null;
|
|
function ladePaypalButtons() {
|
|
const fehlerEl = document.getElementById("subscribe-fehler");
|
|
const ladeHinweis = document.getElementById("paypal-laedt");
|
|
fehlerVerstecken(fehlerEl);
|
|
ladeHinweis.hidden = false;
|
|
ladeHinweis.textContent = "Zahlungsoptionen werden geladen …";
|
|
if (!publicConfig.paypalClientId || !publicConfig.paypalPlanId) {
|
|
ladeHinweis.textContent = "Das Bezahlsystem wird gerade eingerichtet — bitte später erneut versuchen.";
|
|
return;
|
|
}
|
|
if (paypalSdkGeladen) {
|
|
renderPaypalButtons();
|
|
return;
|
|
}
|
|
const script = document.createElement("script");
|
|
script.src = `https://www.paypal.com/sdk/js?client-id=${encodeURIComponent(publicConfig.paypalClientId)}&vault=true&intent=subscription¤cy=EUR&locale=de_DE`;
|
|
script.onload = () => { paypalSdkGeladen = true; renderPaypalButtons(); };
|
|
script.onerror = () => { ladeHinweis.textContent = "PayPal konnte nicht geladen werden. Bitte Seite neu laden."; ladeHinweis.hidden = false; };
|
|
document.body.appendChild(script);
|
|
}
|
|
function renderPaypalButtons() {
|
|
const container = document.getElementById("paypal-button-container");
|
|
const ladeHinweis = document.getElementById("paypal-laedt");
|
|
container.innerHTML = "";
|
|
window.paypal
|
|
.Buttons({
|
|
style: { shape: "pill", color: "gold", layout: "vertical", label: "subscribe" },
|
|
createSubscription: (data, actions) => actions.subscription.create({ plan_id: publicConfig.paypalPlanId }),
|
|
onApprove: async (data) => {
|
|
const fehlerEl = document.getElementById("subscribe-fehler");
|
|
try {
|
|
await S.apiFetch("/supporter/paypal/confirm", { subscriptionId: data.subscriptionID, widerrufConsentAt }, true);
|
|
await pruefeStatus();
|
|
} catch (err) {
|
|
fehlerZeigen(fehlerEl, err.message);
|
|
}
|
|
},
|
|
onError: (err) => {
|
|
fehlerZeigen(document.getElementById("subscribe-fehler"), "PayPal-Fehler: " + (err?.message || "Unbekannter Fehler."));
|
|
},
|
|
})
|
|
.render("#paypal-button-container");
|
|
ladeHinweis.hidden = true;
|
|
}
|
|
|
|
document.getElementById("switch-to-login").addEventListener("click", () => zeige("panel-login"));
|
|
document.getElementById("switch-to-register").addEventListener("click", () => zeige("panel-register"));
|
|
|
|
// Widerrufsrecht-Checkbox: erst nach aktivem Ankreuzen werden die
|
|
// PayPal-Zahlungsoptionen überhaupt geladen/klickbar (siehe agb.html
|
|
// Ziffer 6 + Datenschutzerklärung Ziffer 7). Beim Abwählen wird alles
|
|
// wieder gesperrt und der Zeitstempel verworfen.
|
|
document.getElementById("widerruf-consent").addEventListener("change", (e) => {
|
|
const container = document.getElementById("paypal-button-container");
|
|
const gesperrtHinweis = document.getElementById("paypal-gesperrt-hinweis");
|
|
if (e.target.checked) {
|
|
widerrufConsentAt = new Date().toISOString();
|
|
container.classList.remove("paypal-gesperrt");
|
|
gesperrtHinweis.hidden = true;
|
|
ladePaypalButtons();
|
|
} else {
|
|
widerrufConsentAt = null;
|
|
container.classList.add("paypal-gesperrt");
|
|
gesperrtHinweis.hidden = false;
|
|
}
|
|
});
|
|
|
|
document.getElementById("btn-register").addEventListener("click", async () => {
|
|
const el = document.getElementById("register-fehler");
|
|
fehlerVerstecken(el);
|
|
const displayName = document.getElementById("reg-name").value.trim();
|
|
const tiktokUsername = document.getElementById("reg-tiktok").value.trim();
|
|
const email = document.getElementById("reg-email").value.trim();
|
|
if (!displayName || !email) return fehlerZeigen(el, "Bitte Name und E-Mail-Adresse angeben.");
|
|
try {
|
|
await S.apiFetch("/supporter/register", { displayName, tiktokUsername, email });
|
|
codePurpose = "verify_email";
|
|
codeEmail = email;
|
|
zeige("panel-code");
|
|
} catch (err) {
|
|
fehlerZeigen(el, err.message);
|
|
}
|
|
});
|
|
|
|
document.getElementById("btn-login-request").addEventListener("click", async () => {
|
|
const el = document.getElementById("login-fehler");
|
|
fehlerVerstecken(el);
|
|
const email = document.getElementById("login-email").value.trim();
|
|
if (!email) return fehlerZeigen(el, "Bitte E-Mail-Adresse angeben.");
|
|
try {
|
|
await S.apiFetch("/supporter/login-request", { email });
|
|
codePurpose = "login";
|
|
codeEmail = email;
|
|
zeige("panel-code");
|
|
} catch (err) {
|
|
fehlerZeigen(el, err.message);
|
|
}
|
|
});
|
|
|
|
document.getElementById("btn-code-verify").addEventListener("click", async () => {
|
|
const el = document.getElementById("code-fehler");
|
|
fehlerVerstecken(el);
|
|
const code = document.getElementById("code-input").value.trim();
|
|
if (!code) return fehlerZeigen(el, "Bitte Code eingeben.");
|
|
try {
|
|
const path = codePurpose === "login" ? "/supporter/verify-login" : "/supporter/verify-email";
|
|
const data = await S.apiFetch(path, { email: codeEmail, code });
|
|
S.setToken(data.token);
|
|
await pruefeStatus();
|
|
} catch (err) {
|
|
fehlerZeigen(el, err.message);
|
|
}
|
|
});
|
|
|
|
async function init() {
|
|
try {
|
|
const res = await fetch(`${S.API_BASE}/supporter/public-config`);
|
|
const data = await res.json();
|
|
if (data.ok) publicConfig = data;
|
|
} catch {
|
|
/* Konfiguration konnte nicht geladen werden — Google-Button/PayPal-Buttons bleiben dann aus. */
|
|
}
|
|
/* Bugfix/Nutzer-Wunsch 20.08.2026: "Mit Google anmelden" wäre ein dritter, bisher
|
|
übersehener Weg gewesen, trotz gesperrtem Registrieren-/Login-Knopf doch ein
|
|
echtes Konto anzulegen bzw. sich einzuloggen (falls GOOGLE_CLIENT_ID auf dem
|
|
Server konfiguriert ist). initGoogleConsent() daher bewusst NICHT mehr
|
|
aufgerufen, solange die DogiCrew-Registrierung gesperrt ist — panel-social-login
|
|
bleibt dadurch dauerhaft hidden. Einfach diesen Aufruf wieder aktivieren,
|
|
sobald die Registrierung selbst (btn-register/btn-login-request, siehe oben)
|
|
entsperrt wird. */
|
|
// initGoogleConsent();
|
|
await pruefeStatus();
|
|
}
|
|
|
|
init();
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|