482 lines
20 KiB
Plaintext
482 lines
20 KiB
Plaintext
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>PlusFit24 – Mitgliedschaft abschließen</title>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;700;800&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="/css/style.css">
|
||
</head>
|
||
<body>
|
||
<header class="site-header">
|
||
<div class="header-inner">
|
||
<div class="logo">Plusfit<span>24</span></div>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="signup-main">
|
||
<!-- Fortschrittsleiste -->
|
||
<nav class="progress-nav" id="progressNav">
|
||
<span class="step" data-step="0">TARIF</span>
|
||
<span class="step-dot"></span>
|
||
<span class="step active" data-step="1">4</span>
|
||
<span class="step-dot"></span>
|
||
<span class="step" data-step="2">ANSCHRIFT</span>
|
||
<span class="step-dot"></span>
|
||
<span class="step" data-step="3">LASTSCHRIFT</span>
|
||
<span class="step-dot"></span>
|
||
<span class="step" data-step="4">ABSCHLUSS</span>
|
||
</nav>
|
||
|
||
<div class="signup-container">
|
||
|
||
<!-- ===== SCHRITT 1: Persönliche Daten ===== -->
|
||
<div class="form-step active" id="step1">
|
||
<h2 class="step-title italic">Geburtsdatum</h2>
|
||
|
||
<div class="salutation-group">
|
||
<button type="button" class="sal-btn" data-value="Herr" onclick="selectSalutation(this)">Herr</button>
|
||
<button type="button" class="sal-btn" data-value="Frau" onclick="selectSalutation(this)">Frau</button>
|
||
<button type="button" class="sal-btn" data-value="Keine Angabe" onclick="selectSalutation(this)">Keine Angabe</button>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Titel</label>
|
||
<div class="input-wrap">
|
||
<span class="input-icon">👤</span>
|
||
<input type="text" id="title" placeholder="Dein Titel">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Vorname <span class="req">*</span></label>
|
||
<div class="input-wrap">
|
||
<span class="input-icon">👤</span>
|
||
<input type="text" id="first_name" placeholder="Dein Vorname" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Nachname <span class="req">*</span></label>
|
||
<div class="input-wrap">
|
||
<span class="input-icon">👤</span>
|
||
<input type="text" id="last_name" placeholder="Dein Nachname" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Geburtsdatum <span class="req">*</span></label>
|
||
<div class="input-wrap">
|
||
<span class="input-icon">📅</span>
|
||
<input type="date" id="birth_date" placeholder="TT.mm.jjjj" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Email <span class="req">*</span></label>
|
||
<div class="input-wrap">
|
||
<span class="input-icon">✉️</span>
|
||
<input type="email" id="email" placeholder="Deine Email" required>
|
||
<span class="email-status" id="emailStatus"></span>
|
||
</div>
|
||
<div class="email-message" id="emailMessage"></div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Telefon</label>
|
||
<div class="input-wrap">
|
||
<span class="input-icon">📞</span>
|
||
<input type="tel" id="phone" placeholder="Deine Telefon-/ Handynummer">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="minor-warning hidden" id="minorWarning">
|
||
<div class="warning-box">
|
||
<strong>⚠️ Hinweis für Minderjährige</strong>
|
||
<p>Da du noch nicht 18 Jahre alt bist, benötigst du die Einverständniserklärung deiner Erziehungsberechtigten. Du wirst am Ende aufgefordert, diese zu bestätigen.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="step-buttons">
|
||
<a href="/" class="btn btn-outline">Zurück</a>
|
||
<button type="button" class="btn btn-primary" onclick="validateStep1()">Weiter</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ===== SCHRITT 2: Anschrift ===== -->
|
||
<div class="form-step" id="step2">
|
||
<h2 class="step-title bold">Anschrift</h2>
|
||
<p class="step-subtitle italic">Wo wohnst du?</p>
|
||
|
||
<div class="form-group">
|
||
<label>Deine Adresse <span class="req">*</span></label>
|
||
<div class="input-wrap">
|
||
<span class="input-icon">📍</span>
|
||
<input type="text" id="street" placeholder="Straße, Hausnummer" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<div class="input-wrap">
|
||
<span class="input-icon">📍</span>
|
||
<input type="text" id="address_addition" placeholder="Adress-Zusatz">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<div class="input-wrap">
|
||
<span class="input-icon">📍</span>
|
||
<input type="text" id="zip" placeholder="PLZ" maxlength="5" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<div class="input-wrap">
|
||
<span class="input-icon">📍</span>
|
||
<input type="text" id="city" placeholder="Ort" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="step-buttons">
|
||
<button type="button" class="btn btn-outline" onclick="goToStep(1)">Zurück</button>
|
||
<button type="button" class="btn btn-primary" onclick="validateStep2()">Weiter</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ===== SCHRITT 3: Lastschrift ===== -->
|
||
<div class="form-step" id="step3">
|
||
<h2 class="step-title bold">Lastschrift</h2>
|
||
<p class="step-subtitle italic">Damit wir deinen Mitgliedsbeitrag abbuchen können</p>
|
||
|
||
<div class="sepa-mandate">
|
||
<label class="checkbox-label">
|
||
<input type="checkbox" id="sepa_accepted">
|
||
<span class="checkbox-custom"></span>
|
||
<span>Ich ermächtige PlusFit24 UG - NL: Moosleiten 12 84089 Aiglsbach, Zahlungen von meinem Konto mittels Lastschrift einzuziehen. Zugleich weise ich mein Kreditinstitut an, die von PlusFit24 UG - NL: Moosleiten 12 84089 Aiglsbach auf mein Konto gezogenen Lastschriften einzulösen. Hinweis: Ich kann innerhalb von acht Wochen, beginnend mit dem Belastungsdatum, die Erstattung des belasteten Betrages verlangen. Es gelten dabei die mit meinem Kreditinstitut vereinbarten Bedingungen. Gläubiger-Identifikationsnummer: DE1200100002549495</span>
|
||
</label>
|
||
</div>
|
||
|
||
<label class="form-label-section">Sepa Lastschriftmandat</label>
|
||
|
||
<div class="form-group">
|
||
<div class="input-wrap">
|
||
<span class="input-icon">🏦</span>
|
||
<input type="text" id="bank_name" placeholder="Geldinstitut">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<div class="input-wrap">
|
||
<span class="input-icon">👤</span>
|
||
<input type="text" id="account_holder" placeholder="Name des Kontoinhabers">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<div class="input-wrap">
|
||
<span class="input-icon">💳</span>
|
||
<input type="text" id="iban" placeholder="DE00 0000 0000 0000 0000 00" maxlength="34" autocomplete="off">
|
||
<span class="email-status" id="ibanStatus"></span>
|
||
</div>
|
||
<div class="email-message" id="ibanMessage"></div>
|
||
</div>
|
||
|
||
<div class="step-buttons">
|
||
<button type="button" class="btn btn-outline" onclick="goToStep(2)">Zurück</button>
|
||
<button type="button" class="btn btn-primary" onclick="validateStep3()">Weiter</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ===== SCHRITT 4: Abschluss ===== -->
|
||
<div class="form-step" id="step4">
|
||
<h2 class="step-title bold">Abschluss</h2>
|
||
<p class="step-subtitle italic">Alles auf einen Blick</p>
|
||
|
||
<div class="abschluss-grid">
|
||
<!-- Tarif Übersicht -->
|
||
<div class="tarif-summary-card">
|
||
<div class="summary-badge">◑ Wir freuen uns auf dich!</div>
|
||
<h3>Dein Wunsch-Tarif</h3>
|
||
<div class="summary-feature">
|
||
<span class="feature-icon">📦</span>
|
||
<span>Laufzeit (Monate): <%= tariff.duration_months %></span>
|
||
</div>
|
||
<div class="summary-feature">
|
||
<span class="feature-icon">📦</span>
|
||
<span>Tarif: <%= tariff.name %></span>
|
||
</div>
|
||
<div class="summary-feature">
|
||
<span class="feature-icon">📦</span>
|
||
<span>Zusätzlich: Startpaket <%= Number(tariff.start_package_price).toFixed(2).replace('.', ',') %>€ einmalig</span>
|
||
</div>
|
||
<div class="summary-price">
|
||
<span class="price-big"><%= Number(tariff.price_monthly).toFixed(2).replace('.', ',') %>€</span>
|
||
<span class="price-period">/Monat</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Letzter Schritt -->
|
||
<div class="final-checks">
|
||
<h3>Letzter Schritt</h3>
|
||
<div class="doc-buttons">
|
||
<a href="https://plusfit24.de/wp-content/uploads/2022/11/AG_PlusFit24.pdf" target="_blank" class="doc-btn">Widerrufsbelehrung</a>
|
||
<a href="https://plusfit24.de/datenschutz-2/" target="_blank" class="doc-btn">Datenschutz</a>
|
||
<a href="https://plusfit24.de/wp-content/uploads/2022/11/AG_PlusFit24.pdf" target="_blank" class="doc-btn">AGB</a>
|
||
</div>
|
||
|
||
<label class="checkbox-label">
|
||
<input type="checkbox" id="agb_accepted">
|
||
<span class="checkbox-custom"></span>
|
||
<span>Ich habe die AGBs und Widerrufsbelehrung gelesen und akzeptiert</span>
|
||
</label>
|
||
|
||
<label class="checkbox-label">
|
||
<input type="checkbox" id="datenschutz_accepted">
|
||
<span class="checkbox-custom"></span>
|
||
<span>Ich akzeptiere die Erhebung und Verarbeitung meiner eingegebenen Daten</span>
|
||
</label>
|
||
|
||
<label class="checkbox-label">
|
||
<input type="checkbox" id="data_correct">
|
||
<span class="checkbox-custom"></span>
|
||
<span>Ich bestätige die Richtigkeit meiner Angaben</span>
|
||
</label>
|
||
|
||
<!-- Einverständniserklärung für Minderjährige -->
|
||
<div id="guardianSection" class="hidden">
|
||
<div class="minor-info-box">
|
||
<strong>Einverständniserklärung der Erziehungsberechtigten</strong>
|
||
<p>Da du noch nicht 18 Jahre alt bist, muss ein Erziehungsberechtigter zustimmen.</p>
|
||
<a href="/pdfs/Einverstaendniserklaerung.pdf" target="_blank" class="doc-btn">📄 Einverständniserklärung öffnen</a>
|
||
</div>
|
||
<label class="checkbox-label">
|
||
<input type="checkbox" id="guardian_consent">
|
||
<span class="checkbox-custom"></span>
|
||
<span>Die Einverständniserklärung der Erziehungsberechtigten liegt vor und wurde unterschrieben.</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="submit-section">
|
||
<p class="submit-notice"><strong>Schließe deinen Mitgliedschaftsvertrag mit einem Klick auf den untenstehenden Button verbindlich ab.</strong></p>
|
||
<div id="submitError" class="alert alert-error hidden"></div>
|
||
<button type="button" class="btn btn-submit" id="submitBtn" onclick="submitForm()">
|
||
Kostenpflichtige Mitgliedschaft abschließen
|
||
</button>
|
||
<p class="ssl-notice">🔒 Deine Daten werden ausschließlich verschlüsselt übermittelt.</p>
|
||
</div>
|
||
|
||
<div class="step-buttons">
|
||
<button type="button" class="btn btn-outline" onclick="goToStep(3)">Zurück</button>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</main>
|
||
|
||
<footer class="site-footer">
|
||
<p>© 2024 PlusFit24 UG · <a href="https://plusfit24.de/datenschutz-2/" target="_blank">Datenschutz</a> · <a href="https://plusfit24.de/wp-content/uploads/2022/11/AG_PlusFit24.pdf" target="_blank">AGB</a></p>
|
||
</footer>
|
||
|
||
<script src="/js/iban.js"></script>
|
||
<script>
|
||
const TARIFF_ID = '<%= tariff.id %>';
|
||
let currentStep = 1;
|
||
let salutation = '';
|
||
let emailVerified = false;
|
||
let emailVerifyTimer = null;
|
||
let isMinor = false;
|
||
|
||
// Anrede auswählen
|
||
function selectSalutation(btn) {
|
||
document.querySelectorAll('.sal-btn').forEach(b => b.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
salutation = btn.dataset.value;
|
||
}
|
||
|
||
// Schritt wechseln
|
||
function goToStep(step) {
|
||
document.querySelectorAll('.form-step').forEach(s => s.classList.remove('active'));
|
||
document.getElementById('step' + step).classList.add('active');
|
||
|
||
// Progress nav aktualisieren
|
||
const steps = document.querySelectorAll('.progress-nav .step');
|
||
steps.forEach((s, i) => {
|
||
s.classList.toggle('active', i === step);
|
||
s.classList.toggle('done', i < step);
|
||
});
|
||
|
||
currentStep = step;
|
||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||
}
|
||
|
||
// E-Mail Verifizierung
|
||
document.getElementById('email').addEventListener('input', function() {
|
||
clearTimeout(emailVerifyTimer);
|
||
emailVerified = false;
|
||
document.getElementById('emailStatus').textContent = '';
|
||
document.getElementById('emailMessage').textContent = '';
|
||
|
||
const email = this.value.trim();
|
||
if (email.includes('@') && email.includes('.')) {
|
||
document.getElementById('emailStatus').textContent = '⏳';
|
||
emailVerifyTimer = setTimeout(() => verifyEmail(email), 800);
|
||
}
|
||
});
|
||
|
||
async function verifyEmail(email) {
|
||
try {
|
||
const res = await fetch('/api/verify-email', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ email })
|
||
});
|
||
const data = await res.json();
|
||
if (data.valid) {
|
||
emailVerified = true;
|
||
document.getElementById('emailStatus').textContent = '✅';
|
||
document.getElementById('emailMessage').textContent = '';
|
||
document.getElementById('emailMessage').className = 'email-message';
|
||
} else {
|
||
emailVerified = false;
|
||
document.getElementById('emailStatus').textContent = '❌';
|
||
document.getElementById('emailMessage').textContent = data.reason;
|
||
document.getElementById('emailMessage').className = 'email-message error';
|
||
}
|
||
} catch (e) {
|
||
document.getElementById('emailStatus').textContent = '⚠️';
|
||
}
|
||
}
|
||
|
||
// Geburtsdatum → Minderjähriger prüfen
|
||
document.getElementById('birth_date').addEventListener('change', function() {
|
||
const bd = new Date(this.value);
|
||
const today = new Date();
|
||
let age = today.getFullYear() - bd.getFullYear();
|
||
const m = today.getMonth() - bd.getMonth();
|
||
if (m < 0 || (m === 0 && today.getDate() < bd.getDate())) age--;
|
||
isMinor = age < 18;
|
||
document.getElementById('minorWarning').classList.toggle('hidden', !isMinor);
|
||
});
|
||
|
||
// Schritt 1 validieren
|
||
async function validateStep1() {
|
||
const firstName = document.getElementById('first_name').value.trim();
|
||
const lastName = document.getElementById('last_name').value.trim();
|
||
const birthDate = document.getElementById('birth_date').value;
|
||
const email = document.getElementById('email').value.trim();
|
||
|
||
if (!firstName || !lastName) return alert('Bitte Vor- und Nachname eingeben.');
|
||
if (!birthDate) return alert('Bitte Geburtsdatum eingeben.');
|
||
if (!email) return alert('Bitte E-Mail-Adresse eingeben.');
|
||
|
||
// Alter prüfen
|
||
const bd = new Date(birthDate);
|
||
const today = new Date();
|
||
let age = today.getFullYear() - bd.getFullYear();
|
||
const m = today.getMonth() - bd.getMonth();
|
||
if (m < 0 || (m === 0 && today.getDate() < bd.getDate())) age--;
|
||
if (age < 14) return alert('Das Mindestalter für eine Mitgliedschaft beträgt 14 Jahre.');
|
||
|
||
// E-Mail verifizieren falls noch nicht geschehen
|
||
if (!emailVerified) {
|
||
document.getElementById('emailStatus').textContent = '⏳';
|
||
await verifyEmail(email);
|
||
if (!emailVerified) return alert('Bitte eine gültige E-Mail-Adresse eingeben.');
|
||
}
|
||
|
||
goToStep(2);
|
||
}
|
||
|
||
// Schritt 2 validieren
|
||
function validateStep2() {
|
||
const street = document.getElementById('street').value.trim();
|
||
const zip = document.getElementById('zip').value.trim();
|
||
const city = document.getElementById('city').value.trim();
|
||
if (!street || !zip || !city) return alert('Bitte Straße, PLZ und Ort ausfüllen.');
|
||
goToStep(3);
|
||
}
|
||
|
||
// Schritt 3 validieren
|
||
function validateStep3() {
|
||
// Sepa ist optional aber Checkbox sollte gecheckt sein wenn Daten eingegeben
|
||
// Zeige Minderjährigen-Abschnitt im Abschluss
|
||
if (isMinor) {
|
||
document.getElementById('guardianSection').classList.remove('hidden');
|
||
}
|
||
goToStep(4);
|
||
}
|
||
|
||
// Formular absenden
|
||
async function submitForm() {
|
||
if (!document.getElementById('agb_accepted').checked) return alert('Bitte AGBs und Widerrufsbelehrung akzeptieren.');
|
||
if (!document.getElementById('datenschutz_accepted').checked) return alert('Bitte Datenschutzerklärung akzeptieren.');
|
||
if (!document.getElementById('data_correct').checked) return alert('Bitte die Richtigkeit Ihrer Angaben bestätigen.');
|
||
if (isMinor && !document.getElementById('guardian_consent').checked) {
|
||
return alert('Bei Minderjährigen ist die Einverständniserklärung der Erziehungsberechtigten erforderlich.');
|
||
}
|
||
|
||
const btn = document.getElementById('submitBtn');
|
||
btn.disabled = true;
|
||
btn.textContent = 'Wird gesendet...';
|
||
|
||
const errorDiv = document.getElementById('submitError');
|
||
errorDiv.classList.add('hidden');
|
||
|
||
const payload = {
|
||
tariff_id: TARIFF_ID,
|
||
salutation: salutation,
|
||
title: document.getElementById('title').value.trim(),
|
||
first_name: document.getElementById('first_name').value.trim(),
|
||
last_name: document.getElementById('last_name').value.trim(),
|
||
birth_date: document.getElementById('birth_date').value,
|
||
email: document.getElementById('email').value.trim(),
|
||
phone: document.getElementById('phone').value.trim(),
|
||
street: document.getElementById('street').value.trim(),
|
||
address_addition: document.getElementById('address_addition').value.trim(),
|
||
zip: document.getElementById('zip').value.trim(),
|
||
city: document.getElementById('city').value.trim(),
|
||
bank_name: document.getElementById('bank_name').value.trim(),
|
||
account_holder: document.getElementById('account_holder').value.trim(),
|
||
iban: document.getElementById('iban').value.trim().replace(/\s/g, ''),
|
||
sepa_accepted: document.getElementById('sepa_accepted').checked,
|
||
agb_accepted: document.getElementById('agb_accepted').checked,
|
||
datenschutz_accepted: document.getElementById('datenschutz_accepted').checked,
|
||
data_correct: document.getElementById('data_correct').checked,
|
||
guardian_consent: isMinor ? document.getElementById('guardian_consent').checked : false
|
||
};
|
||
|
||
try {
|
||
const res = await fetch('/api/submit-membership', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(payload)
|
||
});
|
||
const data = await res.json();
|
||
|
||
if (data.success) {
|
||
window.location.href = data.pending ? '/bestaetigung-ausstehend?email=' + encodeURIComponent(document.getElementById('email').value) : '/erfolg';
|
||
} else {
|
||
errorDiv.textContent = data.error || 'Fehler beim Absenden.';
|
||
errorDiv.classList.remove('hidden');
|
||
btn.disabled = false;
|
||
btn.textContent = 'Kostenpflichtige Mitgliedschaft abschließen';
|
||
}
|
||
} catch (e) {
|
||
errorDiv.textContent = 'Netzwerkfehler. Bitte versuche es erneut.';
|
||
errorDiv.classList.remove('hidden');
|
||
btn.disabled = false;
|
||
btn.textContent = 'Kostenpflichtige Mitgliedschaft abschließen';
|
||
}
|
||
}
|
||
// IBAN Validierung (iban.js wird vor diesem Script geladen)
|
||
const ibanInput = document.getElementById('iban');
|
||
if (ibanInput) {
|
||
attachIBANValidation(ibanInput, document.getElementById('ibanStatus'), document.getElementById('ibanMessage'));
|
||
}
|
||
</script>
|
||
|
||
</html>
|