Dashboard #79
@@ -252,6 +252,64 @@ require_once __DIR__ . '/env_badge.php';
|
||||
|
||||
<!-- Right side: Clean User Profile & Logout -->
|
||||
<div class="flex items-center space-x-2 sm:space-x-3">
|
||||
<?php if ($currentPage === 'planner.php' && !empty($formattedSelectedDate)): ?>
|
||||
<!-- Header Planner Datum & Status -->
|
||||
<div class="flex items-center gap-1.5 sm:gap-2 mr-1 sm:mr-2">
|
||||
<div class="flex items-center space-x-1.5 text-xs font-bold text-slate-700 dark:text-slate-200 bg-slate-100 dark:bg-slate-800/80 px-2.5 py-1.5 rounded-xl border border-slate-200/80 dark:border-slate-700/60 shadow-2xs">
|
||||
<i data-lucide="calendar" class="w-3.5 h-3.5 text-indigo-500"></i>
|
||||
<span id="headerCurrentDateDisplay"><?= htmlspecialchars($formattedSelectedDate) ?></span>
|
||||
</div>
|
||||
|
||||
<div id="headerDateBadgesContainer" class="hidden sm:flex items-center gap-1.5">
|
||||
<?php if (!empty($isTodaySelected)): ?>
|
||||
<span class="px-2 py-0.5 rounded-full text-[10px] font-extrabold bg-indigo-50 text-indigo-700 dark:bg-indigo-500/15 dark:text-indigo-300 ring-1 ring-indigo-500/30">VANDAAG</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($isSelectedDateWorkday)): ?>
|
||||
<span class="px-2 py-0.5 rounded-full text-[10px] font-bold bg-emerald-50 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300 ring-1 ring-emerald-500/30 flex items-center gap-1" title="Reguliere werkdag">
|
||||
<i data-lucide="briefcase" class="w-3 h-3"></i>
|
||||
<span>Werkdag</span>
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<span class="px-2 py-0.5 rounded-full text-[10px] font-extrabold bg-amber-50 text-amber-700 dark:bg-amber-500/15 dark:text-amber-400 ring-1 ring-amber-500/30 flex items-center gap-1" title="Weekend / Vrije dag">
|
||||
<i data-lucide="coffee" class="w-3 h-3"></i>
|
||||
<span>Weekend / Vrij</span>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($isSelectedDateBlocked)): ?>
|
||||
<span class="px-2 py-0.5 rounded-full text-[10px] font-extrabold bg-amber-100 text-amber-900 dark:bg-amber-950/80 dark:text-amber-300 ring-1 ring-amber-500/30 flex items-center gap-1 cursor-pointer" onclick="openCalendarBlockModal(<?= htmlspecialchars(json_encode($selectedDayBlock), ENT_QUOTES) ?>)" title="<?= htmlspecialchars($selectedDayBlock['title'] ?? '') ?> (klik om te bewerken)">
|
||||
<i data-lucide="palmtree" class="w-3 h-3 text-amber-600 dark:text-amber-400"></i>
|
||||
<span><?= htmlspecialchars($selectedDayBlock['title'] ?? '') ?></span>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Instellingen Dropdown (Widgets, Indeling & Dagen Blokkeren) - alleen op planner.php -->
|
||||
<div class="relative mr-1 sm:mr-2">
|
||||
<button id="plannerSettingsDropdownBtn" onclick="togglePlannerSettingsMenu(event)" class="p-1.5 sm:p-2 rounded-xl text-slate-400 hover:text-slate-700 dark:hover:text-slate-200 hover:bg-slate-100 dark:hover:bg-slate-800/80 transition cursor-pointer border border-transparent hover:border-slate-200 dark:hover:border-slate-700" title="Dashboard Opties & Instellingen">
|
||||
<i data-lucide="settings" class="w-4 sm:w-5 h-4 sm:h-5"></i>
|
||||
</button>
|
||||
<div id="plannerSettingsDropdownMenu" class="hidden absolute right-0 mt-2 w-56 rounded-2xl bg-white dark:bg-[#111624] border border-slate-200 dark:border-slate-800 shadow-xl py-1.5 z-50 text-xs text-slate-700 dark:text-slate-300">
|
||||
<button onclick="closePlannerSettingsMenu(); openWidgetManagerModal();" class="w-full text-left px-3.5 py-2 hover:bg-slate-50 dark:hover:bg-slate-800/70 flex items-center space-x-2.5 transition cursor-pointer">
|
||||
<i data-lucide="layout-grid" class="w-4 h-4 text-indigo-500"></i>
|
||||
<span class="font-medium">Widgets & Indeling</span>
|
||||
</button>
|
||||
<button onclick="closePlannerSettingsMenu(); openCalendarBlockModal();" class="w-full text-left px-3.5 py-2 hover:bg-slate-50 dark:hover:bg-slate-800/70 flex items-center space-x-2.5 transition cursor-pointer">
|
||||
<i data-lucide="palmtree" class="w-4 h-4 text-amber-500"></i>
|
||||
<span class="font-medium">Vakantie / Dagen Blokkeren</span>
|
||||
</button>
|
||||
<?php if (!empty($isOutlookConnected)): ?>
|
||||
<button onclick="closePlannerSettingsMenu(); triggerManualSync();" class="w-full text-left px-3.5 py-2 hover:bg-slate-50 dark:hover:bg-slate-800/70 flex items-center space-x-2.5 transition cursor-pointer border-t border-slate-100 dark:border-slate-800/80">
|
||||
<i data-lucide="refresh-cw" class="w-4 h-4 text-sky-500"></i>
|
||||
<span class="font-medium">Outlook Synchroniseren</span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Profiel link rechtsboven -->
|
||||
<a href="/profile.php" class="flex items-center space-x-2.5 group hover:opacity-90 transition px-2 py-1.5 rounded-xl hover:bg-slate-100 dark:hover:bg-slate-800/60" title="Mijn Profiel & Instellingen">
|
||||
<div class="w-7 h-7 rounded-lg bg-gradient-to-tr from-indigo-600 to-sky-500 p-0.5 flex-shrink-0 shadow-xs overflow-hidden">
|
||||
|
||||
+71
-94
@@ -7,13 +7,8 @@
|
||||
// Controleer of dit een AJAX verzoek is voor een geruisloze datumwisseling
|
||||
$isAjaxRequest = (!empty($_GET['ajax']) && $_GET['ajax'] === '1');
|
||||
|
||||
if ($isAjaxRequest) {
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
$currentUser = require_auth(true);
|
||||
} else {
|
||||
$pageTitle = 'Fociz';
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
}
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
$currentUser = require_auth($isAjaxRequest);
|
||||
|
||||
require_once __DIR__ . '/includes/settings.php';
|
||||
require_once __DIR__ . '/includes/integrations/microsoft.php';
|
||||
@@ -70,7 +65,33 @@ $dutchShortMonths = ['', 'jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug',
|
||||
$formattedSelectedDate = $dutchFullDays[(int)date('N', $selectedTs)] . ' ' . date('j', $selectedTs) . ' ' . $dutchMonths[(int)date('n', $selectedTs)] . ' ' . date('Y', $selectedTs);
|
||||
$formattedWeekRange = date('j', $mondayTs) . ' ' . $dutchShortMonths[(int)date('n', $mondayTs)] . ' – ' . date('j', $sundayTs) . ' ' . $dutchShortMonths[(int)date('n', $sundayTs)] . ' ' . date('Y', $sundayTs);
|
||||
|
||||
// 1. Haal integratiestatussen op
|
||||
// Haal actieve kalenderblokkades (vakanties / verlof / afwezigheid) op vóór header render
|
||||
$allCalendarBlocks = [];
|
||||
$calendarBlocksByDate = [];
|
||||
try {
|
||||
$stmtBlocks = $db->prepare("
|
||||
SELECT * FROM calendar_blocks
|
||||
WHERE user_id = ? AND start_date <= ? AND end_date >= ?
|
||||
ORDER BY start_date ASC
|
||||
");
|
||||
$stmtBlocks->execute([$userId, date('Y-m-d', strtotime('+35 days', $sundayTs)), date('Y-m-d', strtotime('-14 days', $mondayTs))]);
|
||||
$allCalendarBlocks = $stmtBlocks->fetchAll() ?: [];
|
||||
foreach ($allCalendarBlocks as $cb) {
|
||||
$cbStart = strtotime($cb['start_date']);
|
||||
$cbEnd = strtotime($cb['end_date']);
|
||||
for ($d = $cbStart; $d <= $cbEnd; $d += 86400) {
|
||||
$dStr = date('Y-m-d', $d);
|
||||
$calendarBlocksByDate[$dStr][] = $cb;
|
||||
}
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
error_log("Fout bij ophalen calendar_blocks in planner: " . $e->getMessage());
|
||||
}
|
||||
|
||||
$selectedDayBlock = $calendarBlocksByDate[$selectedDate][0] ?? null;
|
||||
$isSelectedDateBlocked = !empty($selectedDayBlock);
|
||||
|
||||
// 1. Haal integratiestatussen op vóór header render
|
||||
$userIntegrations = [];
|
||||
try {
|
||||
$stmtInt = $db->prepare("SELECT * FROM integrations WHERE user_id = ?");
|
||||
@@ -87,6 +108,11 @@ $isOutlookConnected = !empty($userIntegrations['OUTLOOK']['access_token']) && em
|
||||
$outlookIntegrationSettings = json_decode($userIntegrations['OUTLOOK']['settings'] ?? '{}', true) ?: [];
|
||||
$syncIntervalSeconds = isset($outlookIntegrationSettings['sync_interval_seconds']) ? (int)$outlookIntegrationSettings['sync_interval_seconds'] : 30;
|
||||
|
||||
if (!$isAjaxRequest) {
|
||||
$pageTitle = 'Fociz';
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
}
|
||||
|
||||
$weekOutlookEvents = [];
|
||||
$isLiveOutlook = false;
|
||||
|
||||
@@ -247,32 +273,6 @@ foreach ($weekOutlookEvents as $evt) {
|
||||
$outlookEventsByDate[$evtDate][] = $evt;
|
||||
}
|
||||
|
||||
// 4b. Haal actieve kalenderblokkades (vakanties / verlof / afwezigheid) op
|
||||
$allCalendarBlocks = [];
|
||||
$calendarBlocksByDate = [];
|
||||
try {
|
||||
$stmtBlocks = $db->prepare("
|
||||
SELECT * FROM calendar_blocks
|
||||
WHERE user_id = ? AND start_date <= ? AND end_date >= ?
|
||||
ORDER BY start_date ASC
|
||||
");
|
||||
$stmtBlocks->execute([$userId, date('Y-m-d', strtotime('+35 days', $sundayTs)), date('Y-m-d', strtotime('-14 days', $mondayTs))]);
|
||||
$allCalendarBlocks = $stmtBlocks->fetchAll() ?: [];
|
||||
foreach ($allCalendarBlocks as $cb) {
|
||||
$cbStart = strtotime($cb['start_date']);
|
||||
$cbEnd = strtotime($cb['end_date']);
|
||||
for ($d = $cbStart; $d <= $cbEnd; $d += 86400) {
|
||||
$dStr = date('Y-m-d', $d);
|
||||
$calendarBlocksByDate[$dStr][] = $cb;
|
||||
}
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
error_log("Fout bij ophalen calendar_blocks in planner: " . $e->getMessage());
|
||||
}
|
||||
|
||||
$selectedDayBlock = $calendarBlocksByDate[$selectedDate][0] ?? null;
|
||||
$isSelectedDateBlocked = !empty($selectedDayBlock);
|
||||
|
||||
// 7 Dagen van de week samenstellen voor de weekselector
|
||||
$weekDays = [];
|
||||
for ($i = 0; $i < 7; $i++) {
|
||||
@@ -495,67 +495,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
|
||||
<?php else: ?>
|
||||
<?php ob_start(); ?>
|
||||
<?php endif; ?>
|
||||
<!-- Top Banner: Datum, Hoofddoel & Integraties Status -->
|
||||
<div class="fociz-card p-6 sm:p-7 relative overflow-hidden">
|
||||
<div class="flex flex-col lg:flex-row lg:items-center justify-between gap-4">
|
||||
<div>
|
||||
<div class="flex flex-wrap items-center gap-2 text-indigo-600 dark:text-indigo-400 text-xs font-bold uppercase tracking-wider mb-1">
|
||||
<div class="flex items-center space-x-1.5">
|
||||
<i data-lucide="calendar" class="w-4 h-4"></i>
|
||||
<span><?= htmlspecialchars($formattedSelectedDate) ?></span>
|
||||
</div>
|
||||
<?php if ($isTodaySelected): ?>
|
||||
<span class="px-2.5 py-0.5 rounded-full text-[10px] font-extrabold bg-indigo-50 text-indigo-700 dark:bg-indigo-500/15 dark:text-indigo-300 ring-1 ring-indigo-500/30">VANDAAG</span>
|
||||
<?php else: ?>
|
||||
<span class="px-2.5 py-0.5 rounded-full text-[10px] font-bold bg-slate-100 dark:bg-slate-800/80 text-slate-600 dark:text-slate-400">GEKOZEN DAG</span>
|
||||
<?php endif; ?>
|
||||
<?php if ($isSelectedDateWorkday): ?>
|
||||
<span class="px-2 py-0.5 rounded-full text-[10px] font-bold bg-emerald-50 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300 ring-1 ring-emerald-500/30 flex items-center gap-1" title="Reguliere werkdag conform beheerinstellingen">
|
||||
<i data-lucide="briefcase" class="w-3 h-3"></i>
|
||||
<span>Werkdag</span>
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<span class="px-2 py-0.5 rounded-full text-[10px] font-extrabold bg-amber-50 text-amber-700 dark:bg-amber-500/15 dark:text-amber-400 ring-1 ring-amber-500/30 flex items-center gap-1" title="Weekend / Vrije dag conform beheerinstellingen">
|
||||
<i data-lucide="coffee" class="w-3 h-3"></i>
|
||||
<span>Weekend / Vrij</span>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
<?php if ($isSelectedDateBlocked): ?>
|
||||
<span class="px-2.5 py-0.5 rounded-full text-[10px] font-extrabold bg-amber-100 text-amber-900 dark:bg-amber-950/80 dark:text-amber-300 ring-1 ring-amber-500/30 flex items-center gap-1 cursor-pointer" onclick="openCalendarBlockModal(<?= htmlspecialchars(json_encode($selectedDayBlock), ENT_QUOTES) ?>)" title="<?= htmlspecialchars($selectedDayBlock['title']) ?> (klik om te bewerken)">
|
||||
<i data-lucide="palmtree" class="w-3 h-3 text-amber-600 dark:text-amber-400"></i>
|
||||
<span><?= htmlspecialchars($selectedDayBlock['title']) ?></span>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<h1 class="text-2xl sm:text-3xl font-black tracking-tight text-slate-900 dark:text-white">
|
||||
Fociz
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<!-- Instellingen Dropdown (Widgets, Indeling & Dagen Blokkeren) -->
|
||||
<div class="relative">
|
||||
<button id="plannerSettingsDropdownBtn" onclick="togglePlannerSettingsMenu(event)" class="p-2 rounded-xl text-slate-400 hover:text-slate-700 dark:hover:text-slate-200 hover:bg-slate-100 dark:hover:bg-slate-800/80 transition cursor-pointer border border-transparent hover:border-slate-200 dark:hover:border-slate-700" title="Dashboard Opties & Instellingen">
|
||||
<i data-lucide="settings" class="w-5 h-5"></i>
|
||||
</button>
|
||||
<div id="plannerSettingsDropdownMenu" class="hidden absolute right-0 mt-2 w-56 rounded-2xl bg-white dark:bg-[#111624] border border-slate-200 dark:border-slate-800 shadow-xl py-1.5 z-50 text-xs text-slate-700 dark:text-slate-300">
|
||||
<button onclick="closePlannerSettingsMenu(); openWidgetManagerModal();" class="w-full text-left px-3.5 py-2 hover:bg-slate-50 dark:hover:bg-slate-800/70 flex items-center space-x-2.5 transition cursor-pointer">
|
||||
<i data-lucide="layout-grid" class="w-4 h-4 text-indigo-500"></i>
|
||||
<span class="font-medium">Widgets & Indeling</span>
|
||||
</button>
|
||||
<button onclick="closePlannerSettingsMenu(); openCalendarBlockModal();" class="w-full text-left px-3.5 py-2 hover:bg-slate-50 dark:hover:bg-slate-800/70 flex items-center space-x-2.5 transition cursor-pointer">
|
||||
<i data-lucide="palmtree" class="w-4 h-4 text-amber-500"></i>
|
||||
<span class="font-medium">Vakantie / Dagen Blokkeren</span>
|
||||
</button>
|
||||
<?php if ($isOutlookConnected): ?>
|
||||
<button onclick="closePlannerSettingsMenu(); triggerManualSync();" class="w-full text-left px-3.5 py-2 hover:bg-slate-50 dark:hover:bg-slate-800/70 flex items-center space-x-2.5 transition cursor-pointer border-t border-slate-100 dark:border-slate-800/80">
|
||||
<i data-lucide="refresh-cw" class="w-4 h-4 text-sky-500"></i>
|
||||
<span class="font-medium">Outlook Synchroniseren</span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AI Dagbriefing Banner (async geladen, alleen vandaag) -->
|
||||
<?php if ($isTodaySelected): ?>
|
||||
@@ -1965,6 +1905,10 @@ if ($isAjaxRequest) {
|
||||
'success' => true,
|
||||
'selectedDate' => $selectedDate,
|
||||
'formattedDate' => $formattedSelectedDate,
|
||||
'isToday' => (bool)$isTodaySelected,
|
||||
'isWorkday' => (bool)$isSelectedDateWorkday,
|
||||
'isBlocked' => (bool)$isSelectedDateBlocked,
|
||||
'selectedDayBlock'=> $selectedDayBlock ?? null,
|
||||
'weekStart' => $weekStart,
|
||||
'weekEnd' => $weekEnd,
|
||||
'weekNumber' => $weekNumber,
|
||||
@@ -6230,6 +6174,39 @@ async function switchPlannerDate(newDate, event = null, pushState = true) {
|
||||
document.title = data.title;
|
||||
}
|
||||
|
||||
// Werk datum & badges in top header bij
|
||||
const headerDateEl = document.getElementById('headerCurrentDateDisplay');
|
||||
if (headerDateEl && data.formattedDate) {
|
||||
headerDateEl.textContent = data.formattedDate;
|
||||
}
|
||||
const headerBadgesEl = document.getElementById('headerDateBadgesContainer');
|
||||
if (headerBadgesEl) {
|
||||
let badgesHtml = '';
|
||||
if (data.isToday) {
|
||||
badgesHtml += `<span class="px-2 py-0.5 rounded-full text-[10px] font-extrabold bg-indigo-50 text-indigo-700 dark:bg-indigo-500/15 dark:text-indigo-300 ring-1 ring-indigo-500/30">VANDAAG</span>`;
|
||||
}
|
||||
if (data.isWorkday) {
|
||||
badgesHtml += `<span class="px-2 py-0.5 rounded-full text-[10px] font-bold bg-emerald-50 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300 ring-1 ring-emerald-500/30 flex items-center gap-1" title="Reguliere werkdag">
|
||||
<i data-lucide="briefcase" class="w-3 h-3"></i>
|
||||
<span>Werkdag</span>
|
||||
</span>`;
|
||||
} else {
|
||||
badgesHtml += `<span class="px-2 py-0.5 rounded-full text-[10px] font-extrabold bg-amber-50 text-amber-700 dark:bg-amber-500/15 dark:text-amber-400 ring-1 ring-amber-500/30 flex items-center gap-1" title="Weekend / Vrije dag">
|
||||
<i data-lucide="coffee" class="w-3 h-3"></i>
|
||||
<span>Weekend / Vrij</span>
|
||||
</span>`;
|
||||
}
|
||||
if (data.isBlocked && data.selectedDayBlock) {
|
||||
const blockJson = JSON.stringify(data.selectedDayBlock).replace(/"/g, '"');
|
||||
const blockTitle = (data.selectedDayBlock.title || '').replace(/</g, '<').replace(/>/g, '>');
|
||||
badgesHtml += `<span class="px-2 py-0.5 rounded-full text-[10px] font-extrabold bg-amber-100 text-amber-900 dark:bg-amber-950/80 dark:text-amber-300 ring-1 ring-amber-500/30 flex items-center gap-1 cursor-pointer" onclick='openCalendarBlockModal(${blockJson})' title="${blockTitle} (klik om te bewerken)">
|
||||
<i data-lucide="palmtree" class="w-3 h-3 text-amber-600 dark:text-amber-400"></i>
|
||||
<span>${blockTitle}</span>
|
||||
</span>`;
|
||||
}
|
||||
headerBadgesEl.innerHTML = badgesHtml;
|
||||
}
|
||||
|
||||
// Werk URL bij in adresbalk zonder paginaherlaad
|
||||
if (pushState && window.history && window.history.pushState) {
|
||||
const todayStr = '<?= $today ?>';
|
||||
|
||||
Reference in New Issue
Block a user