Planner wijzigingen
This commit is contained in:
+202
-160
@@ -994,13 +994,8 @@ for ($h = $startHour; $h <= $endHour; $h++) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Rechterkant: Dagen Blokkeren, AI Slim Indelen & Directe datumselector -->
|
||||
<!-- Rechterkant: AI Slim Indelen & Directe datumselector -->
|
||||
<div class="flex flex-wrap items-center gap-2 justify-end">
|
||||
<button type="button" onclick="openCalendarBlockModal()" title="Hele of meerdere dagen blokkeren voor vakantie, verlof of afwezigheid" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-amber-50 hover:bg-amber-100 dark:bg-amber-950/40 dark:hover:bg-amber-900/50 text-amber-800 dark:text-amber-300 border border-amber-200 dark:border-amber-800/60 text-xs font-semibold shadow-2xs transition cursor-pointer">
|
||||
<i data-lucide="palmtree" class="w-3.5 h-3.5 text-amber-600 dark:text-amber-400"></i>
|
||||
<span class="hidden sm:inline">Dagen Blokkeren</span>
|
||||
</button>
|
||||
|
||||
<?php if ($aiSettings['ai_enabled'] && $aiSettings['has_key']): ?>
|
||||
<button onclick="aiSmartSchedule(this)" id="aiScheduleBtn" title="Laat AI Co-Pilot openstaande taken optimaal inplannen om meetings en lunch heen" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-gradient-to-r from-indigo-600 to-sky-600 hover:from-indigo-500 hover:to-sky-500 text-white text-xs font-semibold shadow-xs transition cursor-pointer">
|
||||
<i data-lucide="sparkles" class="w-3.5 h-3.5"></i>
|
||||
@@ -1022,32 +1017,38 @@ for ($h = $startHour; $h <= $endHour; $h++) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2. 7 Dagen Weekstrook (Dagselector) -->
|
||||
<!-- 2. 7 Dagen Weekstrook (Dagselector met Rechtermuisknop Blokkade Opties) -->
|
||||
<div class="grid grid-cols-2 sm:grid-cols-4 md:grid-cols-7 gap-2.5">
|
||||
<?php foreach ($weekDays as $wd): ?>
|
||||
<a
|
||||
href="<?= ($wd['date'] === $today) ? 'planner.php' : ('planner.php?date=' . $wd['date']) ?>"
|
||||
onclick="switchPlannerDate('<?= $wd['date'] ?>', event); return false;"
|
||||
class="fociz-card-interactive group relative flex flex-col p-3 rounded-xl border transition-all text-left <?= $wd['is_selected']
|
||||
? 'bg-gradient-to-b from-indigo-500/15 via-indigo-500/5 to-transparent dark:from-indigo-500/25 dark:via-indigo-500/10 dark:to-transparent border-indigo-500 ring-2 ring-indigo-500/40 shadow-sm'
|
||||
: ($wd['is_blocked']
|
||||
? 'bg-amber-50/70 dark:bg-amber-950/20 border-amber-300/80 dark:border-amber-800/60 hover:border-amber-400 shadow-2xs'
|
||||
oncontextmenu="openDayContextMenu(event, '<?= $wd['date'] ?>', <?= $wd['is_blocked'] ? (int)$wd['block_info']['id'] : 0 ?>, '<?= $wd['is_blocked'] ? addslashes(htmlspecialchars($wd['block_info']['title'], ENT_QUOTES)) : '' ?>'); return false;"
|
||||
data-date="<?= $wd['date'] ?>"
|
||||
data-blocked="<?= $wd['is_blocked'] ? '1' : '0' ?>"
|
||||
class="fociz-card-interactive group relative flex flex-col p-3 rounded-xl border transition-all text-left <?= $wd['is_blocked']
|
||||
? ($wd['is_selected']
|
||||
? 'bg-amber-100/90 dark:bg-amber-950/60 border-amber-400 dark:border-amber-600 ring-2 ring-amber-400/50 shadow-sm'
|
||||
: 'bg-amber-50/80 dark:bg-amber-950/30 border-amber-300/80 dark:border-amber-800/70 hover:border-amber-400 dark:hover:border-amber-600 shadow-2xs')
|
||||
: ($wd['is_selected']
|
||||
? 'bg-gradient-to-b from-indigo-500/15 via-indigo-500/5 to-transparent dark:from-indigo-500/25 dark:via-indigo-500/10 dark:to-transparent border-indigo-500 ring-2 ring-indigo-500/40 shadow-sm'
|
||||
: ($wd['is_workday']
|
||||
? 'bg-slate-50/70 dark:bg-[#0c0f17]/50 border-slate-200/80 dark:border-slate-800/80 hover:border-indigo-300 dark:hover:border-indigo-600/50 hover:bg-white dark:hover:bg-[#111624] shadow-2xs'
|
||||
: 'bg-slate-100/60 dark:bg-[#080b11]/60 border-dashed border-amber-300/60 dark:border-amber-900/40 hover:border-amber-400 dark:hover:border-amber-700 hover:bg-white dark:hover:bg-[#0f141f] shadow-2xs')) ?>"
|
||||
: 'bg-slate-100/60 dark:bg-[#080b11]/60 border-dashed border-slate-200/80 dark:border-slate-800/80 hover:border-slate-300 dark:hover:border-slate-700 hover:bg-white dark:hover:bg-[#0f141f] shadow-2xs')) ?>"
|
||||
title="<?= $wd['is_blocked'] ? ('Geblokkeerd: ' . htmlspecialchars($wd['block_info']['title']) . ' • Rechtermuisknop voor opties') : 'Klik om te selecteren • Rechtermuisknop om dag te blokkeren' ?>"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<span class="text-[10px] font-bold uppercase tracking-wider <?= $wd['is_selected'] ? 'text-indigo-600 dark:text-indigo-400' : ($wd['is_workday'] ? 'text-slate-500 dark:text-slate-400' : 'text-slate-400 dark:text-slate-500') ?>">
|
||||
<span class="text-[10px] font-bold uppercase tracking-wider <?= $wd['is_blocked'] ? 'text-amber-800 dark:text-amber-300' : ($wd['is_selected'] ? 'text-indigo-600 dark:text-indigo-400' : ($wd['is_workday'] ? 'text-slate-500 dark:text-slate-400' : 'text-slate-400 dark:text-slate-500')) ?>">
|
||||
<?= $wd['short_name'] ?>
|
||||
</span>
|
||||
<div class="flex items-center gap-1">
|
||||
<?php if ($wd['is_blocked']): ?>
|
||||
<span class="px-1.5 py-0.5 rounded text-[8px] font-extrabold uppercase bg-amber-200/90 dark:bg-amber-900/80 text-amber-950 dark:text-amber-200 border border-amber-300 dark:border-amber-700/80 flex items-center gap-0.5" title="<?= htmlspecialchars($wd['block_info']['title']) ?>">
|
||||
<i data-lucide="palmtree" class="w-2.5 h-2.5"></i>
|
||||
<span><?= htmlspecialchars(mb_strimwidth($wd['block_info']['title'], 0, 7, '..')) ?></span>
|
||||
<span class="px-2 py-0.5 rounded-md text-[9px] font-bold uppercase bg-amber-200/90 dark:bg-amber-900/80 text-amber-950 dark:text-amber-200 border border-amber-300 dark:border-amber-700/80 inline-flex items-center gap-1 leading-none shadow-2xs" title="<?= htmlspecialchars($wd['block_info']['title']) ?>">
|
||||
<i data-lucide="palmtree" class="w-2.5 h-2.5 flex-shrink-0"></i>
|
||||
<span class="max-w-[80px] truncate"><?= htmlspecialchars($wd['block_info']['title']) ?></span>
|
||||
</span>
|
||||
<?php elseif ($wd['is_weekend']): ?>
|
||||
<span class="px-1.5 py-0.5 rounded text-[8px] font-extrabold uppercase bg-amber-50 dark:bg-amber-950/60 text-amber-700 dark:text-amber-400 border border-amber-200/80 dark:border-amber-800/60" title="Weekend / Niet-werkdag conform beheerinstellingen">
|
||||
<span class="px-1.5 py-0.5 rounded text-[8px] font-extrabold uppercase bg-slate-200/60 dark:bg-slate-800 text-slate-500 dark:text-slate-400 border border-slate-300/60 dark:border-slate-700/60">
|
||||
Weekend
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
@@ -1094,40 +1095,16 @@ for ($h = $startHour; $h <= $endHour; $h++) {
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($isSelectedDateBlocked): ?>
|
||||
<!-- Prominente Vakantie / Blokkade Banner -->
|
||||
<div class="p-4 sm:p-5 rounded-2xl bg-gradient-to-r from-amber-50 via-amber-100/60 to-orange-50 dark:from-amber-950/40 dark:via-[#1a1408] dark:to-orange-950/30 border-2 border-amber-300/90 dark:border-amber-700/70 flex flex-col sm:flex-row sm:items-center justify-between gap-4 shadow-sm">
|
||||
<div class="flex items-start sm:items-center space-x-3.5">
|
||||
<div class="w-11 h-11 rounded-2xl bg-amber-200 dark:bg-amber-900/80 text-amber-900 dark:text-amber-200 flex items-center justify-center font-bold text-xl flex-shrink-0 shadow-xs ring-2 ring-amber-300 dark:ring-amber-700/80">
|
||||
🏖️
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center space-x-2 flex-wrap gap-y-1">
|
||||
<h4 class="text-sm sm:text-base font-black text-amber-950 dark:text-amber-200">
|
||||
<?= htmlspecialchars($selectedDayBlock['title']) ?>
|
||||
</h4>
|
||||
<span class="px-2.5 py-0.5 rounded-full text-[10px] font-extrabold bg-amber-200/90 text-amber-950 dark:bg-amber-800/80 dark:text-amber-100 uppercase tracking-wider border border-amber-300 dark:border-amber-700">
|
||||
<?= htmlspecialchars($selectedDayBlock['block_type']) ?>
|
||||
</span>
|
||||
</div>
|
||||
<p class="text-xs text-amber-900/80 dark:text-amber-300/80 mt-1">
|
||||
Geblokkeerd van <strong><?= date('j M Y', strtotime($selectedDayBlock['start_date'])) ?></strong> t/m <strong><?= date('j M Y', strtotime($selectedDayBlock['end_date'])) ?></strong>
|
||||
<?php if (!empty($selectedDayBlock['notes'])): ?>
|
||||
• <?= htmlspecialchars($selectedDayBlock['notes']) ?>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2 self-end sm:self-auto flex-shrink-0">
|
||||
<button onclick="openCalendarBlockModal(<?= htmlspecialchars(json_encode($selectedDayBlock), ENT_QUOTES) ?>)" class="px-3.5 py-1.5 rounded-xl bg-white dark:bg-slate-900 text-slate-800 dark:text-slate-200 text-xs font-bold hover:bg-amber-50 dark:hover:bg-slate-800 border border-amber-300/80 dark:border-amber-700 transition shadow-2xs cursor-pointer">
|
||||
Bewerken
|
||||
</button>
|
||||
<button onclick="deleteCalendarBlock(<?= (int)$selectedDayBlock['id'] ?>)" class="px-3.5 py-1.5 rounded-xl bg-rose-50 hover:bg-rose-100 dark:bg-rose-950/50 dark:hover:bg-rose-900/60 text-rose-700 dark:text-rose-300 text-xs font-bold border border-rose-200 dark:border-rose-800/60 transition shadow-2xs cursor-pointer">
|
||||
Opheffen
|
||||
</button>
|
||||
</div>
|
||||
<!-- Contextmenu voor Rechtermuisklik op een dag -->
|
||||
<div id="dayContextMenu" class="fixed z-[9999] hidden min-w-[220px] bg-white dark:bg-[#111624] border border-slate-200 dark:border-slate-800 rounded-2xl shadow-xl py-1 text-xs text-slate-800 dark:text-slate-200 select-none animate-in fade-in zoom-in-95 duration-75">
|
||||
<div class="px-3 py-1.5 text-[10px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-wider border-b border-slate-100 dark:border-slate-800/80 flex items-center justify-between">
|
||||
<span id="dayContextMenuDateLabel">Dag</span>
|
||||
<span id="dayContextMenuStatusBadge"></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div id="dayContextMenuActions" class="p-1 space-y-0.5">
|
||||
<!-- Acties worden via JS ingevuld -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3. Sub-header van de Tijdlijn voor de geselecteerde dag -->
|
||||
<div class="flex items-center justify-between pt-3 border-t border-slate-100 dark:border-slate-800/80">
|
||||
@@ -2435,30 +2412,17 @@ if ($isAjaxRequest) {
|
||||
|
||||
<div>
|
||||
<label class="block text-xs font-bold text-slate-700 dark:text-slate-300 mb-1">Type Blokkade</label>
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
<button type="button" onclick="updateCalBlockDefaultTitle('VACATION')" id="calType_VACATION" class="cal-block-type-btn p-2 rounded-xl border text-center transition cursor-pointer flex flex-col items-center">
|
||||
<span class="text-base mb-0.5">🏖️</span>
|
||||
<span class="text-[10px] font-bold">Vakantie</span>
|
||||
</button>
|
||||
<button type="button" onclick="updateCalBlockDefaultTitle('LEAVE')" id="calType_LEAVE" class="cal-block-type-btn p-2 rounded-xl border text-center transition cursor-pointer flex flex-col items-center">
|
||||
<span class="text-base mb-0.5">✈️</span>
|
||||
<span class="text-[10px] font-bold">Verlof / ADV</span>
|
||||
</button>
|
||||
<button type="button" onclick="updateCalBlockDefaultTitle('SICK')" id="calType_SICK" class="cal-block-type-btn p-2 rounded-xl border text-center transition cursor-pointer flex flex-col items-center">
|
||||
<span class="text-base mb-0.5">🤒</span>
|
||||
<span class="text-[10px] font-bold">Ziekte</span>
|
||||
</button>
|
||||
<button type="button" onclick="updateCalBlockDefaultTitle('FOCUS')" id="calType_FOCUS" class="cal-block-type-btn p-2 rounded-xl border text-center transition cursor-pointer flex flex-col items-center">
|
||||
<span class="text-base mb-0.5">🎯</span>
|
||||
<span class="text-[10px] font-bold">Focusdag</span>
|
||||
</button>
|
||||
</div>
|
||||
<input type="hidden" id="calBlockType" value="VACATION">
|
||||
<select id="calBlockType" onchange="updateCalBlockDefaultTitle(this.value)" class="w-full px-3 py-2 rounded-xl bg-slate-50 dark:bg-slate-800/80 border border-slate-200 dark:border-slate-700 text-xs font-medium text-slate-900 dark:text-white focus:outline-hidden focus:ring-2 focus:ring-amber-500">
|
||||
<option value="VACATION">Vakantie</option>
|
||||
<option value="LEAVE">Verlof / ADV / Vrije dag</option>
|
||||
<option value="SICK">Ziekte / Afwezig</option>
|
||||
<option value="FOCUS">Focusdag</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-xs font-bold text-slate-700 dark:text-slate-300 mb-1">Titel / Omschrijving <span class="text-rose-500">*</span></label>
|
||||
<input type="text" id="calBlockTitle" required placeholder="Bijv. Zomervakantie, ADV dag, Verlof..." class="w-full px-3 py-2 rounded-xl bg-slate-50 dark:bg-slate-800/80 border border-slate-200 dark:border-slate-700 text-xs font-medium text-slate-900 dark:text-white placeholder-slate-400 focus:outline-hidden focus:ring-2 focus:ring-amber-500">
|
||||
<input type="text" id="calBlockTitle" required placeholder="Bijv. Vakantie, Vrije dag, Verlof..." class="w-full px-3 py-2 rounded-xl bg-slate-50 dark:bg-slate-800/80 border border-slate-200 dark:border-slate-700 text-xs font-medium text-slate-900 dark:text-white placeholder-slate-400 focus:outline-hidden focus:ring-2 focus:ring-amber-500">
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
@@ -2493,20 +2457,6 @@ if ($isAjaxRequest) {
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Overzicht actieve / geplande blokkades -->
|
||||
<div class="pt-2 border-t border-slate-100 dark:border-slate-800">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="text-[11px] font-bold text-slate-600 dark:text-slate-400 uppercase tracking-wider">Actieve & Toekomstige Blokkades</span>
|
||||
<button type="button" onclick="loadCalendarBlocksList()" class="text-[10px] text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 font-semibold cursor-pointer flex items-center space-x-1">
|
||||
<i data-lucide="refresh-cw" class="w-2.5 h-2.5"></i>
|
||||
<span>Vernieuwen</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="calendarBlocksListContainer" class="space-y-1.5 max-h-36 overflow-y-auto pr-1">
|
||||
<div class="text-[11px] text-slate-400 text-center py-2">Laden...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Knoppen balk -->
|
||||
<div class="flex items-center justify-between pt-3 border-t border-slate-100 dark:border-slate-800/80 flex-shrink-0">
|
||||
<button type="button" id="btnDeleteCurrentCalBlock" onclick="deleteCurrentCalendarBlock()" class="hidden px-3 py-2 rounded-xl bg-rose-50 hover:bg-rose-100 dark:bg-rose-950/50 dark:hover:bg-rose-900/60 text-rose-700 dark:text-rose-300 text-xs font-bold border border-rose-200 dark:border-rose-800/60 transition cursor-pointer items-center space-x-1">
|
||||
@@ -2801,7 +2751,7 @@ function showWidgetToast(htmlMessage, type = 'success', duration = 3500) {
|
||||
}, duration);
|
||||
}
|
||||
|
||||
// --- Agenda Dagen Blokkeren (Vakantie / Verlof / Focus) ---
|
||||
// --- Agenda Dagen Blokkeren & Rechtermuisklik Context Menu ---
|
||||
const CAL_BLOCK_DEFAULT_TITLES = {
|
||||
'VACATION': 'Vakantie',
|
||||
'LEAVE': 'Verlof',
|
||||
@@ -2812,31 +2762,182 @@ const CAL_BLOCK_DEFAULT_TITLES = {
|
||||
function selectCalBlockType(type) {
|
||||
const input = document.getElementById('calBlockType');
|
||||
if (input) input.value = type;
|
||||
|
||||
const types = ['VACATION', 'LEAVE', 'SICK', 'FOCUS'];
|
||||
types.forEach(t => {
|
||||
const btn = document.getElementById(`calType_${t}`);
|
||||
if (!btn) return;
|
||||
if (t === type) {
|
||||
btn.className = 'cal-block-type-btn p-2 rounded-xl border border-amber-500 bg-amber-100 dark:bg-amber-950/80 text-amber-950 dark:text-amber-200 font-bold shadow-xs text-center transition cursor-pointer flex flex-col items-center ring-2 ring-amber-500/20';
|
||||
} else {
|
||||
btn.className = 'cal-block-type-btn p-2 rounded-xl border border-slate-200 dark:border-slate-700/80 bg-slate-50 dark:bg-slate-800/60 text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 text-center transition cursor-pointer flex flex-col items-center';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateCalBlockDefaultTitle(type) {
|
||||
const titleInput = document.getElementById('calBlockTitle');
|
||||
const currentVal = titleInput ? titleInput.value.trim() : '';
|
||||
const oldType = document.getElementById('calBlockType')?.value;
|
||||
|
||||
selectCalBlockType(type);
|
||||
|
||||
if (titleInput && (!currentVal || currentVal === (CAL_BLOCK_DEFAULT_TITLES[oldType] || ''))) {
|
||||
if (titleInput && (!currentVal || Object.values(CAL_BLOCK_DEFAULT_TITLES).includes(currentVal))) {
|
||||
titleInput.value = CAL_BLOCK_DEFAULT_TITLES[type] || '';
|
||||
}
|
||||
}
|
||||
|
||||
// --- Rechtermuisklik Context Menu voor Dagen ---
|
||||
let activeContextMenuDay = null;
|
||||
|
||||
function openDayContextMenu(e, dateStr, blockId = 0, blockTitle = '') {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
activeContextMenuDay = {
|
||||
date: dateStr,
|
||||
blockId: blockId,
|
||||
title: blockTitle
|
||||
};
|
||||
|
||||
const menu = document.getElementById('dayContextMenu');
|
||||
const label = document.getElementById('dayContextMenuDateLabel');
|
||||
const statusBadge = document.getElementById('dayContextMenuStatusBadge');
|
||||
const actions = document.getElementById('dayContextMenuActions');
|
||||
|
||||
if (!menu || !label || !actions) return;
|
||||
|
||||
// Nederlandse dag en maand formatteren
|
||||
const dParts = dateStr.split('-');
|
||||
const dObj = new Date(parseInt(dParts[0], 10), parseInt(dParts[1], 10) - 1, parseInt(dParts[2], 10));
|
||||
const dayNames = ['Zondag', 'Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrijdag', 'Zaterdag'];
|
||||
const monthNames = ['jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'];
|
||||
const formatted = `${dayNames[dObj.getDay()]} ${dObj.getDate()} ${monthNames[dObj.getMonth()]}`;
|
||||
|
||||
label.textContent = formatted;
|
||||
|
||||
if (blockId > 0) {
|
||||
statusBadge.innerHTML = `<span class="px-1.5 py-0.5 rounded text-[9px] font-bold bg-amber-100 dark:bg-amber-950 text-amber-800 dark:text-amber-300 border border-amber-300/80 dark:border-amber-700/80">${escapeHtml(blockTitle || 'Geblokkeerd')}</span>`;
|
||||
|
||||
actions.innerHTML = `
|
||||
<button type="button" onclick="quickUnblockDay(${blockId})" class="w-full flex items-center space-x-2 px-3 py-2 rounded-xl text-left text-rose-600 dark:text-rose-400 hover:bg-rose-50 dark:hover:bg-rose-950/40 transition cursor-pointer font-medium">
|
||||
<i data-lucide="trash-2" class="w-3.5 h-3.5 flex-shrink-0 text-rose-500"></i>
|
||||
<span>Blokkade opheffen</span>
|
||||
</button>
|
||||
<button type="button" onclick="closeDayContextMenu(); openCalendarBlockModal({id: ${blockId}, start_date: '${dateStr}', end_date: '${dateStr}', title: '${escapeHtml(blockTitle)}'}, '${dateStr}')" class="w-full flex items-center space-x-2 px-3 py-2 rounded-xl text-left hover:bg-slate-100 dark:hover:bg-slate-800/80 text-slate-700 dark:text-slate-300 transition cursor-pointer font-medium">
|
||||
<i data-lucide="calendar" class="w-3.5 h-3.5 flex-shrink-0 text-slate-400"></i>
|
||||
<span>Periode aanpassen...</span>
|
||||
</button>
|
||||
`;
|
||||
} else {
|
||||
statusBadge.innerHTML = `<span class="text-[9px] font-normal text-slate-400">Beschikbaar</span>`;
|
||||
|
||||
actions.innerHTML = `
|
||||
<button type="button" onclick="quickBlockDay('${dateStr}', 'Vakantie', 'VACATION')" class="w-full flex items-center space-x-2 px-3 py-2 rounded-xl text-left hover:bg-amber-50 dark:hover:bg-amber-950/50 text-slate-800 dark:text-slate-200 transition cursor-pointer font-medium">
|
||||
<span class="text-sm leading-none">🏖️</span>
|
||||
<span>Hele dag: Vakantie</span>
|
||||
</button>
|
||||
<button type="button" onclick="quickBlockDay('${dateStr}', 'Verlof', 'LEAVE')" class="w-full flex items-center space-x-2 px-3 py-2 rounded-xl text-left hover:bg-amber-50 dark:hover:bg-amber-950/50 text-slate-800 dark:text-slate-200 transition cursor-pointer font-medium">
|
||||
<span class="text-sm leading-none">✈️</span>
|
||||
<span>Hele dag: Verlof / Vrij</span>
|
||||
</button>
|
||||
<button type="button" onclick="quickBlockDay('${dateStr}', 'Ziek', 'SICK')" class="w-full flex items-center space-x-2 px-3 py-2 rounded-xl text-left hover:bg-amber-50 dark:hover:bg-amber-950/50 text-slate-800 dark:text-slate-200 transition cursor-pointer font-medium">
|
||||
<span class="text-sm leading-none">🤒</span>
|
||||
<span>Hele dag: Ziek / Afwezig</span>
|
||||
</button>
|
||||
<div class="my-1 border-t border-slate-100 dark:border-slate-800/80"></div>
|
||||
<button type="button" onclick="closeDayContextMenu(); openCalendarBlockModal(null, '${dateStr}')" class="w-full flex items-center space-x-2 px-3 py-2 rounded-xl text-left hover:bg-slate-100 dark:hover:bg-slate-800/80 text-slate-600 dark:text-slate-400 transition cursor-pointer font-medium">
|
||||
<i data-lucide="calendar-plus" class="w-3.5 h-3.5 flex-shrink-0 text-slate-400"></i>
|
||||
<span>Meerdere dagen blokkeren...</span>
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
|
||||
if (window.lucide && lucide.createIcons) {
|
||||
lucide.createIcons();
|
||||
}
|
||||
|
||||
menu.classList.remove('hidden');
|
||||
|
||||
const menuWidth = 220;
|
||||
const menuHeight = menu.offsetHeight || 160;
|
||||
let posX = e.clientX;
|
||||
let posY = e.clientY;
|
||||
|
||||
if (posX + menuWidth > window.innerWidth - 10) {
|
||||
posX = window.innerWidth - menuWidth - 15;
|
||||
}
|
||||
if (posY + menuHeight > window.innerHeight - 10) {
|
||||
posY = window.innerHeight - menuHeight - 15;
|
||||
}
|
||||
|
||||
menu.style.left = `${posX}px`;
|
||||
menu.style.top = `${posY}px`;
|
||||
}
|
||||
|
||||
function closeDayContextMenu() {
|
||||
const menu = document.getElementById('dayContextMenu');
|
||||
if (menu) {
|
||||
menu.classList.add('hidden');
|
||||
}
|
||||
activeContextMenuDay = null;
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
const menu = document.getElementById('dayContextMenu');
|
||||
if (menu && !menu.contains(e.target)) {
|
||||
closeDayContextMenu();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape') {
|
||||
closeDayContextMenu();
|
||||
}
|
||||
});
|
||||
|
||||
async function quickBlockDay(dateStr, title, blockType) {
|
||||
closeDayContextMenu();
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/planner.php?action=save_calendar_block', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
title: title,
|
||||
block_type: blockType,
|
||||
start_date: dateStr,
|
||||
end_date: dateStr,
|
||||
sync_to_outlook: true
|
||||
})
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
if (data && data.success) {
|
||||
showWidgetToast(`${title} ingepland voor ${dateStr}`, 'success');
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 300);
|
||||
} else {
|
||||
alert(data.error || 'Fout bij inplannen van blokkade');
|
||||
}
|
||||
} catch (err) {
|
||||
alert('Netwerkfout bij inplannen van blokkade');
|
||||
}
|
||||
}
|
||||
|
||||
async function quickUnblockDay(blockId) {
|
||||
closeDayContextMenu();
|
||||
if (!blockId) return;
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/planner.php?action=delete_calendar_block', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id: blockId })
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
if (data && data.success) {
|
||||
showWidgetToast('Blokkade opgeheven', 'success');
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 300);
|
||||
} else {
|
||||
alert(data.error || 'Fout bij opheffen van blokkade');
|
||||
}
|
||||
} catch (err) {
|
||||
alert('Netwerkfout bij opheffen van blokkade');
|
||||
}
|
||||
}
|
||||
|
||||
function openCalendarBlockModal(existingBlock = null, defaultDate = null) {
|
||||
const modal = document.getElementById('calendarBlockModal');
|
||||
if (!modal) return;
|
||||
@@ -2862,7 +2963,7 @@ function openCalendarBlockModal(existingBlock = null, defaultDate = null) {
|
||||
deleteBtn.classList.remove('hidden');
|
||||
deleteBtn.classList.add('flex');
|
||||
}
|
||||
if (modalTitle) modalTitle.textContent = 'Blokkade Bewerken';
|
||||
if (modalTitle) modalTitle.textContent = 'Blokkade Aanpassen';
|
||||
} else {
|
||||
if (idInput) idInput.value = 0;
|
||||
selectCalBlockType('VACATION');
|
||||
@@ -2874,11 +2975,9 @@ function openCalendarBlockModal(existingBlock = null, defaultDate = null) {
|
||||
deleteBtn.classList.add('hidden');
|
||||
deleteBtn.classList.remove('flex');
|
||||
}
|
||||
if (modalTitle) modalTitle.textContent = 'Dagen Blokkeren / Vakantie';
|
||||
if (modalTitle) modalTitle.textContent = 'Meerdere Dagen Blokkeren';
|
||||
}
|
||||
|
||||
loadCalendarBlocksList();
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
modal.classList.add('flex');
|
||||
|
||||
@@ -2895,63 +2994,6 @@ function closeCalendarBlockModal() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadCalendarBlocksList() {
|
||||
const container = document.getElementById('calendarBlocksListContainer');
|
||||
if (!container) return;
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/planner.php?action=get_calendar_blocks');
|
||||
const data = await res.json();
|
||||
|
||||
if (!data.success || !Array.isArray(data.blocks) || data.blocks.length === 0) {
|
||||
container.innerHTML = '<p class="text-[11px] text-slate-400 text-center py-2 italic">Geen actieve of geplande blokkades gevonden.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
const icons = {
|
||||
'VACATION': '🏖️',
|
||||
'LEAVE': '✈️',
|
||||
'SICK': '🤒',
|
||||
'FOCUS': '🎯'
|
||||
};
|
||||
|
||||
container.innerHTML = data.blocks.map(b => {
|
||||
const icon = icons[b.block_type] || '📅';
|
||||
const safeTitle = escapeHtml(b.title);
|
||||
const dateStr = b.start_date === b.end_date
|
||||
? b.start_date
|
||||
: `${b.start_date} t/m ${b.end_date}`;
|
||||
const blockJson = JSON.stringify(b).replace(/"/g, '"');
|
||||
|
||||
return `
|
||||
<div class="flex items-center justify-between p-2 rounded-xl bg-slate-50 dark:bg-slate-800/70 border border-slate-200/70 dark:border-slate-700/60 text-xs">
|
||||
<div class="flex items-center space-x-2 min-w-0 flex-1 cursor-pointer" onclick="openCalendarBlockModal(${blockJson})">
|
||||
<span class="text-sm flex-shrink-0">${icon}</span>
|
||||
<div class="min-w-0 flex-1 truncate">
|
||||
<div class="font-bold text-slate-800 dark:text-slate-200 truncate">${safeTitle}</div>
|
||||
<div class="text-[10px] text-slate-500 dark:text-slate-400">${dateStr}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-1 flex-shrink-0 ml-2">
|
||||
<button type="button" onclick="openCalendarBlockModal(${blockJson})" class="p-1 text-slate-400 hover:text-indigo-600 dark:hover:text-indigo-400 transition cursor-pointer" title="Bewerken">
|
||||
<i data-lucide="edit-2" class="w-3.5 h-3.5"></i>
|
||||
</button>
|
||||
<button type="button" onclick="deleteCalendarBlock(${b.id})" class="p-1 text-slate-400 hover:text-rose-600 dark:hover:text-rose-400 transition cursor-pointer" title="Opheffen">
|
||||
<i data-lucide="trash-2" class="w-3.5 h-3.5"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
if (typeof lucide !== 'undefined' && lucide.createIcons) {
|
||||
lucide.createIcons();
|
||||
}
|
||||
} catch (e) {
|
||||
container.innerHTML = '<p class="text-[11px] text-rose-500 text-center py-2">Kon blokkades niet laden.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
async function submitCalendarBlock(event) {
|
||||
event.preventDefault();
|
||||
const btn = document.getElementById('btnSaveCalBlock');
|
||||
|
||||
Reference in New Issue
Block a user