439 lines
21 KiB
PHP
Executable File
439 lines
21 KiB
PHP
Executable File
<?php
|
||
include('inc/check_login.php');
|
||
include('inc/db.php');
|
||
include('inc/helpers.php');
|
||
|
||
$logged_in_user_id = isset($_SESSION['user_id']) ? intval($_SESSION['user_id']) : 1;
|
||
|
||
// 🔹 Funktion: Prüft, ob Benutzer im Abwesenheitsmodus ist
|
||
function is_user_on_vacation($conn, $user_id, $meeting_date)
|
||
{
|
||
$stmt = mysqli_prepare($conn, "
|
||
SELECT 1 FROM vacations
|
||
WHERE user_id = ?
|
||
AND ? BETWEEN start_date AND end_date
|
||
LIMIT 1
|
||
");
|
||
if (!$stmt) return false;
|
||
mysqli_stmt_bind_param($stmt, "is", $user_id, $meeting_date);
|
||
mysqli_stmt_execute($stmt);
|
||
$result = mysqli_stmt_get_result($stmt);
|
||
$found = mysqli_fetch_assoc($result);
|
||
mysqli_stmt_close($stmt);
|
||
return $found !== null;
|
||
}
|
||
|
||
// 🔹 Funktion: Automatisch ablehnen, wenn im Urlaub (außer bei expliziter Zusage)
|
||
function auto_decline_if_on_vacation($conn, $meeting_id, $user_id, $meeting_date)
|
||
{
|
||
if (!is_user_on_vacation($conn, $user_id, $meeting_date)) {
|
||
return null;
|
||
}
|
||
|
||
$check_sql = "SELECT rsvp_status FROM meeting_teilnehmer WHERE meeting_id = ? AND user_id = ?";
|
||
$check_stmt = mysqli_prepare($conn, $check_sql);
|
||
mysqli_stmt_bind_param($check_stmt, "ii", $meeting_id, $user_id);
|
||
mysqli_stmt_execute($check_stmt);
|
||
$existing = mysqli_fetch_assoc(mysqli_stmt_get_result($check_stmt));
|
||
mysqli_stmt_close($check_stmt);
|
||
|
||
// Wenn bereits "accepted", nichts tun
|
||
if ($existing && $existing['rsvp_status'] === 'accepted') {
|
||
return 'accepted';
|
||
}
|
||
|
||
// Sonst: ablehnen
|
||
if ($existing) {
|
||
$upd = mysqli_prepare($conn, "UPDATE meeting_teilnehmer SET rsvp_status = 'declined', attended = 0 WHERE meeting_id = ? AND user_id = ?");
|
||
mysqli_stmt_bind_param($upd, "ii", $meeting_id, $user_id);
|
||
mysqli_stmt_execute($upd);
|
||
mysqli_stmt_close($upd);
|
||
} else {
|
||
$ins = mysqli_prepare($conn, "INSERT INTO meeting_teilnehmer (meeting_id, user_id, rsvp_status, attended) VALUES (?, ?, 'declined', 0)");
|
||
mysqli_stmt_bind_param($ins, "ii", $meeting_id, $user_id);
|
||
mysqli_stmt_execute($ins);
|
||
mysqli_stmt_close($ins);
|
||
}
|
||
|
||
return 'declined';
|
||
}
|
||
|
||
// Funktion: aktueller, nicht abgeschlossener Termin
|
||
function get_current_meeting($conn)
|
||
{
|
||
$sql = "SELECT id, meeting_date, color_id, reason
|
||
FROM meetings
|
||
WHERE is_completed = 0
|
||
ORDER BY meeting_date ASC
|
||
LIMIT 1";
|
||
$result = mysqli_query($conn, $sql);
|
||
return ($result && mysqli_num_rows($result) > 0) ? mysqli_fetch_assoc($result) : null;
|
||
}
|
||
|
||
$row = get_current_meeting($conn);
|
||
|
||
// 🔴 Automatisches Abschließen bei vergangenem Termin wurde ENTFERNT
|
||
// → Termin bleibt sichtbar, bis Admin in participant.php abschließt
|
||
|
||
// --- TEILNAHME-LOGIK ---
|
||
if ($row) {
|
||
$meeting_id = $row['id'];
|
||
|
||
// Aktionen verarbeiten (Zusagen / Absagen / Vielleicht)
|
||
if (isset($_GET['action']) && isset($_GET['meeting_id']) && $_GET['meeting_id'] == $meeting_id) {
|
||
$action = $_GET['action'];
|
||
$rsvp_status_value = null;
|
||
$attended_value = 0;
|
||
|
||
if ($action === 'accept') {
|
||
$rsvp_status_value = 'accepted';
|
||
$attended_value = 1;
|
||
} elseif ($action === 'decline') {
|
||
$rsvp_status_value = 'declined';
|
||
$attended_value = 0;
|
||
} elseif ($action === 'maybe') {
|
||
$rsvp_status_value = 'maybe';
|
||
$attended_value = 0;
|
||
}
|
||
|
||
if ($rsvp_status_value !== null) {
|
||
$check_sql = "SELECT rsvp_status FROM meeting_teilnehmer WHERE meeting_id = ? AND user_id = ?";
|
||
$check_stmt = mysqli_prepare($conn, $check_sql);
|
||
$existing = null;
|
||
if ($check_stmt) {
|
||
mysqli_stmt_bind_param($check_stmt, "ii", $meeting_id, $logged_in_user_id);
|
||
mysqli_stmt_execute($check_stmt);
|
||
$existing = mysqli_fetch_assoc(mysqli_stmt_get_result($check_stmt));
|
||
mysqli_stmt_close($check_stmt);
|
||
}
|
||
|
||
if ($existing) {
|
||
$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 {
|
||
$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);
|
||
}
|
||
}
|
||
header("Location: index.php");
|
||
exit;
|
||
}
|
||
}
|
||
|
||
// 🔥 Automatisch ablehnen, wenn im Abwesenheitsmodus
|
||
$auto_declined = auto_decline_if_on_vacation($conn, $meeting_id, $logged_in_user_id, $row['meeting_date']);
|
||
|
||
// Status abrufen (kann jetzt "declined" sein)
|
||
$user_attendance_status = null;
|
||
$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);
|
||
}
|
||
|
||
// Teilnehmerlisten laden
|
||
$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);
|
||
}
|
||
|
||
// --- ZAHLENDE PERSON BESTIMMEN ---
|
||
$next_payer_username = null;
|
||
if ($total_accepted > 0) {
|
||
$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)) {
|
||
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) {
|
||
$payer_candidates[] = $row_payer['username'];
|
||
}
|
||
}
|
||
mysqli_stmt_close($stmt_next_payer);
|
||
if (!empty($payer_candidates)) {
|
||
sort($payer_candidates);
|
||
$next_payer_username = $payer_candidates[0];
|
||
}
|
||
}
|
||
|
||
// --- TERMINVERSCHIEBUNG (ohne Änderung) ---
|
||
include('verschiebung.php');
|
||
}
|
||
|
||
include('inc/header.php');
|
||
|
||
$german_weekdays = [
|
||
'Mon' => 'Mo.',
|
||
'Tue' => 'Di.',
|
||
'Wed' => 'Mi.',
|
||
'Thu' => 'Do.',
|
||
'Fri' => 'Fr.',
|
||
'Sat' => 'Sa.',
|
||
'Sun' => 'So.'
|
||
];
|
||
?>
|
||
|
||
<div class="container py-0">
|
||
<!-- Optional: Hinweis bei automatischer Ablehnung -->
|
||
<?php if (isset($auto_declined) && $auto_declined === 'declined'): ?>
|
||
<div class="alert alert-info alert-dismissible fade show" role="alert">
|
||
Abwesenheitsmodus aktiv.
|
||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if (isset($_SESSION['success_message'])): ?>
|
||
<div class="alert alert-info alert-dismissible fade show" role="alert">
|
||
<?= htmlspecialchars($_SESSION['success_message']) ?>
|
||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||
</div>
|
||
<?php unset($_SESSION['success_message']); ?>
|
||
<?php endif; ?>
|
||
|
||
<?php if (isset($_SESSION['error_message'])): ?>
|
||
<div class="alert alert-warning alert-dismissible fade show" role="alert">
|
||
<?= htmlspecialchars($_SESSION['error_message']) ?>
|
||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||
</div>
|
||
<?php unset($_SESSION['error_message']); ?>
|
||
<?php endif; ?>
|
||
|
||
<div class="text-center mb-4">
|
||
<h2 class="fw-bold">Farbe des nächsten Treffens</h2>
|
||
</div>
|
||
|
||
<?php if ($row): ?>
|
||
<?php
|
||
$english_weekday = date('D', strtotime($row['meeting_date']));
|
||
$german_weekday = $german_weekdays[$english_weekday] ?? '';
|
||
$color_stmt = mysqli_prepare($conn, "SELECT * FROM colors WHERE id = ?");
|
||
mysqli_stmt_bind_param($color_stmt, "i", $row['color_id']);
|
||
mysqli_stmt_execute($color_stmt);
|
||
$color_row = mysqli_fetch_assoc(mysqli_stmt_get_result($color_stmt));
|
||
?>
|
||
<div class="card mx-auto bg-light shadow" style="max-width: 500px;">
|
||
<div class="card-body text-center">
|
||
<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-6 fw-normal m-0" style="color: <?= get_readable_text_color($color_row['hex_code']) ?>;"><?= htmlspecialchars($row['reason']) ?></p>
|
||
</div>
|
||
<p class="text-muted">nächster Termin:</p>
|
||
<p class="text-muted h3 fw-bold mb-2"><?= $german_weekday . ' ' . date('d.m.Y H:i', strtotime($row['meeting_date'])) ?></p>
|
||
<div class="mt-3 mb-2">
|
||
<button class="btn btn-sm btn-outline-primary" type="button" data-bs-toggle="collapse" data-bs-target="#rescheduleForm" aria-expanded="false" aria-controls="rescheduleForm">
|
||
Terminverschiebung vorschlagen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<!-- Verschiebungsformular (unverändert) -->
|
||
<div class="collapse" id="rescheduleForm">
|
||
<div class="card card-body bg-light mt-3 mx-auto" style="max-width: 90%;">
|
||
<h5>Anderen Termin vorschlagen</h5>
|
||
<form method="POST">
|
||
<div class="mb-3">
|
||
<label for="new_date" class="form-label">Neuer Termin:</label>
|
||
<input type="datetime-local" class="form-control" id="new_date" name="new_date" value="<?= $row ? date('Y-m-d\TH:i', strtotime($row['meeting_date'])) : '' ?>" required>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label for="reason" class="form-label">Grund/Bemerkung:</label>
|
||
<textarea class="form-control" id="reason" name="reason" rows="2" placeholder="Warum soll der Termin verschoben werden?"></textarea>
|
||
</div>
|
||
<div class="d-flex gap-2">
|
||
<button type="submit" name="propose_reschedule" class="btn btn-sm btn-outline-primary">Vorschlag einreichen</button>
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="collapse" data-bs-target="#rescheduleForm">Abbrechen</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<div class="d-flex justify-content-center pt-2 pb-3" style="max-width: 500px; margin-left: auto; margin-right: auto; flex-direction: column; align-items: center;">
|
||
<?php if ($user_attendance_status === 'accepted'): ?>
|
||
<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>
|
||
|
||
<?php if ($next_payer_username): ?>
|
||
<div class="text-center my-2 mx-auto" style="max-width: 500px; border-radius: 0.5rem;">
|
||
<p class="fw-bold mb-1">Rechnung wird bezahlt von:</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: 500px; margin-left: auto; margin-right: auto;">
|
||
<a href="admin/participant.php?id=<?= htmlspecialchars($row['id']) ?>" class="btn btn-sm btn-outline-secondary">Teilnahme eintragen</a>
|
||
</div>
|
||
|
||
<!-- Teilnehmerübersicht (unverändert) -->
|
||
<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 class="small"><?= $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 class="small"><?= $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 class="small"><?= $user; ?></li>
|
||
<?php endforeach; ?>
|
||
</ul>
|
||
<?php else: ?>
|
||
<p class="mb-0 text-muted small">Keine</p>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Hier kommt dein bestehender Verschiebungs-HTML-Block – unverändert -->
|
||
<!-- (Du kannst ihn aus deinem Originalcode kopieren) -->
|
||
|
||
<?php else: ?>
|
||
<div class="alert alert-warning text-center">Keine anstehenden Termine gefunden.</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
const links = document.querySelectorAll('.participant-toggle-collapse');
|
||
const collapseElements = document.querySelectorAll('.card-footer .collapse');
|
||
links.forEach(link => {
|
||
link.addEventListener('click', function(e) {
|
||
e.preventDefault();
|
||
const isExpanded = collapseElements[0].classList.contains('show');
|
||
collapseElements.forEach(el => isExpanded ? el.classList.remove('show') : el.classList.add('show'));
|
||
links.forEach(l => l.setAttribute('aria-expanded', !isExpanded));
|
||
});
|
||
});
|
||
});
|
||
if ('serviceWorker' in navigator) {
|
||
window.addEventListener('load', () => {
|
||
navigator.serviceWorker.register('/sw.js').catch(console.error);
|
||
});
|
||
}
|
||
</script>
|
||
|
||
<?php include('inc/footer.php'); ?>
|