änderung hier wird nun die verttragsnummer übergeben

This commit is contained in:
Cay 2026-02-25 19:12:12 +00:00
parent 795b8a66ce
commit 03913c6680
3 changed files with 639 additions and 386 deletions

View File

@ -1,135 +1,325 @@
const express = require('express');
const Database = require('better-sqlite3');
const auth = require('../middleware/authMiddleware');
<%- include('partials/header') %>
const router = express.Router();
const db = new Database('plusfit.db');
<style>
.step { display: none; }
.step.active { display: block; }
/* Übersicht */
router.get('/', auth, (req, res) => {
const vertragsarten = db
.prepare('SELECT * FROM vertragsarten ORDER BY id ASC')
.all();
.container-form {
max-width: 700px;
margin: auto;
}
res.render('contracts', { vertragsarten });
});
.progress {
height: 10px;
margin-bottom: 30px;
}
/* Neu anlegen */
router.post('/create', auth, (req, res) => {
const { name, laufzeit, betrag, aktiv, beschreibung } = req.body;
.step-nav {
display: flex;
justify-content: space-between;
font-size: 14px;
margin-bottom: 20px;
}
db.prepare(`
INSERT INTO vertragsarten
(name, beschreibung, laufzeit, betrag, aktiv)
VALUES (?, ?, ?, ?, ?)
`).run(
name,
beschreibung,
laufzeit,
betrag,
aktiv ? 1 : 0
);
.step-nav span.active {
font-weight: bold;
color: #3b3be3;
}
@media(max-width:768px){
h4{font-size:18px;}
button{width:100%;}
}
</style>
res.redirect('/contracts');
});
<div class="container-form">
// Vertragsart aktiv / inaktiv setzen
router.post('/toggle/:id', auth, (req, res) => {
const { id } = req.params;
<% if (typeof error !== 'undefined') { %>
<div class="alert alert-danger">
<%= error %>
</div>
<% } %>
db.prepare(`
UPDATE vertragsarten
SET aktiv = CASE
WHEN aktiv = 1 THEN 0
ELSE 1
END
WHERE id = ?
`).run(id);
<h3 class="text-center mb-4">Mitglied werden</h3>
res.redirect('/contracts');
});
<div class="progress">
<div id="progressBar"
class="progress-bar bg-primary"
style="width:33%">
</div>
</div>
// Vertragsart deaktivieren + User migrieren
router.post('/deactivate/:id', auth, (req, res) => {
const oldId = req.params.id;
const { newContractId } = req.body;
<div class="step-nav text-center mb-3">
<span id="nav1">Daten</span>
<span id="nav2">Bank</span>
<span id="nav3">Prüfen</span>
</div>
if (!newContractId) {
return res.status(400).send('Neue Vertragsart fehlt');
<form method="POST" action="/register/create" id="registerForm">
<!-- ================= STEP 1 ================= -->
<div class="step" id="step1">
<h4>Mitgliedsdaten</h4>
<input name="vorname" class="form-control mb-2" placeholder="Vorname" required>
<input name="nachname" class="form-control mb-2" placeholder="Nachname" required>
<input type="date"
name="geburtsdatum"
id="geburtsdatum"
class="form-control mb-2"
required>
<input name="mobil" class="form-control mb-2" placeholder="Mobilnummer" required>
<input type="email" name="email" class="form-control mb-2" placeholder="E-Mail" required>
<h5 class="mt-3">Adresse</h5>
<input name="strasse" class="form-control mb-2" placeholder="Straße" required>
<input name="hausnummer" class="form-control mb-2" placeholder="Nr." required>
<input name="plz" class="form-control mb-2" placeholder="PLZ" required>
<input name="ort" class="form-control mb-2" placeholder="Ort" required>
<input name="land" class="form-control mb-2" value="Deutschland">
<button type="button" class="btn btn-primary mt-3" onclick="nextStep(2)">
Weiter
</button>
</div>
<!-- ================= STEP 2 ================= -->
<div class="step" id="step2">
<h4>Bankdaten</h4>
<input name="kontoinhaber" class="form-control mb-2" placeholder="Kontoinhaber" required>
<input name="mandatsreferenz" class="form-control mb-2" placeholder="Mandatsreferenz" required>
<input name="iban" class="form-control mb-2" placeholder="IBAN" required>
<input name="bic" class="form-control mb-2" placeholder="BIC" required>
<div class="form-check mt-2">
<input class="form-check-input"
type="checkbox"
name="agreeSepa"
value="on"
required>
<label class="form-check-label">
SEPA-Mandat erteilen
</label>
</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 d-none" id="consentBox">
<input class="form-check-input"
type="checkbox"
name="agreeConsent"
id="agreeConsent"
value="on">
<label class="form-check-label">
Einverständnis der Erziehungsberechtigten
</label>
</div>
<div class="form-check mb-3">
<input class="form-check-input"
type="checkbox"
name="agreeAgb"
value="on"
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>
window.fromServerError = <%= typeof errorStep !== 'undefined' ? 'true' : 'false' %>;
let currentStep = <%= typeof errorStep !== 'undefined' ? errorStep : 1 %>;
const form = document.getElementById('registerForm');
function nextStep(step){
if(step > currentStep && !window.fromServerError){
if(!validateStep(currentStep)) return;
}
const tx = db.transaction(() => {
saveForm();
// 1⃣ Alle User auf neue Vertragsart umstellen
db.prepare(`
UPDATE users
SET vertragsvariante = ?
WHERE vertragsvariante = ?
`).run(newContractId, oldId);
currentStep = step;
// 2⃣ Alte Vertragsart deaktivieren
db.prepare(`
UPDATE vertragsarten
SET aktiv = 0
WHERE id = ?
`).run(oldId);
document.querySelectorAll('.step')
.forEach(s => s.classList.remove('active'));
document.getElementById('step'+step)
.classList.add('active');
updateNav();
updateProgress();
if(step === 3){
buildSummary();
checkAgeAndConsent();
}
}
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;
}
function updateProgress(){
document.getElementById('progressBar')
.style.width = (currentStep * 33) + '%';
}
function updateNav(){
document.querySelectorAll('.step-nav span')
.forEach(n => n.classList.remove('active'));
document.getElementById('nav'+currentStep)
.classList.add('active');
}
function isUnder18(){
const bday = document.getElementById('geburtsdatum').value;
if(!bday) return false;
const birth = new Date(bday);
const today = new Date();
let age = today.getFullYear() - birth.getFullYear();
if(today.getMonth() < birth.getMonth() ||
(today.getMonth() === birth.getMonth() &&
today.getDate() < birth.getDate())){
age--;
}
return age < 18;
}
function checkAgeAndConsent(){
const box = document.getElementById('consentBox');
const checkbox = document.getElementById('agreeConsent');
if(isUnder18()){
box.classList.remove('d-none');
checkbox.required = true;
}else{
box.classList.add('d-none');
checkbox.required = false;
checkbox.checked = true;
}
}
form.addEventListener('input', saveForm);
function saveForm(){
const data = {};
Array.from(form.elements).forEach(el=>{
if(!el.name) return;
if(el.type === 'checkbox'){
data[el.name] = el.checked ? 'on' : '';
}else{
data[el.name] = el.value;
}
});
localStorage.setItem('registerData', JSON.stringify(data));
}
tx();
function loadForm(){
const data = JSON.parse(localStorage.getItem('registerData'));
if(!data) return;
res.redirect('/contracts');
Object.keys(data).forEach(key=>{
const field = form.elements[key];
if(!field) return;
if(field.type === 'checkbox'){
field.checked = data[key] === 'on';
}else{
field.value = data[key];
}
});
}
function buildSummary(){
const data = JSON.parse(localStorage.getItem('registerData'));
if(!data) return;
document.getElementById('summaryBox').innerHTML = `
<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}
`;
}
form.addEventListener('submit',()=>{
localStorage.removeItem('registerData');
});
// Öffentliche Vertragsauswahl für ALLE Besucher
router.get('/select', (req, res) => {
const vertragsarten = db.prepare(`
SELECT *
FROM vertragsarten
WHERE aktiv = 1
ORDER BY betrag ASC
`).all();
loadForm();
setTimeout(()=>{ nextStep(currentStep); },100);
res.render('contractsSelect', { vertragsarten });
});
</script>
const PDFDocument = require('pdfkit');
router.get('/pdf/:id', (req, res) => {
const v = db.prepare(`
SELECT *
FROM vertragsarten
WHERE id = ? AND aktiv = 1
`).get(req.params.id);
if (!v) {
return res.status(404).send('Vertrag nicht gefunden');
}
const doc = new PDFDocument();
res.setHeader('Content-Type', 'application/pdf');
res.setHeader(
'Content-Disposition',
`inline; filename=vertrag_${v.name}.pdf`
);
doc.pipe(res);
doc.fontSize(20).text(`Vertrag: ${v.name}`, { align: 'center' });
doc.moveDown();
doc.fontSize(12)
.text(`Laufzeit: ${v.laufzeit} Monate`)
.text(`Betrag: ${v.betrag.toFixed(2)} € / Monat`)
.moveDown();
doc.text(v.beschreibung || 'Keine weitere Beschreibung.');
doc.end();
});
module.exports = router;
<%- include('partials/footer') %></br>

View File

@ -1,265 +1,325 @@
const express = require("express");
const Database = require("better-sqlite3");
const validateSepa = require("../utils/sepaValidator");
const { encrypt } = require("../utils/crypto");
const generateVertragsnummer = require("../utils/vertragsnummer");
const createContractPdf = require("../utils/contractPdf");
const sendContractMail = require("../utils/sendContractMail");
const sendAdminMail = require("../utils/sendAdminMail");
<%- include('partials/header') %>
const router = express.Router();
const db = new Database("plusfit.db");
<style>
.step { display: none; }
.step.active { display: block; }
/* =========================
Helper
========================= */
function loadActiveContracts() {
return db
.prepare(
`
SELECT *
FROM vertragsarten
WHERE aktiv = 1
ORDER BY betrag ASC
`,
)
.all();
.container-form {
max-width: 700px;
margin: auto;
}
/* =========================
GET /register
========================= */
router.get("/", (req, res) => {
const vertragId = req.query.vertrag || null;
.progress {
height: 10px;
margin-bottom: 30px;
}
const vertraege = loadActiveContracts();
.step-nav {
display: flex;
justify-content: space-between;
font-size: 14px;
margin-bottom: 20px;
}
// Prüfen ob Vertrag existiert
const selected = vertraege.find((v) => v.id == vertragId);
.step-nav span.active {
font-weight: bold;
color: #3b3be3;
}
return res.render("register", {
vertragsarten: vertraege,
selectedVertrag: selected ? selected.id : null,
selectedVertragData: selected || null,
formData: {},
});
@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>
<div class="progress">
<div id="progressBar"
class="progress-bar bg-primary"
style="width:33%">
</div>
</div>
<div class="step-nav text-center mb-3">
<span id="nav1">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" id="step1">
<h4>Mitgliedsdaten</h4>
<input name="vorname" class="form-control mb-2" placeholder="Vorname" required>
<input name="nachname" class="form-control mb-2" placeholder="Nachname" required>
<input type="date"
name="geburtsdatum"
id="geburtsdatum"
class="form-control mb-2"
required>
<input name="mobil" class="form-control mb-2" placeholder="Mobilnummer" required>
<input type="email" name="email" class="form-control mb-2" placeholder="E-Mail" required>
<h5 class="mt-3">Adresse</h5>
<input name="strasse" class="form-control mb-2" placeholder="Straße" required>
<input name="hausnummer" class="form-control mb-2" placeholder="Nr." required>
<input name="plz" class="form-control mb-2" placeholder="PLZ" required>
<input name="ort" class="form-control mb-2" placeholder="Ort" required>
<input name="land" class="form-control mb-2" value="Deutschland">
<button type="button" class="btn btn-primary mt-3" onclick="nextStep(2)">
Weiter
</button>
</div>
<!-- ================= STEP 2 ================= -->
<div class="step" id="step2">
<h4>Bankdaten</h4>
<input name="kontoinhaber" class="form-control mb-2" placeholder="Kontoinhaber" required>
<input name="mandatsreferenz" class="form-control mb-2" placeholder="Mandatsreferenz" required>
<input name="iban" class="form-control mb-2" placeholder="IBAN" required>
<input name="bic" class="form-control mb-2" placeholder="BIC" required>
<div class="form-check mt-2">
<input class="form-check-input"
type="checkbox"
name="agreeSepa"
value="on"
required>
<label class="form-check-label">
SEPA-Mandat erteilen
</label>
</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 d-none" id="consentBox">
<input class="form-check-input"
type="checkbox"
name="agreeConsent"
id="agreeConsent"
value="on">
<label class="form-check-label">
Einverständnis der Erziehungsberechtigten
</label>
</div>
<div class="form-check mb-3">
<input class="form-check-input"
type="checkbox"
name="agreeAgb"
value="on"
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>
window.fromServerError = <%= typeof errorStep !== 'undefined' ? 'true' : 'false' %>;
let currentStep = <%= typeof errorStep !== 'undefined' ? errorStep : 1 %>;
const form = document.getElementById('registerForm');
function nextStep(step){
if(step > currentStep && !window.fromServerError){
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 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;
}
function updateProgress(){
document.getElementById('progressBar')
.style.width = (currentStep * 33) + '%';
}
function updateNav(){
document.querySelectorAll('.step-nav span')
.forEach(n => n.classList.remove('active'));
document.getElementById('nav'+currentStep)
.classList.add('active');
}
function isUnder18(){
const bday = document.getElementById('geburtsdatum').value;
if(!bday) return false;
const birth = new Date(bday);
const today = new Date();
let age = today.getFullYear() - birth.getFullYear();
if(today.getMonth() < birth.getMonth() ||
(today.getMonth() === birth.getMonth() &&
today.getDate() < birth.getDate())){
age--;
}
return age < 18;
}
function checkAgeAndConsent(){
const box = document.getElementById('consentBox');
const checkbox = document.getElementById('agreeConsent');
if(isUnder18()){
box.classList.remove('d-none');
checkbox.required = true;
}else{
box.classList.add('d-none');
checkbox.required = false;
checkbox.checked = true;
}
}
form.addEventListener('input', saveForm);
function saveForm(){
const data = {};
Array.from(form.elements).forEach(el=>{
if(!el.name) return;
if(el.type === 'checkbox'){
data[el.name] = el.checked ? 'on' : '';
}else{
data[el.name] = el.value;
}
});
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) return;
if(field.type === 'checkbox'){
field.checked = data[key] === 'on';
}else{
field.value = data[key];
}
});
}
function buildSummary(){
const data = JSON.parse(localStorage.getItem('registerData'));
if(!data) return;
document.getElementById('summaryBox').innerHTML = `
<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}
`;
}
form.addEventListener('submit',()=>{
localStorage.removeItem('registerData');
});
/* =========================
POST /register/create
========================= */
router.post("/create", async (req, res) => {
const u = req.body;
const vertragsarten = loadActiveContracts();
loadForm();
setTimeout(()=>{ nextStep(currentStep); },100);
/* =========================
Vertragsdaten laden
========================= */
const contractData = db
.prepare(
`
SELECT name, laufzeit, betrag
FROM vertragsarten
WHERE id = ? AND aktiv = 1
`,
)
.get(u.vertragsvariante);
</script>
if (!contractData) {
return res.render("register", {
vertragsarten,
selectedVertrag: u.vertragsvariante,
error: "Vertragsdaten konnten nicht geladen werden.",
formData: u,
});
}
/* =========================
Pflicht-Zustimmungen
========================= */
if (!u.agreeConsent || !u.agreeAgb || !u.agreeSepa) {
return res.render("register", {
vertragsarten,
selectedVertrag: u.vertragsvariante,
error: "Bitte bestätige alle rechtlichen Hinweise, um fortzufahren.",
formData: u,
});
}
/* =========================
Formale SEPA-Prüfung
========================= */
const sepaError = validateSepa({
ibanValue: u.iban,
bic: u.bic,
mandatsreferenz: u.mandatsreferenz,
});
if (sepaError) {
return res.render("register", {
vertragsarten,
selectedVertrag: u.vertragsvariante,
error: sepaError,
formData: u,
});
}
/* =========================
Logische Prüfungen
========================= */
const mandatsExists = db
.prepare(
`
SELECT id FROM users
WHERE mandatsreferenz = ?
`,
)
.get(u.mandatsreferenz);
if (mandatsExists) {
return res.render("register", {
vertragsarten,
selectedVertrag: u.vertragsvariante,
error: "Diese Mandatsreferenz ist bereits vergeben.",
formData: u,
});
}
/* =========================
Vertrags- & Zustimmungsdaten
========================= */
const vertragsnummer = generateVertragsnummer();
const zustimmungsDatum = new Date().toISOString();
const zustimmungsIp = (
req.headers["x-forwarded-for"] ||
req.socket?.remoteAddress ||
""
)
.split(",")[0]
.trim();
const vertragsversion = "v1.0";
const widerrufBis = new Date();
widerrufBis.setDate(widerrufBis.getDate() + 14);
/* =========================
Verschlüsselung
========================= */
const ibanEncrypted = encrypt(u.iban);
const bicEncrypted = encrypt(u.bic);
/* =========================
SPEICHERN
========================= */
db.prepare(
`
INSERT INTO users (
vertragsnummer,
vertragsvariante,
vorname, nachname,
strasse, hausnummer, plz, ort, land,
mobil, telefon, email,
kontoinhaber, iban, bic, mandatsreferenz,
zustimmung_agb,
zustimmung_sepa,
zustimmung_einverstaendnis,
zustimmung_datum,
zustimmung_ip,
vertragsversion,
widerruf_moeglich_bis,
status,
gesperrt
) VALUES (
?,?,
?,?,
?,?,?,?,?,
?,?,?,
?,?,?,?,
?,?,?,?,
?,?,
?,?,
0
)
`,
).run(
vertragsnummer,
u.vertragsvariante,
u.vorname,
u.nachname,
u.strasse,
u.hausnummer,
u.plz,
u.ort,
u.land,
u.mobil,
u.telefon,
u.email,
u.kontoinhaber,
ibanEncrypted,
bicEncrypted,
u.mandatsreferenz,
u.agreeAgb ? 1 : 0,
u.agreeSepa ? 1 : 0,
u.agreeConsent ? 1 : 0,
zustimmungsDatum,
zustimmungsIp,
vertragsversion,
widerrufBis.toISOString(),
"aktiv",
);
/* =========================
Vertrags-PDF
========================= */
const pdfPath = await createContractPdf({
vertragsnummer,
vorname: u.vorname,
nachname: u.nachname,
vertragName: contractData.name,
laufzeit: contractData.laufzeit,
betrag: contractData.betrag,
datum: zustimmungsDatum,
ip: zustimmungsIp,
});
/* =========================
Vertragsmail
========================= */
await sendContractMail({
email: u.email,
vorname: u.vorname,
vertragsnummer,
vertragName: contractData.name,
betrag: contractData.betrag,
datum: zustimmungsDatum,
pdfPath,
});
await sendAdminMail({
vertragsnummer,
vorname: u.vorname,
nachname: u.nachname,
email: u.email,
vertragName: contractData.name,
betrag: contractData.betrag,
datum: zustimmungsDatum,
ip: zustimmungsIp,
});
/* =========================
ERFOLG
========================= */
return res.render("registerSuccess", { vertragsnummer });
});
module.exports = router;
<%- include('partials/footer') %></br>

View File

@ -1,28 +1,34 @@
<%- include('partials/header') %>
<style>
.step{display:none}
.step.active{display:block}
.step { display:none; }
.step.active { display:block; }
.container-form{max-width:700px;margin:auto}
.container-form{
max-width:700px;
margin:auto;
}
.progress{height:10px;margin-bottom:30px}
.progress{
height:10px;
margin-bottom:30px;
}
.step-nav{
display:flex;
justify-content:space-between;
font-size:14px;
margin-bottom:20px
display:flex;
justify-content:space-between;
font-size:14px;
margin-bottom:20px;
}
.step-nav span.active{
font-weight:bold;
color:#3b3be3
font-weight:bold;
color:#3b3be3;
}
@media(max-width:768px){
h4{font-size:18px}
button{width:100%}
h4{font-size:18px;}
button{width:100%;}
}
</style>
@ -35,6 +41,7 @@ button{width:100%}
</div>
<% } %>
<h3 class="text-center mb-4">Mitglied werden</h3>
@ -47,7 +54,7 @@ style="width:33%">
</div>
<!-- Nav -->
<!-- Navigation -->
<div class="step-nav text-center mb-3">
<span id="nav1">Daten</span>
<span id="nav2">Bank</span>
@ -155,7 +162,6 @@ Weiter →
<!-- Vertrag hidden -->
<input type="hidden"
name="vertragsvariante"
id="vertragHidden"
value="<%= selectedVertrag || '' %>">
@ -167,7 +173,7 @@ value="<%= selectedVertrag || '' %>">
<% if(selectedVertragData){ %>
<%= selectedVertragData.name %>
<%= selectedVertragData.betrag.toFixed(2) %> € / Monat
<% }else{ %>
<% } else { %>
Kein Vertrag gewählt
<% } %>
</b>
@ -179,7 +185,7 @@ Kein Vertrag gewählt
<h5>Rechtliches</h5>
<!-- Eltern -->
<!-- Eltern-Zustimmung -->
<div class="form-check mb-2 d-none" id="consentBox">
<input class="form-check-input"
@ -205,10 +211,7 @@ value="on"
required>
<label class="form-check-label">
<a href="https://plusfit24.de/wp-content/uploads/2022/11/AG_PlusFit24.pdf"
target="_blank">
AGB gelesen
</a>
AGB akzeptiert
</label>
</div>
@ -267,7 +270,7 @@ document.getElementById('step'+step)
updateNav();
updateProgress();
if(step===3){
if(step === 3){
buildSummary();
checkAgeAndConsent();
}