diff --git a/public/css/style.css b/public/css/style.css index 5057f56..783ef03 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -1027,3 +1027,45 @@ body { border-color: var(--error) !important; background: #fff5f5 !important; } + +/* ---- Auszeit-Bereich in Karte 3 ---- */ +.auszeit-section { + margin-top: 20px; + border-top: 1.5px solid var(--border); + padding-top: 16px; +} +.auszeit-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 12px; +} +.auszeit-title { + font-size: 0.85rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.5px; + color: var(--text-muted); +} +.neue-auszeit { + margin-top: 16px; + background: #f8f8ff; + border: 1.5px dashed var(--primary); + border-radius: 10px; + padding: 16px; +} +.neue-auszeit-title { + font-size: 0.88rem; + font-weight: 700; + color: var(--primary); + margin-bottom: 12px; +} +.auszeit-form-row { + display: flex; + gap: 12px; + align-items: flex-start; + flex-wrap: wrap; +} +.auszeit-form-row .karte-field { + min-width: 130px; +} diff --git a/routes/admin.js b/routes/admin.js index 03b30cd..6003f4e 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -197,8 +197,7 @@ router.post('/members/:id/update', requireAdmin, async (req, res) => { const { salutation, title, first_name, last_name, birth_date, email, phone, street, address_addition, zip, city, - bank_name, account_holder, iban, tariff_id, status, - pause_from, pause_until + bank_name, account_holder, iban, tariff_id, status } = req.body; try { await db.query(` @@ -219,4 +218,61 @@ router.post('/members/:id/update', requireAdmin, async (req, res) => { res.redirect(`/admin/members/${req.params.id}?error=Fehler+beim+Speichern`); } }); + +// ===== AUSZEITEN ===== +router.post('/members/:id/pauses/add', requireAdmin, async (req, res) => { + const { pause_start, pause_end, pause_months, reason } = req.body; + const memberId = req.params.id; + try { + if (!pause_start || !pause_end || !pause_months) { + return res.redirect(`/admin/members/${memberId}?error=Bitte+alle+Pflichtfelder+ausfüllen`); + } + if (new Date(pause_end) <= new Date(pause_start)) { + return res.redirect(`/admin/members/${memberId}?error=Enddatum+muss+nach+Startdatum+liegen`); + } + // Auszeit eintragen + await db.query( + 'INSERT INTO membership_pauses (membership_id, pause_start, pause_end, pause_months, reason) VALUES (?, ?, ?, ?, ?)', + [memberId, pause_start, pause_end, pause_months, reason || null] + ); + // pause_months_total und effective_end aktualisieren + await db.query(` + UPDATE memberships + SET pause_months_total = ( + SELECT COALESCE(SUM(pause_months), 0) FROM membership_pauses WHERE membership_id = ? + ), + effective_end = DATE_ADD(contract_end, INTERVAL ( + SELECT COALESCE(SUM(pause_months), 0) FROM membership_pauses WHERE membership_id = ? + ) MONTH) + WHERE id = ? + `, [memberId, memberId, memberId]); + res.redirect(`/admin/members/${memberId}?success=Auszeit+eingetragen`); + } catch (err) { + console.error(err); + res.redirect(`/admin/members/${memberId}?error=Fehler+beim+Eintragen+der+Auszeit`); + } +}); + +router.post('/members/:id/pauses/:pauseId/delete', requireAdmin, async (req, res) => { + const { id: memberId, pauseId } = req.params; + try { + await db.query('DELETE FROM membership_pauses WHERE id = ? AND membership_id = ?', [pauseId, memberId]); + // Summe neu berechnen + await db.query(` + UPDATE memberships + SET pause_months_total = ( + SELECT COALESCE(SUM(pause_months), 0) FROM membership_pauses WHERE membership_id = ? + ), + effective_end = DATE_ADD(contract_end, INTERVAL ( + SELECT COALESCE(SUM(pause_months), 0) FROM membership_pauses WHERE membership_id = ? + ) MONTH) + WHERE id = ? + `, [memberId, memberId, memberId]); + res.redirect(`/admin/members/${memberId}?success=Auszeit+gelöscht`); + } catch (err) { + console.error(err); + res.redirect(`/admin/members/${memberId}?error=Fehler+beim+Löschen`); + } +}); + module.exports = router; diff --git a/views/admin/member-detail.ejs b/views/admin/member-detail.ejs index 7d5af9a..6e1eef4 100644 --- a/views/admin/member-detail.ejs +++ b/views/admin/member-detail.ejs @@ -10,7 +10,6 @@
-
-
-
← Zurück

<%= member.first_name %> <%= member.last_name %>

Mitglied #<%= member.id %> - - <%= member.status === 'active' ? '✅ Aktiv' : '❌ Inaktiv' %> + + <%= member.status === 'active' ? '✅ Aktiv' : member.status === 'paused' ? '⏸ Pausiert' : '❌ Inaktiv' %> <% if (member.is_minor) { %> ⚠️ Minderjährig @@ -52,23 +49,19 @@ <% if (error) { %>
<%= error %>
<% } %>
-
-
- 👤 -

