IT882
This commit is contained in:
@@ -219,3 +219,23 @@ function get_session_idle_timeout(): int {
|
|||||||
return in_array($timeout, $validTimeouts, true) ? $timeout : 1800;
|
return in_array($timeout, $validTimeouts, true) ? $timeout : 1800;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Haalt de beheerbare dagblokkade-redenen op (bijv. Vakantie, Verlof, Ziek, Focusdag, ADV).
|
||||||
|
* Standaard voorzien van een duidelijke titel, emoji-icoon en actief-status.
|
||||||
|
*/
|
||||||
|
function get_calendar_block_reasons(): array {
|
||||||
|
$defaultReasons = [
|
||||||
|
['code' => 'VACATION', 'title' => 'Vakantie', 'icon' => '🏖️', 'is_active' => 1],
|
||||||
|
['code' => 'LEAVE', 'title' => 'Verlof / Vrij', 'icon' => '✈️', 'is_active' => 1],
|
||||||
|
['code' => 'SICK', 'title' => 'Ziek / Afwezig', 'icon' => '🤒', 'is_active' => 1],
|
||||||
|
['code' => 'FOCUS', 'title' => 'Focusdag', 'icon' => '🎯', 'is_active' => 1],
|
||||||
|
['code' => 'ADV', 'title' => 'ADV Dag', 'icon' => '📋', 'is_active' => 1],
|
||||||
|
];
|
||||||
|
|
||||||
|
$saved = get_system_setting('calendar_block_reasons', null);
|
||||||
|
if (is_array($saved) && !empty($saved)) {
|
||||||
|
return $saved;
|
||||||
|
}
|
||||||
|
return $defaultReasons;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+45
-43
@@ -36,6 +36,7 @@ $selectedTs = strtotime($selectedDate);
|
|||||||
// Haal organisatie werkdag- en AI-standaarden op (Release v1.4 & v1.5)
|
// Haal organisatie werkdag- en AI-standaarden op (Release v1.4 & v1.5)
|
||||||
$workdaySettings = get_workday_settings();
|
$workdaySettings = get_workday_settings();
|
||||||
$aiSettings = get_ai_settings();
|
$aiSettings = get_ai_settings();
|
||||||
|
$calendarBlockReasons = get_calendar_block_reasons();
|
||||||
$activeWorkdays = $workdaySettings['workdays'] ?? [1, 2, 3, 4, 5];
|
$activeWorkdays = $workdaySettings['workdays'] ?? [1, 2, 3, 4, 5];
|
||||||
if (!is_array($activeWorkdays) || empty($activeWorkdays)) {
|
if (!is_array($activeWorkdays) || empty($activeWorkdays)) {
|
||||||
$activeWorkdays = [1, 2, 3, 4, 5];
|
$activeWorkdays = [1, 2, 3, 4, 5];
|
||||||
@@ -1095,17 +1096,6 @@ for ($h = $startHour; $h <= $endHour; $h++) {
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</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>
|
|
||||||
<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 -->
|
<!-- 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">
|
<div class="flex items-center justify-between pt-3 border-t border-slate-100 dark:border-slate-800/80">
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
@@ -2387,6 +2377,17 @@ if ($isAjaxRequest) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Contextmenu voor Rechtermuisklik op een dag (geplaatst op body-niveau om absolute viewport containment te waarborgen) -->
|
||||||
|
<div id="dayContextMenu" class="fixed z-[99999] hidden min-w-[220px] max-w-[280px] bg-white dark:bg-[#111624] border border-slate-200 dark:border-slate-800 rounded-2xl shadow-2xl 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>
|
||||||
|
<div id="dayContextMenuActions" class="p-1 space-y-0.5">
|
||||||
|
<!-- Acties worden via JS ingevuld -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Modal: Agenda Dagen Blokkeren (Vakantie / Verlof / Focus) -->
|
<!-- Modal: Agenda Dagen Blokkeren (Vakantie / Verlof / Focus) -->
|
||||||
<div id="calendarBlockModal" class="fixed inset-0 z-50 bg-slate-950/70 backdrop-blur-sm hidden items-center justify-center p-4">
|
<div id="calendarBlockModal" class="fixed inset-0 z-50 bg-slate-950/70 backdrop-blur-sm hidden items-center justify-center p-4">
|
||||||
<div class="fociz-card p-6 w-full max-w-lg shadow-2xl space-y-4 max-h-[90vh] flex flex-col">
|
<div class="fociz-card p-6 w-full max-w-lg shadow-2xl space-y-4 max-h-[90vh] flex flex-col">
|
||||||
@@ -2413,10 +2414,11 @@ if ($isAjaxRequest) {
|
|||||||
<div>
|
<div>
|
||||||
<label class="block text-xs font-bold text-slate-700 dark:text-slate-300 mb-1">Type Blokkade</label>
|
<label class="block text-xs font-bold text-slate-700 dark:text-slate-300 mb-1">Type Blokkade</label>
|
||||||
<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">
|
<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>
|
<?php foreach ($calendarBlockReasons as $reason): ?>
|
||||||
<option value="LEAVE">Verlof / ADV / Vrije dag</option>
|
<?php if (!empty($reason['is_active'])): ?>
|
||||||
<option value="SICK">Ziekte / Afwezig</option>
|
<option value="<?= htmlspecialchars($reason['code']) ?>"><?= htmlspecialchars((!empty($reason['icon']) ? $reason['icon'] . ' ' : '') . $reason['title']) ?></option>
|
||||||
<option value="FOCUS">Focusdag</option>
|
<?php endif; ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -2752,12 +2754,13 @@ function showWidgetToast(htmlMessage, type = 'success', duration = 3500) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Agenda Dagen Blokkeren & Rechtermuisklik Context Menu ---
|
// --- Agenda Dagen Blokkeren & Rechtermuisklik Context Menu ---
|
||||||
const CAL_BLOCK_DEFAULT_TITLES = {
|
const CAL_BLOCK_REASONS = <?= json_encode(array_values(array_filter($calendarBlockReasons, fn($r) => !empty($r['is_active'])))) ?>;
|
||||||
'VACATION': 'Vakantie',
|
const CAL_BLOCK_DEFAULT_TITLES = {};
|
||||||
'LEAVE': 'Verlof',
|
if (Array.isArray(CAL_BLOCK_REASONS)) {
|
||||||
'SICK': 'Ziekte / Afwezig',
|
CAL_BLOCK_REASONS.forEach(r => {
|
||||||
'FOCUS': 'Focusdag'
|
if (r && r.code) CAL_BLOCK_DEFAULT_TITLES[r.code] = r.title;
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function selectCalBlockType(type) {
|
function selectCalBlockType(type) {
|
||||||
const input = document.getElementById('calBlockType');
|
const input = document.getElementById('calBlockType');
|
||||||
@@ -2819,19 +2822,25 @@ function openDayContextMenu(e, dateStr, blockId = 0, blockTitle = '') {
|
|||||||
} else {
|
} else {
|
||||||
statusBadge.innerHTML = `<span class="text-[9px] font-normal text-slate-400">Beschikbaar</span>`;
|
statusBadge.innerHTML = `<span class="text-[9px] font-normal text-slate-400">Beschikbaar</span>`;
|
||||||
|
|
||||||
|
let reasonsHtml = '';
|
||||||
|
if (Array.isArray(CAL_BLOCK_REASONS) && CAL_BLOCK_REASONS.length > 0) {
|
||||||
|
reasonsHtml = CAL_BLOCK_REASONS.map(r => `
|
||||||
|
<button type="button" onclick="quickBlockDay('${dateStr}', '${escapeHtml(r.title)}', '${escapeHtml(r.code)}')" 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">${escapeHtml(r.icon || '📅')}</span>
|
||||||
|
<span>Hele dag: ${escapeHtml(r.title)}</span>
|
||||||
|
</button>
|
||||||
|
`).join('');
|
||||||
|
} else {
|
||||||
|
reasonsHtml = `
|
||||||
|
<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>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
actions.innerHTML = `
|
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">
|
${reasonsHtml}
|
||||||
<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>
|
<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">
|
<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>
|
<i data-lucide="calendar-plus" class="w-3.5 h-3.5 flex-shrink-0 text-slate-400"></i>
|
||||||
@@ -2847,16 +2856,9 @@ function openDayContextMenu(e, dateStr, blockId = 0, blockTitle = '') {
|
|||||||
menu.classList.remove('hidden');
|
menu.classList.remove('hidden');
|
||||||
|
|
||||||
const menuWidth = 220;
|
const menuWidth = 220;
|
||||||
const menuHeight = menu.offsetHeight || 160;
|
const menuHeight = menu.offsetHeight || 180;
|
||||||
let posX = e.clientX;
|
let posX = Math.max(12, Math.min(window.innerWidth - menuWidth - 16, e.clientX));
|
||||||
let posY = e.clientY;
|
let posY = Math.max(12, Math.min(window.innerHeight - menuHeight - 16, 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.left = `${posX}px`;
|
||||||
menu.style.top = `${posY}px`;
|
menu.style.top = `${posY}px`;
|
||||||
|
|||||||
Reference in New Issue
Block a user