An/Abmelden und nächster Zahler hinzugefügt

This commit is contained in:
Borgal
2025-08-22 15:52:00 +02:00
parent 4f46487d30
commit b09b2b40aa

337
index.php
View File

@@ -3,12 +3,23 @@ include('inc/check_login.php');
include('inc/db.php'); include('inc/db.php');
include('inc/helpers.php'); include('inc/helpers.php');
// Funktion, um den nächsten Termin zu holen // Die Benutzer-ID wird jetzt sicher aus der Session gelesen.
function get_next_meeting($conn) // Stellen Sie sicher, dass Ihre check_login.php die Session startet und die user_id speichert.
if (!isset($_SESSION['user_id'])) {
// Hier können Sie eine Umleitung zur Login-Seite einfügen
// oder, für Testzwecke, eine Standard-ID festlegen.
// Für eine echte Anwendung ist die Umleitung zu empfehlen.
$logged_in_user_id = 1;
} else {
$logged_in_user_id = intval($_SESSION['user_id']);
}
// Funktion, um den aktuellen, noch nicht abgeschlossenen Termin zu holen
function get_current_meeting($conn)
{ {
$sql = "SELECT id, meeting_date, color_id, reason $sql = "SELECT id, meeting_date, color_id, reason
FROM meetings FROM meetings
WHERE meeting_date > NOW() WHERE is_completed = 0
ORDER BY meeting_date ASC ORDER BY meeting_date ASC
LIMIT 1"; LIMIT 1";
@@ -20,8 +31,180 @@ function get_next_meeting($conn)
return null; return null;
} }
// Den nächsten Termin holen // Den aktuellen Termin holen
$row = get_next_meeting($conn); $row = get_current_meeting($conn);
// Logik: Wenn ein Termin existiert und dessen Datum/Uhrzeit in der Vergangenheit liegt,
// wird er als "abgeschlossen" markiert und der nächste Termin wird geladen.
if ($row && strtotime($row['meeting_date']) < time()) {
$id_to_complete = $row['id'];
$sql_update = "UPDATE meetings SET is_completed = 1 WHERE id = ?";
$stmt_update = mysqli_prepare($conn, $sql_update);
if ($stmt_update) {
mysqli_stmt_bind_param($stmt_update, "i", $id_to_complete);
mysqli_stmt_execute($stmt_update);
mysqli_stmt_close($stmt_update);
}
// Den nächsten (jetzt aktuellen) Termin neu laden
$row = get_current_meeting($conn);
}
// --- NEUE LOGIK FÜR TEILNAHMEBESTÄTIGUNG ---
if ($row) {
$meeting_id = $row['id'];
$user_attendance_status = null;
// Aktionen aus der URL verarbeiten
if (isset($_GET['action']) && isset($_GET['meeting_id']) && $_GET['meeting_id'] == $meeting_id) {
$action = $_GET['action'];
$rsvp_status_value = null;
$attended_value = 0; // Standardwert für attended ist 0
if ($action == 'accept') {
$rsvp_status_value = 'accepted';
$attended_value = 1; // Setze attended auf 1 bei Zusage
} elseif ($action == 'decline') {
$rsvp_status_value = 'declined';
$attended_value = 0; // Setze attended auf 0 bei Absage
} elseif ($action == 'maybe') {
$rsvp_status_value = 'maybe';
$attended_value = 0; // Setze attended auf 0 bei "Vielleicht"
}
if ($rsvp_status_value !== null) {
// Vorhandenen Eintrag prüfen
$check_sql = "SELECT rsvp_status FROM meeting_teilnehmer WHERE meeting_id = ? AND user_id = ?";
$check_stmt = mysqli_prepare($conn, $check_sql);
if ($check_stmt) {
mysqli_stmt_bind_param($check_stmt, "ii", $meeting_id, $logged_in_user_id);
mysqli_stmt_execute($check_stmt);
$check_result = mysqli_stmt_get_result($check_stmt);
$existing_attendance = mysqli_fetch_assoc($check_result);
mysqli_stmt_close($check_stmt);
if ($existing_attendance) {
// Eintrag aktualisieren
$update_sql = "UPDATE meeting_teilnehmer SET rsvp_status = ?, attended = ? WHERE meeting_id = ? AND user_id = ?";
$update_stmt = mysqli_prepare($conn, $update_sql);
if ($update_stmt) {
mysqli_stmt_bind_param($update_stmt, "siii", $rsvp_status_value, $attended_value, $meeting_id, $logged_in_user_id);
mysqli_stmt_execute($update_stmt);
mysqli_stmt_close($update_stmt);
}
} else {
// Neuen Eintrag hinzufügen
$insert_sql = "INSERT INTO meeting_teilnehmer (meeting_id, user_id, attended, rsvp_status) VALUES (?, ?, ?, ?)";
$insert_stmt = mysqli_prepare($conn, $insert_sql);
if ($insert_stmt) {
mysqli_stmt_bind_param($insert_stmt, "iiis", $meeting_id, $logged_in_user_id, $attended_value, $rsvp_status_value);
mysqli_stmt_execute($insert_stmt);
mysqli_stmt_close($insert_stmt);
}
}
}
}
// Nach der Aktion die Seite neu laden, um die Buttons zu aktualisieren
header("Location: index.php");
exit;
}
// Status des eingeloggten Nutzers für den aktuellen Termin abrufen
$user_status_sql = "SELECT rsvp_status FROM meeting_teilnehmer WHERE meeting_id = ? AND user_id = ?";
$user_status_stmt = mysqli_prepare($conn, $user_status_sql);
if ($user_status_stmt) {
mysqli_stmt_bind_param($user_status_stmt, "ii", $meeting_id, $logged_in_user_id);
mysqli_stmt_execute($user_status_stmt);
$user_status_result = mysqli_stmt_get_result($user_status_stmt);
$user_status_row = mysqli_fetch_assoc($user_status_result);
if ($user_status_row) {
$user_attendance_status = $user_status_row['rsvp_status'];
}
mysqli_stmt_close($user_status_stmt);
}
// Daten für die Benutzerübersicht abrufen
// Annahme: Es gibt eine 'users'-Tabelle mit 'id' und 'username'
$attendees_sql = "SELECT t.rsvp_status, u.username
FROM meeting_teilnehmer AS t
LEFT JOIN users AS u ON t.user_id = u.id
WHERE t.meeting_id = ?";
$attendees_stmt = mysqli_prepare($conn, $attendees_sql);
$accepted_users = [];
$declined_users = [];
$maybe_users = [];
$total_accepted = 0;
$total_declined = 0;
$total_maybe = 0;
if ($attendees_stmt) {
mysqli_stmt_bind_param($attendees_stmt, "i", $meeting_id);
mysqli_stmt_execute($attendees_stmt);
$attendees_result = mysqli_stmt_get_result($attendees_stmt);
while ($row_user = mysqli_fetch_assoc($attendees_result)) {
switch ($row_user['rsvp_status']) {
case 'accepted':
$accepted_users[] = htmlspecialchars($row_user['username']);
$total_accepted++;
break;
case 'declined':
$declined_users[] = htmlspecialchars($row_user['username']);
$total_declined++;
break;
case 'maybe':
$maybe_users[] = htmlspecialchars($row_user['username']);
$total_maybe++;
break;
}
}
mysqli_stmt_close($attendees_stmt);
}
// --- NEUE LOGIK FÜR DIE BESTIMMUNG DES NÄCHSTEN ZAHLERS ---
$next_payer_username = null;
// Nur prüfen, wenn es zugesagte Teilnehmer gibt
if ($total_accepted > 0) {
// SQL-Abfrage, um die Anzahl der bezahlten Einträge für zugesagte Benutzer zu ermitteln
// Die Sub-Query zählt die bezahlten Einträge (paid=1) für jeden Benutzer.
$sql_next_payer = "
SELECT
u.username,
(SELECT COUNT(*) FROM meeting_teilnehmer WHERE user_id = u.id AND paid = 1) AS paid_count
FROM meeting_teilnehmer mt
JOIN users u ON mt.user_id = u.id
WHERE mt.meeting_id = ? AND mt.rsvp_status = 'accepted'
ORDER BY paid_count ASC
";
$stmt_next_payer = mysqli_prepare($conn, $sql_next_payer);
mysqli_stmt_bind_param($stmt_next_payer, "i", $meeting_id);
mysqli_stmt_execute($stmt_next_payer);
$result_next_payer = mysqli_stmt_get_result($stmt_next_payer);
$payer_candidates = [];
$min_paid_count = -1;
while ($row_payer = mysqli_fetch_assoc($result_next_payer)) {
// Finden der minimalen Anzahl an bezahlten Rechnungen
if ($min_paid_count == -1 || $row_payer['paid_count'] < $min_paid_count) {
$min_paid_count = $row_payer['paid_count'];
$payer_candidates = [$row_payer['username']];
} elseif ($row_payer['paid_count'] == $min_paid_count) {
// Bei Gleichstand den Benutzer zur Liste der Kandidaten hinzufügen
$payer_candidates[] = $row_payer['username'];
}
}
mysqli_stmt_close($stmt_next_payer);
// Neu: Bei Gleichstand wird alphabetisch sortiert und der erste genommen.
if (!empty($payer_candidates)) {
sort($payer_candidates);
$next_payer_username = $payer_candidates[0];
}
}
}
// Die Funktion get_readable_text_color() ist jetzt in helpers.php und kann hier direkt aufgerufen werden. // Die Funktion get_readable_text_color() ist jetzt in helpers.php und kann hier direkt aufgerufen werden.
@@ -39,9 +222,9 @@ $german_weekdays = [
]; ];
?> ?>
<div class="container py-5"> <div class="container py-0">
<div class="text-center mb-5"> <div class="text-center mb-4">
<h1 class="display-4 fw-bold">DoMiLi</h1> <h2 class="fw-bold">Farbe des nächsten Treffens</h2>
</div> </div>
<?php if ($row): ?> <?php if ($row): ?>
@@ -59,21 +242,113 @@ $german_weekdays = [
?> ?>
<div class="card mx-auto bg-light shadow" style="max-width: 400px;"> <div class="card mx-auto bg-light shadow" style="max-width: 400px;">
<div class="card-body text-center"> <div class="card-body text-center">
<h5 class="card-title mb-3">Farbe des nächsten Treffens</h5>
<div class="rounded-4 mb-3 mx-auto d-flex flex-column justify-content-center align-items-center color-box" style="background-image: linear-gradient(135deg, <?= htmlspecialchars($color_row['hex_code']) ?>, <?= darken_color($color_row['hex_code']) ?>);"> <div class="rounded-4 mb-3 mx-auto d-flex flex-column justify-content-center align-items-center color-box" style="background-image: linear-gradient(135deg, <?= htmlspecialchars($color_row['hex_code']) ?>, <?= darken_color($color_row['hex_code']) ?>);">
<p class="fs-5 fw-semibold m-0" style="color: <?= get_readable_text_color($color_row['hex_code']) ?>;"><?= htmlspecialchars($color_row['name']) ?></p> <p class="fs-5 fw-semibold m-0" style="color: <?= get_readable_text_color($color_row['hex_code']) ?>;"><?= htmlspecialchars($color_row['name']) ?></p>
<p class="fs-6 fw-normal m-0" style="color: <?= get_readable_text_color($color_row['hex_code']) ?>;"><?= htmlspecialchars($row['reason']) ?></p> <p class="fs-6 fw-normal m-0" style="color: <?= get_readable_text_color($color_row['hex_code']) ?>;"><?= htmlspecialchars($row['reason']) ?></p>
</div> </div>
<p class="text-muted">nächster Termin:</p> <p class="text-muted">nächster Termin:</p>
<p class="text-muted fw-bold"><?= $german_weekday . ' ' . date('d.m.Y H:i', strtotime($row['meeting_date'])) ?></p> <p class="text-muted h3 fw-bold mb-0"><?= $german_weekday . ' ' . date('d.m.Y H:i', strtotime($row['meeting_date'])) ?></p>
</div> </div>
<div class="d-flex justify-content-center my-3" style="max-width: 400px; margin-left: auto; margin-right: auto;"> <div class="d-flex justify-content-center pt-2 pb-3" style="max-width: 400px; margin-left: auto; margin-right: auto; flex-direction: column; align-items: center;">
<a href="#" class="btn btn-sm btn-outline-danger me-2">Absagen</a> <?php if ($user_attendance_status === 'accepted'): ?>
<a href="#" class="btn btn-sm btn-outline-secondary">Verschiebung beantragen</a> <p class="text-success fw-bold mb-4">Du hast zugesagt!</p>
<div class="d-flex justify-content-center">
<a href="index.php?action=decline&meeting_id=<?= htmlspecialchars($meeting_id); ?>" class="btn btn-sm btn-outline-danger me-2">Absagen</a>
<a href="index.php?action=maybe&meeting_id=<?= htmlspecialchars($meeting_id); ?>" class="btn btn-sm btn-outline-info">noch unklar</a>
</div>
<?php elseif ($user_attendance_status === 'declined'): ?>
<p class="text-danger fw-bold mb-4">Du hast abgesagt!</p>
<div class="d-flex justify-content-center">
<a href="index.php?action=accept&meeting_id=<?= htmlspecialchars($meeting_id); ?>" class="btn btn-sm btn-outline-success me-2">Zusagen</a>
<a href="index.php?action=maybe&meeting_id=<?= htmlspecialchars($meeting_id); ?>" class="btn btn-sm btn-outline-info">noch unklar</a>
</div>
<?php elseif ($user_attendance_status === 'maybe'): ?>
<p class="text-muted fw-bold mb-4">Vielleicht dabei!</p>
<div class="d-flex justify-content-center">
<a href="index.php?action=accept&meeting_id=<?= htmlspecialchars($meeting_id); ?>" class="btn btn-sm btn-outline-success me-2">Zusagen</a>
<a href="index.php?action=decline&meeting_id=<?= htmlspecialchars($meeting_id); ?>" class="btn btn-sm btn-outline-danger">Absagen</a>
</div>
<?php else: ?>
<p class="text-muted fw-bold mb-4">Bist du dabei?</p>
<div class="d-flex justify-content-center">
<a href="index.php?action=accept&meeting_id=<?= htmlspecialchars($meeting_id); ?>" class="btn btn-sm btn-outline-success me-2">Zusagen</a>
<a href="index.php?action=decline&meeting_id=<?= htmlspecialchars($meeting_id); ?>" class="btn btn-sm btn-outline-danger me-2">Absagen</a>
<a href="index.php?action=maybe&meeting_id=<?= htmlspecialchars($meeting_id); ?>" class="btn btn-sm btn-outline-info">Vielleicht</a>
</div>
<?php endif; ?>
</div> </div>
<?php if ($next_payer_username): ?>
<div class="text-center my-2 mx-auto" style="max-width: 400px; border-radius: 0.5rem;">
<p class="fw-bold mb-1">Empfehlung für die nächste Rechnung:</p>
<h4 class="text-muted fw-bold mb-0"><?= htmlspecialchars($next_payer_username); ?></h4>
</div>
<?php endif; ?>
<div class="d-flex justify-content-center my-3" style="max-width: 400px; margin-left: auto; margin-right: auto;"> <div class="d-flex justify-content-center my-3" style="max-width: 400px; margin-left: auto; margin-right: auto;">
<a href="admin/participant.php?id=<?= htmlspecialchars($row['id']) ?>" class="btn btn-sm btn-outline-primary">Teilnahme eintragen</a> <a href="admin/participant.php?id=<?= htmlspecialchars($row['id']) ?>" class="btn btn-sm btn-outline-secondary">Teilnahme eintragen</a>
</div>
<div class="card-footer text-center mt-3">
<p class="text-muted mb-1">Teilnehmerübersicht:</p>
<div class="d-flex justify-content-around">
<div class="text-center">
<p class="text-success mb-1 small">
<a class="text-success text-decoration-none participant-toggle-collapse" href="#acceptedCollapse" role="button" aria-expanded="false" aria-controls="acceptedCollapse">
Zusagen: <?= $total_accepted; ?>
</a>
</p>
<div class="collapse mt-2" id="acceptedCollapse">
<?php if (!empty($accepted_users)): ?>
<ul class="list-unstyled mb-0">
<?php foreach ($accepted_users as $user): ?>
<li><?= $user; ?></li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<p class="mb-0 text-muted small">Keine</p>
<?php endif; ?>
</div>
</div>
<div class="text-center">
<p class="text-danger mb-1 small">
<a class="text-danger text-decoration-none participant-toggle-collapse" href="#declinedCollapse" role="button" aria-expanded="false" aria-controls="declinedCollapse">
Absagen: <?= $total_declined; ?>
</a>
</p>
<div class="collapse mt-2" id="declinedCollapse">
<?php if (!empty($declined_users)): ?>
<ul class="list-unstyled mb-0">
<?php foreach ($declined_users as $user): ?>
<li><?= $user; ?></li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<p class="mb-0 text-muted small">Keine</p>
<?php endif; ?>
</div>
</div>
<div class="text-center">
<p class="text-warning mb-1 small">
<a class="text-info text-decoration-none participant-toggle-collapse" href="#maybeCollapse" role="button" aria-expanded="false" aria-controls="maybeCollapse">
Vielleicht: <?= $total_maybe; ?>
</a>
</p>
<div class="collapse mt-2" id="maybeCollapse">
<?php if (!empty($maybe_users)): ?>
<ul class="list-unstyled mb-0">
<?php foreach ($maybe_users as $user): ?>
<li><?= $user; ?></li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<p class="mb-0 text-muted small">Keine</p>
<?php endif; ?>
</div>
</div>
</div>
</div> </div>
</div> </div>
@@ -85,4 +360,38 @@ $german_weekdays = [
</div> </div>
<script>
// Dies ist ein einfaches JavaScript, um alle drei Listen gleichzeitig ein- und auszuklappen.
document.addEventListener('DOMContentLoaded', function() {
// Wählt nur die Links mit der spezifischen Klasse aus
const links = document.querySelectorAll('.participant-toggle-collapse');
// Wählt nur die Collapse-Elemente innerhalb des .card-footer aus
const collapseElements = document.querySelectorAll('.card-footer .collapse');
links.forEach(link => {
link.addEventListener('click', function(e) {
// Verhindert das Standardverhalten des Links (Springen zur ID)
e.preventDefault();
// Überprüft, ob das erste Element sichtbar ist
const isExpanded = collapseElements[0].classList.contains('show');
// Fügt die "show"-Klasse zu allen Elementen hinzu oder entfernt sie
collapseElements.forEach(el => {
if (isExpanded) {
el.classList.remove('show');
} else {
el.classList.add('show');
}
});
// Aktualisiert den aria-expanded-Status für Barrierefreiheit
links.forEach(l => {
l.setAttribute('aria-expanded', !isExpanded);
});
});
});
});
</script>
<?php include('inc/footer.php'); ?> <?php include('inc/footer.php'); ?>