Persönliche Daten

-
+
👤

Persönliche Daten

@@ -107,10 +100,7 @@
-
- 📍 -

Adresse

-
+
📍

Adresse

@@ -138,12 +128,10 @@
-
-
- 📄 -

Vertrag

-
+
+
📄

Vertrag

+
@@ -156,6 +144,7 @@
+
@@ -165,8 +154,6 @@
-
-
@@ -176,6 +163,7 @@
+
@@ -185,8 +173,6 @@
-
-
-
-
- - + + +
+
+ ⏸ Auszeiten
-
- - + + <% if (pauses.length === 0) { %> +

Keine Auszeiten eingetragen.

+ <% } else { %> + + + + + + + + + + + + + <% pauses.forEach(p => { %> + + + + + + + + + <% }) %> + +
VonBisMonateGrundEingetragen am
<%= new Date(p.pause_start).toLocaleDateString('de-DE') %><%= new Date(p.pause_end).toLocaleDateString('de-DE') %><%= p.pause_months %><%= p.reason || '–' %><%= new Date(p.created_at).toLocaleDateString('de-DE') %>
+ <% } %> + + +
+
-
-
- 🏦 -

Bankdaten / SEPA

-
+
+
🏦

Bankdaten / SEPA

-
+
-
-
-
+
-
-
-
- - -
-
-
-
@@ -253,6 +281,15 @@
+
+
+ + +
+
+
<% if (member.is_minor) { %>
@@ -264,42 +301,6 @@
- -
-
- -

Auszeiten

-
-
- <% if (pauses.length === 0) { %> -

Keine Auszeiten eingetragen.

- <% } else { %> - - - - - - - - - - - - <% pauses.forEach(p => { %> - - - - - - - - <% }) %> - -
VonBisMonateGrundEingetragen am
<%= new Date(p.pause_start).toLocaleDateString('de-DE') %><%= new Date(p.pause_end).toLocaleDateString('de-DE') %><%= p.pause_months %><%= p.reason || '–' %><%= new Date(p.created_at).toLocaleDateString('de-DE') %>
- <% } %> -
-
-
@@ -312,20 +313,19 @@ function enableEdit() { editableFields.forEach(f => f.removeAttribute('disabled')); - // IBAN Validierung aktivieren - const ibanInput = document.getElementById('ibanInput'); - const ibanMessage = document.getElementById('ibanMessage'); - if (ibanInput) { - attachIBANValidation(ibanInput, null, ibanMessage); - } document.getElementById('editBtn').classList.add('hidden'); document.getElementById('saveBtn').classList.remove('hidden'); document.getElementById('cancelBtn').classList.remove('hidden'); document.querySelectorAll('.karte').forEach(k => k.classList.add('edit-mode')); + // Auszeit-Bereich einblenden + document.getElementById('neueAuszeit').classList.remove('hidden'); + document.querySelectorAll('.edit-only').forEach(el => el.classList.remove('hidden')); + // IBAN Validierung + const ibanInput = document.getElementById('ibanInput'); + if (ibanInput) attachIBANValidation(ibanInput, null, document.getElementById('ibanMessage')); } function cancelEdit() { - // Seite neu laden = alle Änderungen verwerfen window.location.reload(); }