462 lines
8.2 KiB
Plaintext
462 lines
8.2 KiB
Plaintext
<%- include('partials/header') %>
|
||
|
||
<style>
|
||
|
||
/* =========================
|
||
LAYOUT
|
||
========================= */
|
||
|
||
.step { display: none; }
|
||
.step.active { display: block; }
|
||
|
||
.container-form {
|
||
max-width: 700px;
|
||
margin: auto;
|
||
}
|
||
|
||
.progress {
|
||
height: 10px;
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
.step-nav {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
font-size: 14px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.step-nav span.active {
|
||
font-weight: bold;
|
||
color: #3b3be3;
|
||
}
|
||
|
||
/* Mobile */
|
||
@media(max-width:768px){
|
||
h4{font-size:18px;}
|
||
button{width:100%;}
|
||
}
|
||
|
||
</style>
|
||
|
||
|
||
<div class="container-form">
|
||
|
||
<% if (typeof error !== 'undefined') { %>
|
||
<div class="alert alert-danger">
|
||
⚠️ <%= error %>
|
||
</div>
|
||
<% } %>
|
||
|
||
<h3 class="text-center mb-4">Mitglied werden</h3>
|
||
|
||
|
||
<!-- Fortschritt -->
|
||
<div class="progress">
|
||
<div id="progressBar"
|
||
class="progress-bar bg-primary"
|
||
style="width:33%">
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- Navigation -->
|
||
<div class="step-nav text-center mb-3">
|
||
<span id="nav1" class="active">Daten</span>
|
||
<span id="nav2">Bank</span>
|
||
<span id="nav3">Prüfen</span>
|
||
</div>
|
||
|
||
|
||
<form method="POST" action="/register/create" id="registerForm">
|
||
|
||
|
||
<!-- ========================= -->
|
||
<!-- STEP 1 -->
|
||
<!-- ========================= -->
|
||
<div class="step active" id="step1">
|
||
|
||
<h4>Mitgliedsdaten</h4>
|
||
|
||
<div class="row g-3">
|
||
|
||
<input name="vorname" class="form-control" placeholder="Vorname" required>
|
||
|
||
<input name="nachname" class="form-control" placeholder="Nachname" required>
|
||
|
||
<input type="date"
|
||
name="geburtsdatum"
|
||
class="form-control"
|
||
placeholder="Geburtsdatum"
|
||
required>
|
||
|
||
<input name="mobil" class="form-control" placeholder="Mobilnummer" required>
|
||
|
||
<input type="email" name="email" class="form-control" placeholder="E-Mail" required>
|
||
|
||
|
||
<h5 class="mt-3">Adresse</h5>
|
||
|
||
<input name="strasse" class="form-control" placeholder="Straße" required>
|
||
|
||
<input name="hausnummer" class="form-control" placeholder="Nr." required>
|
||
|
||
<input name="plz" class="form-control" placeholder="PLZ" required>
|
||
|
||
<input name="ort" class="form-control" placeholder="Ort" required>
|
||
|
||
<input name="land" class="form-control" value="Deutschland">
|
||
|
||
</div>
|
||
|
||
|
||
<button type="button"
|
||
class="btn btn-primary mt-4"
|
||
onclick="nextStep(2)">
|
||
Weiter →
|
||
</button>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<!-- ========================= -->
|
||
<!-- STEP 2 -->
|
||
<!-- ========================= -->
|
||
<div class="step" id="step2">
|
||
|
||
<h4>Bankdaten</h4>
|
||
|
||
<div class="row g-3">
|
||
|
||
<input name="kontoinhaber" class="form-control" placeholder="Kontoinhaber" required>
|
||
|
||
<input name="mandatsreferenz" class="form-control" placeholder="Mandatsreferenz" required>
|
||
|
||
<input name="iban" class="form-control" placeholder="IBAN" required>
|
||
|
||
<input name="bic" class="form-control" placeholder="BIC" required>
|
||
|
||
|
||
<div class="form-check mt-2">
|
||
<input class="form-check-input" type="checkbox" name="agreeSepa" required>
|
||
<label class="form-check-label">
|
||
SEPA-Mandat erteilen
|
||
</label>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
<div class="d-flex justify-content-between mt-4">
|
||
|
||
<button type="button"
|
||
class="btn btn-secondary"
|
||
onclick="nextStep(1)">
|
||
← Zurück
|
||
</button>
|
||
|
||
<button type="button"
|
||
class="btn btn-primary"
|
||
onclick="nextStep(3)">
|
||
Weiter →
|
||
</button>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<!-- ========================= -->
|
||
<!-- STEP 3 -->
|
||
<!-- ========================= -->
|
||
<div class="step" id="step3">
|
||
|
||
<h4>Zusammenfassung</h4>
|
||
|
||
<div class="card p-3 mb-3 bg-light">
|
||
|
||
<div id="summaryBox"></div>
|
||
|
||
</div>
|
||
|
||
|
||
<h5>Vertrag</h5>
|
||
|
||
<select name="vertragsvariante"
|
||
class="form-select mb-3"
|
||
required>
|
||
|
||
<option value="">Bitte wählen</option>
|
||
|
||
<% vertragsarten.forEach(v => { %>
|
||
|
||
<option value="<%= v.id %>">
|
||
<%= v.name %> – <%= v.betrag.toFixed(2) %> €
|
||
</option>
|
||
|
||
<% }) %>
|
||
|
||
</select>
|
||
|
||
|
||
<h5>Rechtliches</h5>
|
||
|
||
<div class="form-check mb-2">
|
||
|
||
<input class="form-check-input"
|
||
type="checkbox"
|
||
name="agreeConsent"
|
||
id="agreeConsent">
|
||
|
||
<label class="form-check-label">
|
||
Einverständnis gelesen
|
||
</label>
|
||
|
||
</div>
|
||
|
||
|
||
<div class="form-check mb-3">
|
||
|
||
<input class="form-check-input"
|
||
type="checkbox"
|
||
name="agreeAgb"
|
||
required>
|
||
|
||
<label class="form-check-label">
|
||
AGB akzeptiert
|
||
</label>
|
||
|
||
</div>
|
||
|
||
|
||
<div class="d-flex justify-content-between mt-4">
|
||
|
||
<button type="button"
|
||
class="btn btn-secondary"
|
||
onclick="nextStep(2)">
|
||
← Zurück
|
||
</button>
|
||
|
||
<button type="submit"
|
||
class="btn btn-success btn-lg">
|
||
Abschließen
|
||
</button>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
</form>
|
||
</div>
|
||
|
||
|
||
|
||
<script>
|
||
|
||
/* ============================
|
||
STEPS
|
||
============================ */
|
||
|
||
let currentStep = 1;
|
||
|
||
|
||
function nextStep(step){
|
||
|
||
// 👉 Nur validieren, wenn wir vorwärts gehen
|
||
if(step > currentStep){
|
||
if(!validateStep(currentStep)) return;
|
||
}
|
||
|
||
saveForm();
|
||
|
||
|
||
currentStep = step;
|
||
|
||
document.querySelectorAll('.step')
|
||
.forEach(s => s.classList.remove('active'));
|
||
|
||
document.getElementById('step'+step)
|
||
.classList.add('active');
|
||
|
||
updateNav();
|
||
updateProgress();
|
||
|
||
if(step === 3){
|
||
buildSummary();
|
||
checkAgeAndConsent();
|
||
}
|
||
}
|
||
|
||
function checkAgeAndConsent(){
|
||
|
||
const data =
|
||
JSON.parse(localStorage.getItem('registerData'));
|
||
|
||
if(!data || !data.geburtsdatum) return;
|
||
|
||
const birth = new Date(data.geburtsdatum);
|
||
const today = new Date();
|
||
|
||
let age = today.getFullYear() - birth.getFullYear();
|
||
|
||
const m = today.getMonth() - birth.getMonth();
|
||
if (m < 0 || (m === 0 && today.getDate() < birth.getDate())) {
|
||
age--;
|
||
}
|
||
|
||
const consentBox =
|
||
document.getElementById('agreeConsent');
|
||
|
||
if(!consentBox) return;
|
||
|
||
// Unter 18 → aktiv & Pflicht
|
||
if(age < 18){
|
||
|
||
consentBox.disabled = false;
|
||
consentBox.required = true;
|
||
|
||
} else {
|
||
|
||
// Ab 18 → deaktiviert
|
||
consentBox.checked = false;
|
||
consentBox.disabled = true;
|
||
consentBox.required = false;
|
||
}
|
||
}
|
||
|
||
|
||
/* ============================
|
||
VALIDIERUNG
|
||
============================ */
|
||
|
||
function validateStep(step){
|
||
|
||
const container =
|
||
document.getElementById('step'+step);
|
||
|
||
const fields =
|
||
container.querySelectorAll('input,select');
|
||
|
||
for(let field of fields){
|
||
|
||
if(!field.checkValidity()){
|
||
field.reportValidity();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
/* ============================
|
||
PROGRESS
|
||
============================ */
|
||
|
||
function updateProgress(){
|
||
|
||
const percent = currentStep * 33;
|
||
|
||
document.getElementById('progressBar')
|
||
.style.width = percent + '%';
|
||
}
|
||
|
||
|
||
/* ============================
|
||
NAV
|
||
============================ */
|
||
|
||
function updateNav(){
|
||
|
||
document.querySelectorAll('.step-nav span')
|
||
.forEach(n => n.classList.remove('active'));
|
||
|
||
document.getElementById('nav'+currentStep)
|
||
.classList.add('active');
|
||
}
|
||
|
||
|
||
/* ============================
|
||
AUTO SAVE
|
||
============================ */
|
||
|
||
const form = document.getElementById('registerForm');
|
||
|
||
form.addEventListener('input', saveForm);
|
||
|
||
function saveForm(){
|
||
|
||
const data = {};
|
||
|
||
new FormData(form).forEach((v,k)=>{
|
||
data[k]=v;
|
||
});
|
||
|
||
localStorage.setItem('registerData',
|
||
JSON.stringify(data));
|
||
}
|
||
|
||
|
||
function loadForm(){
|
||
|
||
const data =
|
||
JSON.parse(localStorage.getItem('registerData'));
|
||
|
||
if(!data) return;
|
||
|
||
Object.keys(data).forEach(key=>{
|
||
|
||
const field =
|
||
form.elements[key];
|
||
|
||
if(field){
|
||
field.value = data[key];
|
||
}
|
||
});
|
||
}
|
||
|
||
loadForm();
|
||
|
||
|
||
/* ============================
|
||
SUMMARY
|
||
============================ */
|
||
|
||
function buildSummary(){
|
||
|
||
const data =
|
||
JSON.parse(localStorage.getItem('registerData'));
|
||
|
||
if(!data) return;
|
||
|
||
let html = `
|
||
<b>Name:</b> ${data.vorname} ${data.nachname}<br>
|
||
<b>Geburtsdatum:</b> ${data.geburtsdatum}<br>
|
||
<b>Email:</b> ${data.email}<br>
|
||
<b>Mobil:</b> ${data.mobil}<br>
|
||
<b>Adresse:</b>
|
||
${data.strasse} ${data.hausnummer},
|
||
${data.plz} ${data.ort}<br>
|
||
|
||
<b>IBAN:</b> ${data.iban}<br>
|
||
`;
|
||
|
||
document.getElementById('summaryBox').innerHTML = html;
|
||
}
|
||
|
||
|
||
/* ============================
|
||
CLEAR AFTER SUBMIT
|
||
============================ */
|
||
|
||
form.addEventListener('submit',()=>{
|
||
localStorage.removeItem('registerData');
|
||
});
|
||
|
||
</script>
|
||
|
||
|
||
<%- include('partials/footer') %> |