This commit is contained in:
cay 2026-03-28 09:28:41 +00:00
parent ac03d796bf
commit fed7951a98
4 changed files with 54 additions and 9 deletions

View File

@ -1537,3 +1537,23 @@ body:not(.admin-body) > * {
.member-row-pending::before {
content: '⏳';
}
/* ---- Neue Mitglieder Hervorhebung ---- */
.stat-card-new {
border: 1.5px solid #bae6fd !important;
background: #f0f9ff !important;
cursor: pointer;
transition: box-shadow 0.2s;
}
.stat-card-new:hover {
box-shadow: 0 0 0 3px rgba(8,145,178,0.15);
}
.member-row-new td {
background: #f0f9ff !important;
}
.member-row-new td:first-child::before {
content: '🆕 ';
}
.member-row-new:hover td {
background: #e0f2fe !important;
}

View File

@ -51,7 +51,8 @@ router.get('/', requireAdmin, async (req, res) => {
SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active_count,
SUM(CASE WHEN is_minor = 1 THEN 1 ELSE 0 END) as minors,
SUM(CASE WHEN created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) THEN 1 ELSE 0 END) as last_30_days,
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending_count
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending_count,
SUM(CASE WHEN reviewed = 0 AND status = 'active' THEN 1 ELSE 0 END) as new_count
FROM memberships
`);
res.render('admin/dashboard', {
@ -334,4 +335,15 @@ router.post('/members/:id/confirm', requireAdmin, async (req, res) => {
}
});
// Mitglied als gesehen markieren
router.post('/members/:id/reviewed', requireAdmin, async (req, res) => {
try {
await db.query('UPDATE memberships SET reviewed = 1 WHERE id = ?', [req.params.id]);
res.json({ success: true });
} catch (err) {
res.json({ success: false });
}
});
module.exports = router;

View File

@ -190,8 +190,8 @@ router.post('/submit-membership', async (req, res) => {
start_package_price,
signup_date, contract_start, contract_end, effective_end,
first_payment_date, first_payment_amt,
status)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
status, reviewed)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
`, [
tariff_id, salutation, title || '', first_name, last_name, birth_date,
email, phone || '', street, address_addition || '', zip, city,
@ -208,7 +208,7 @@ router.post('/submit-membership', async (req, res) => {
contractEnd.toISOString().split('T')[0],
contractStart.toISOString().split('T')[0],
firstPaymentAmt,
'pending'
'pending', 0
]);
// Bestätigungs-E-Mail senden

View File

@ -17,8 +17,8 @@
<a href="#" class="nav-link" onclick="showSection('kategorien', this)">🏷️ Kategorien</a>
<a href="#" class="nav-link" onclick="showSection('mitglieder', this)">
👥 Mitglieder
<% if (stats.pending_count > 0) { %>
<span class="nav-badge"><%= stats.pending_count %></span>
<% if ((stats.pending_count || 0) + (stats.new_count || 0) > 0) { %>
<span class="nav-badge"><%= (stats.pending_count || 0) + (stats.new_count || 0) %></span>
<% } %>
</a>
<a href="/admin/contracts" class="nav-link">📑 Verträge</a>
@ -50,9 +50,15 @@
<div class="stat-label">Letzte 30 Tage</div>
</div>
<% if (stats.pending_count > 0) { %>
<div class="stat-card stat-card-pending" onclick="showSection('mitglieder', document.querySelector('[onclick*=mitglieder]'))" style="cursor:pointer" title="Klicken um ausstehende Verträge anzuzeigen">
<div class="stat-card stat-card-pending" onclick="showSection('mitglieder', document.querySelector('[onclick*=mitglieder]'))" style="cursor:pointer" title="Ausstehende Bestätigungen">
<div class="stat-number" style="color:var(--error)"><%= stats.pending_count %></div>
<div class="stat-label">⚠️ Ausstehend</div>
<div class="stat-label">⏳ Ausstehend</div>
</div>
<% } %>
<% if (stats.new_count > 0) { %>
<div class="stat-card stat-card-new" onclick="showSection('mitglieder', document.querySelector('[onclick*=mitglieder]'))" style="cursor:pointer" title="Neue Mitglieder die noch nicht bearbeitet wurden">
<div class="stat-number" style="color:#0891b2"><%= stats.new_count %></div>
<div class="stat-label">🆕 Neu</div>
</div>
<% } %>
<div class="stat-card">
@ -165,7 +171,7 @@
</thead>
<tbody>
<% memberships.forEach(m => { %>
<tr class="member-row <%= m.status === 'pending' ? 'member-row-pending' : '' %>" onclick="window.location='/admin/members/<%= m.id %>'" style="cursor:pointer">
<tr class="member-row <%= m.status === 'pending' ? 'member-row-pending' : (!m.reviewed ? 'member-row-new' : '') %>" onclick="openMember(<%= m.id %>, <%= m.reviewed ? 1 : 0 %>)" style="cursor:pointer">
<td><strong><%= m.salutation %> <%= m.first_name %> <%= m.last_name %></strong></td>
<td><%= m.email %></td>
<td><%= m.tariff_name || '' %></td>
@ -378,6 +384,13 @@
toggleModal('editCategoryModal');
}
function openMember(id, reviewed) {
if (!reviewed) {
fetch('/admin/members/' + id + '/reviewed', { method: 'POST' });
}
window.location = '/admin/members/' + id;
}
function filterMembers() {
const q = document.getElementById('memberSearch').value.toLowerCase();
document.querySelectorAll('.member-row').forEach(row => {