'CSRF-Fehler', 'got'=>$_POST['csrf_token']??'', 'expected'=>$_SESSION['csrf_token']??'']); exit; } $newStatus = $_POST['status'] ?? ''; $note = trim($_POST['note'] ?? ''); $allowed = ['available', 'busy', 'break', 'offline']; if (!in_array($newStatus, $allowed, true)) { http_response_code(400); echo json_encode(['error' => 'Ungültiger Status']); exit; } $drv = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME); $availabilitySql = $drv === 'sqlite' ? 'INSERT INTO staff_availability (staff_id, status, note, updated_at) VALUES (?,?,?,?) ON CONFLICT(staff_id) DO UPDATE SET status=excluded.status, note=excluded.note, updated_at=excluded.updated_at' : 'INSERT INTO staff_availability (staff_id, status, note, updated_at) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE status=VALUES(status), note=VALUES(note), updated_at=VALUES(updated_at)'; try { $pdo->prepare($availabilitySql)->execute([$staff['id'], $newStatus, $note ?: null, db_now()]); echo json_encode(['ok' => true, 'status' => $newStatus]); } catch (Throwable $e) { error_log('staff_availability: ' . $e->getMessage()); http_response_code(500); echo json_encode(['error' => 'Status konnte nicht gespeichert werden.']); } exit; } // ── Schichtplan (Admin-Seite) ───────────────────────────────────────────────── $admin = $staff['role'] === 'admin' ? $staff : null; if ($_SERVER['REQUEST_METHOD'] === 'POST') { verify_csrf(); $action = $_POST['action'] ?? ''; if ($action === 'save_shifts' && $admin) { $targetId = (int)($_POST['staff_id'] ?? 0); $__nameStmt = $pdo->prepare('SELECT name FROM staff WHERE id = ?'); $__nameStmt->execute([$targetId]); $editAgentName = $__nameStmt->fetchColumn() ?: "#$targetId"; if (!$targetId) { flash('error', 'Ungültiger Mitarbeiter.'); redirect('/staff/availability.php'); } // Alte Schichten löschen $pdo->prepare('DELETE FROM staff_shifts WHERE staff_id = ?')->execute([$targetId]); // Neue speichern $days = $_POST['days'] ?? []; foreach ($days as $day => $times) { if (empty($times['active'])) continue; $start = $times['start'] ?? '08:00'; $end = $times['end'] ?? '17:00'; // Keine Zeitvalidierung – Nutzer ist verantwortlich $pdo->prepare( 'INSERT INTO staff_shifts (staff_id, weekday, start_time, end_time, is_active) VALUES (?,?,?,?,1)' )->execute([$targetId, (int)$day, $start, $end]); } audit_log($admin['id'], "Schichtplan für Mitarbeiter #$targetId gespeichert"); flash('success', 'Schichtplan für ' . e($editAgentName ?? "#$targetId") . ' gespeichert.'); redirect('/staff/availability.php?edit=' . $targetId); } } // ── Daten laden ─────────────────────────────────────────────────────────────── $agents = $pdo->query( "SELECT s.*, sa.status AS avail_status, sa.note AS avail_note, sa.updated_at AS avail_updated FROM staff s LEFT JOIN staff_availability sa ON sa.staff_id = s.id WHERE s.is_active = 1 ORDER BY s.name" )->fetchAll(); // Schichten für alle Mitarbeiter $allShifts = $pdo->query( 'SELECT * FROM staff_shifts WHERE is_active = 1 ORDER BY staff_id, weekday, start_time' )->fetchAll(); $shiftsByStaff = []; foreach ($allShifts as $sh) { $shiftsByStaff[$sh['staff_id']][$sh['weekday']][] = $sh; } // Für den Edit-Modus $editStaffId = (int)($_GET['edit'] ?? 0); $editShifts = $editStaffId ? ($shiftsByStaff[$editStaffId] ?? []) : []; $pageTitle = 'Verfügbarkeit & Schichten'; $activePage = 'availability'; require __DIR__ . '/_header.php'; $statusLabels = [ 'available' => ['Verfügbar', '#22c55e', '🟢'], 'busy' => ['Beschäftigt', '#f59e0b', '🟡'], 'break' => ['Pause', '#6366f1', '🟣'], 'offline' => ['Offline', '#94a3b8', '⚫'], ]; $weekdays = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']; ?>

Verfügbarkeit & Schichten

Mein Status
[$sl, $sc, $se]): ?>
Team-Übersicht
🌴
⚙️

Schichtplan:

Definiere an welchen Tagen und zu welchen Zeiten dieser Mitarbeiter verfügbar ist. Tickets werden außerhalb der Schicht nicht automatisch zugewiesen.

Tag Aktiv Von Bis
onchange="toggleDay(, this.checked)"> required> required>
Abbrechen