Planner changes
This commit is contained in:
@@ -175,7 +175,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// 3. Organisatie Werkdag Standaarden opslaan (Release v1.4)
|
||||
elseif ($action === 'save_workday_settings') {
|
||||
$workdayStart = trim($_POST['workday_start'] ?? '08:30');
|
||||
$workdayEnd = trim($_POST['workday_end'] ?? '17:30');
|
||||
$workdayEnd = trim($_POST['workday_end'] ?? '17:00');
|
||||
$lunchStart = trim($_POST['lunch_start'] ?? '12:30');
|
||||
$lunchEnd = trim($_POST['lunch_end'] ?? '13:00');
|
||||
$pomoFocus = max(10, min(120, (int)($_POST['pomodoro_focus'] ?? 25)));
|
||||
|
||||
+17
-6
@@ -651,10 +651,11 @@ try {
|
||||
$data = is_array($rawInput) ? $rawInput : $_GET;
|
||||
$duration = max(5, (int)($data['duration_minutes'] ?? 30));
|
||||
$excludeTaskId = (int)($data['task_id'] ?? 0);
|
||||
$startFromNextWorkday = !empty($data['start_from_next_workday']);
|
||||
|
||||
$workdaySettings = get_workday_settings();
|
||||
$workdayStartStr = $workdaySettings['workday_start'] ?? '08:30';
|
||||
$workdayEndStr = $workdaySettings['workday_end'] ?? '17:30';
|
||||
$workdayEndStr = $workdaySettings['workday_end'] ?? '17:00';
|
||||
$lunchStartStr = $workdaySettings['lunch_start'] ?? '12:30';
|
||||
$lunchEndStr = $workdaySettings['lunch_end'] ?? '13:00';
|
||||
|
||||
@@ -693,6 +694,12 @@ try {
|
||||
$dutchMonths = ['', 'jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'];
|
||||
|
||||
$checkDate = clone $now;
|
||||
if ($startFromNextWorkday) {
|
||||
$checkDate->modify('+1 day');
|
||||
while ((int)$checkDate->format('N') >= 6) {
|
||||
$checkDate->modify('+1 day');
|
||||
}
|
||||
}
|
||||
$foundSlot = null;
|
||||
$maxDays = 14;
|
||||
$checkedDays = 0;
|
||||
@@ -707,7 +714,7 @@ try {
|
||||
}
|
||||
|
||||
$dateStr = $checkDate->format('Y-m-d');
|
||||
$isToday = ($dateStr === $now->format('Y-m-d'));
|
||||
$isToday = ($dateStr === $now->format('Y-m-d')) && !$startFromNextWorkday;
|
||||
|
||||
// Bepaal vroegste startminuut voor deze dag (op hele kwartieren)
|
||||
if ($isToday) {
|
||||
@@ -805,13 +812,17 @@ try {
|
||||
|
||||
if ($foundSlot) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'slot' => $foundSlot,
|
||||
'success' => true,
|
||||
'slot' => $foundSlot,
|
||||
'workday_start' => $workdayStartStr,
|
||||
'workday_end' => $workdayEndStr,
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => "Geen vrij blok van {$duration} minuten gevonden binnen de gezette werktijden ({$workdayStartStr} - {$workdayEndStr}) voor de komende {$maxDays} werkdagen.",
|
||||
'success' => false,
|
||||
'workday_start' => $workdayStartStr,
|
||||
'workday_end' => $workdayEndStr,
|
||||
'error' => "Geen vrij blok van {$duration} minuten gevonden binnen de gezette werktijden ({$workdayStartStr} - {$workdayEndStr}) voor de komende {$maxDays} werkdagen.",
|
||||
]);
|
||||
}
|
||||
exit;
|
||||
|
||||
+1
-1
@@ -168,7 +168,7 @@ function fociz_ai_summarize_to_roadmap(string $content, string $sessionTitle = '
|
||||
*/
|
||||
function fociz_ai_smart_schedule(array $tasks, array $events, array $workdaySettings): array {
|
||||
$startH = (int)explode(':', $workdaySettings['workday_start'] ?? '08:30')[0];
|
||||
$endH = (int)explode(':', $workdaySettings['workday_end'] ?? '17:30')[0];
|
||||
$endH = (int)explode(':', $workdaySettings['workday_end'] ?? '17:00')[0];
|
||||
$lunchStart = $workdaySettings['lunch_start'] ?? '12:30';
|
||||
$lunchEnd = $workdaySettings['lunch_end'] ?? '13:00';
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ function set_system_setting(string $key, $value): bool {
|
||||
function get_workday_settings(): array {
|
||||
return [
|
||||
'workday_start' => get_system_setting('workday_start', '08:30'),
|
||||
'workday_end' => get_system_setting('workday_end', '17:30'),
|
||||
'workday_end' => get_system_setting('workday_end', '17:00'),
|
||||
'lunch_start' => get_system_setting('lunch_start', '12:30'),
|
||||
'lunch_end' => get_system_setting('lunch_end', '13:00'),
|
||||
'pomodoro_focus' => (int)get_system_setting('pomodoro_focus', 25),
|
||||
|
||||
+311
-22
@@ -378,7 +378,7 @@ $initialSyncHash = md5(json_encode([
|
||||
|
||||
// 6. Tijdlijn uren & Werkdag Standaarden (Release v1.4)
|
||||
$workdayStartStr = $workdaySettings['workday_start'] ?? '08:30';
|
||||
$workdayEndStr = $workdaySettings['workday_end'] ?? '17:30';
|
||||
$workdayEndStr = $workdaySettings['workday_end'] ?? '17:00';
|
||||
$lunchStart = $workdaySettings['lunch_start'] ?? '12:30';
|
||||
$lunchEnd = $workdaySettings['lunch_end'] ?? '13:00';
|
||||
$lunchHour = (int)explode(':', $lunchStart)[0];
|
||||
@@ -2084,6 +2084,52 @@ if ($isAjaxRequest) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal: Waarschuwing Buiten Werktijden -->
|
||||
<div id="outsideWorkhoursModal" 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-md shadow-2xl space-y-4 border border-amber-500/30">
|
||||
<div class="flex items-start space-x-3">
|
||||
<div class="w-10 h-10 rounded-2xl bg-amber-500/10 border border-amber-500/20 text-amber-500 flex items-center justify-center flex-shrink-0">
|
||||
<i data-lucide="alert-triangle" class="w-5 h-5"></i>
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<h3 class="text-base font-bold text-slate-900 dark:text-white leading-tight">
|
||||
Let op! Je plant buiten werktijden
|
||||
</h3>
|
||||
<p class="text-xs text-slate-500 dark:text-slate-400 mt-1">
|
||||
Het ingeplande tijdblok valt buiten de gezette werktijden.
|
||||
</p>
|
||||
</div>
|
||||
<button type="button" onclick="closeOutsideWorkhoursModal('CANCEL')" class="p-1 text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 rounded-lg transition cursor-pointer flex-shrink-0">
|
||||
<i data-lucide="x" class="w-4 h-4"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="bg-amber-50 dark:bg-amber-950/20 border border-amber-200 dark:border-amber-800/40 rounded-xl p-3.5 text-xs text-amber-800 dark:text-amber-300 space-y-1.5">
|
||||
<div class="flex items-center justify-between text-[11px] font-semibold text-amber-900 dark:text-amber-200">
|
||||
<span>Gekozen tijdblok:</span>
|
||||
<span id="outsideWorkhoursSelectedSlot" class="font-mono font-bold"></span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-[11px] text-amber-700 dark:text-amber-400">
|
||||
<span>Gezette werktijden:</span>
|
||||
<span id="outsideWorkhoursBounds" class="font-mono font-semibold"></span>
|
||||
</div>
|
||||
<p class="text-[11px] text-amber-700/80 dark:text-amber-400/80 pt-1 border-t border-amber-200/60 dark:border-amber-800/30">
|
||||
Kies <strong>Nee</strong> om het item automatisch in te plannen in het eerstvolgende open blok op de volgende werkdag, of kies <strong>Ja</strong> om toch nu buiten werktijd te plannen.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center space-x-2.5 pt-2">
|
||||
<button type="button" id="btnOutsideWorkhoursNo" onclick="closeOutsideWorkhoursModal('NEE')" class="flex-1 px-4 py-2.5 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white font-bold text-xs transition shadow-xs flex items-center justify-center space-x-1.5 cursor-pointer">
|
||||
<i data-lucide="calendar-arrow-up" class="w-4 h-4"></i>
|
||||
<span>Nee (Volgende werkdag)</span>
|
||||
</button>
|
||||
<button type="button" id="btnOutsideWorkhoursYes" onclick="closeOutsideWorkhoursModal('JA')" class="px-4 py-2.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-200 font-semibold text-xs transition cursor-pointer">
|
||||
<span>Ja, toch inplannen</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal: Direct E-mail Inplannen als Dagtaak -->
|
||||
<div id="planEmailDirectModal" 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">
|
||||
@@ -3412,16 +3458,27 @@ function setJiraPlanDuration(minutes) {
|
||||
}
|
||||
|
||||
function suggestNextFreeSlot() {
|
||||
// Zoek het volgende ronde kwartier na het huidige moment
|
||||
const now = new Date();
|
||||
let h = now.getHours();
|
||||
let m = now.getMinutes();
|
||||
// Rond op naar boven naar het volgende kwartier
|
||||
m = Math.ceil((m + 1) / 15) * 15;
|
||||
if (m >= 60) { h += 1; m = 0; }
|
||||
// Begrenzen op werktijd 08:00-18:00
|
||||
if (h < 8) { h = 8; m = 0; }
|
||||
if (h >= 18) { h = 8; m = 0; } // Morgen → val terug op 08:00
|
||||
|
||||
const wStart = (typeof FOCIZ_WORKDAY_START !== 'undefined' && FOCIZ_WORKDAY_START) ? FOCIZ_WORKDAY_START : '08:30';
|
||||
const wEnd = (typeof FOCIZ_WORKDAY_END !== 'undefined' && FOCIZ_WORKDAY_END) ? FOCIZ_WORKDAY_END : '17:00';
|
||||
const [startH, startM] = wStart.split(':').map(Number);
|
||||
const [endH, endM] = wEnd.split(':').map(Number);
|
||||
|
||||
const curMin = h * 60 + m;
|
||||
const startMin = startH * 60 + startM;
|
||||
const endMin = endH * 60 + endM;
|
||||
|
||||
if (curMin < startMin) {
|
||||
return `${String(startH).padStart(2,'0')}:${String(startM).padStart(2,'0')}`;
|
||||
}
|
||||
if (curMin >= endMin) {
|
||||
return `${String(startH).padStart(2,'0')}:${String(startM).padStart(2,'0')}`;
|
||||
}
|
||||
return `${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')}`;
|
||||
}
|
||||
|
||||
@@ -3434,16 +3491,44 @@ async function submitJiraPlanModal() {
|
||||
const finalTitle = customTitle || `Oppakken Jira item ${issue.key}`;
|
||||
|
||||
const dateInput = document.getElementById('jiraPlanDate');
|
||||
const planDate = (dateInput && dateInput.value) ? dateInput.value : ((typeof activePlannerDate !== 'undefined' && activePlannerDate) ? activePlannerDate : new Date().toISOString().slice(0, 10));
|
||||
let planDate = (dateInput && dateInput.value) ? dateInput.value : ((typeof activePlannerDate !== 'undefined' && activePlannerDate) ? activePlannerDate : new Date().toISOString().slice(0, 10));
|
||||
|
||||
const duration = parseInt(document.getElementById('jiraPlanDuration').value, 10) || 15;
|
||||
const startTime = document.getElementById('jiraPlanStartTime').value.trim();
|
||||
let startTime = document.getElementById('jiraPlanStartTime').value.trim();
|
||||
const priority = document.getElementById('jiraPlanPriority').value;
|
||||
|
||||
// Controleer of de ingeplande tijd buiten de gezette werktijden valt
|
||||
if (startTime) {
|
||||
const [hh, mm] = startTime.split(':').map(Number);
|
||||
const endMin = hh * 60 + mm + duration;
|
||||
const endTime = `${String(Math.floor(endMin / 60)).padStart(2,'0')}:${String(endMin % 60).padStart(2,'0')}`;
|
||||
|
||||
const check = checkWorkdayBounds(planDate, startTime, endTime, duration);
|
||||
if (check.isOutside) {
|
||||
const answer = await promptOutsideWorkhoursModal(check);
|
||||
if (answer === 'CANCEL') {
|
||||
return;
|
||||
}
|
||||
if (answer === 'NEE') {
|
||||
// Automatisch naar volgende werkdag met eerder gezette voorwaarden
|
||||
try {
|
||||
const nextSlot = await findSlotOnNextWorkday(duration, 0);
|
||||
planDate = nextSlot.date;
|
||||
startTime = nextSlot.start;
|
||||
} catch (err) {
|
||||
alert(err.message || 'Kon geen open blok vinden op de volgende werkdag.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const btn = document.getElementById('btnSubmitJiraPlan');
|
||||
const origHtml = btn.innerHTML;
|
||||
btn.innerHTML = '<span class="text-xs font-bold animate-pulse">Inplannen...</span>';
|
||||
btn.disabled = true;
|
||||
const origHtml = btn ? btn.innerHTML : '';
|
||||
if (btn) {
|
||||
btn.innerHTML = '<span class="text-xs font-bold animate-pulse">Inplannen...</span>';
|
||||
btn.disabled = true;
|
||||
}
|
||||
|
||||
try {
|
||||
const payload = {
|
||||
@@ -3478,13 +3563,17 @@ async function submitJiraPlanModal() {
|
||||
}
|
||||
} else {
|
||||
alert(data.error || 'Kon ticket niet inplannen');
|
||||
btn.innerHTML = origHtml;
|
||||
btn.disabled = false;
|
||||
if (btn) {
|
||||
btn.innerHTML = origHtml;
|
||||
btn.disabled = false;
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
alert('Netwerkfout bij inplannen');
|
||||
btn.innerHTML = origHtml;
|
||||
btn.disabled = false;
|
||||
if (btn) {
|
||||
btn.innerHTML = origHtml;
|
||||
btn.disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3530,6 +3619,31 @@ async function submitPlanEmailDirect() {
|
||||
return;
|
||||
}
|
||||
|
||||
let planDate = activePlannerDate;
|
||||
if (startTime) {
|
||||
const [hh, mm] = startTime.split(':').map(Number);
|
||||
const endMin = hh * 60 + mm + duration;
|
||||
const endTime = `${String(Math.floor(endMin / 60)).padStart(2,'0')}:${String(endMin % 60).padStart(2,'0')}`;
|
||||
|
||||
const check = checkWorkdayBounds(planDate, startTime, endTime, duration);
|
||||
if (check.isOutside) {
|
||||
const answer = await promptOutsideWorkhoursModal(check);
|
||||
if (answer === 'CANCEL') {
|
||||
return;
|
||||
}
|
||||
if (answer === 'NEE') {
|
||||
try {
|
||||
const nextSlot = await findSlotOnNextWorkday(duration, 0);
|
||||
planDate = nextSlot.date;
|
||||
startTime = nextSlot.start;
|
||||
} catch (err) {
|
||||
alert(err.message || 'Kon geen open blok vinden op de volgende werkdag.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const btn = document.getElementById('btnSubmitPlanEmailDirect');
|
||||
const origHtml = btn.innerHTML;
|
||||
btn.innerText = 'Inplannen...';
|
||||
@@ -3546,13 +3660,13 @@ async function submitPlanEmailDirect() {
|
||||
duration_minutes: duration,
|
||||
time_block_start: startTime,
|
||||
sync_outlook: syncOutlook,
|
||||
date: activePlannerDate
|
||||
date: planDate
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.success) {
|
||||
closePlanEmailDirectModal();
|
||||
switchPlannerDate(activePlannerDate, null, false);
|
||||
switchPlannerDate(planDate, null, false);
|
||||
} else {
|
||||
alert(data.error || 'Kon e-mail niet inplannen');
|
||||
}
|
||||
@@ -3669,6 +3783,135 @@ let weekStartDate = '<?= $weekStart ?>';
|
||||
let weekEndDate = '<?= $weekEnd ?>';
|
||||
let currentSyncHash = '<?= $initialSyncHash ?? '' ?>';
|
||||
let isDateSwitching = false;
|
||||
const FOCIZ_WORKDAY_START = '<?= $workdayStartStr ?>';
|
||||
const FOCIZ_WORKDAY_END = '<?= $workdayEndStr ?>';
|
||||
|
||||
/**
|
||||
* Controleert of een gepland tijdstip buiten de gezette werktijden of in het weekend valt
|
||||
*/
|
||||
function checkWorkdayBounds(planDate, startTime, endTime, duration) {
|
||||
if (!startTime || !startTime.trim()) {
|
||||
return { isOutside: false };
|
||||
}
|
||||
|
||||
const start = startTime.trim();
|
||||
let [sH, sM] = start.split(':').map(Number);
|
||||
if (isNaN(sH) || isNaN(sM)) return { isOutside: false };
|
||||
|
||||
let dur = parseInt(duration, 10);
|
||||
if (isNaN(dur) || dur <= 0) dur = 30;
|
||||
|
||||
let end = (endTime && endTime.trim()) ? endTime.trim() : '';
|
||||
let eH, eM;
|
||||
if (end) {
|
||||
[eH, eM] = end.split(':').map(Number);
|
||||
}
|
||||
if (isNaN(eH) || isNaN(eM)) {
|
||||
const totalEndMin = sH * 60 + sM + dur;
|
||||
eH = Math.floor(totalEndMin / 60);
|
||||
eM = totalEndMin % 60;
|
||||
end = `${String(eH).padStart(2,'0')}:${String(eM).padStart(2,'0')}`;
|
||||
}
|
||||
|
||||
const startMin = sH * 60 + sM;
|
||||
const endMin = eH * 60 + eM;
|
||||
|
||||
const wStart = (typeof FOCIZ_WORKDAY_START !== 'undefined' && FOCIZ_WORKDAY_START) ? FOCIZ_WORKDAY_START : '08:30';
|
||||
const wEnd = (typeof FOCIZ_WORKDAY_END !== 'undefined' && FOCIZ_WORKDAY_END) ? FOCIZ_WORKDAY_END : '17:00';
|
||||
|
||||
const [wsH, wsM] = wStart.split(':').map(Number);
|
||||
const [weH, weM] = wEnd.split(':').map(Number);
|
||||
const wStartMin = wsH * 60 + wsM;
|
||||
const wEndMin = weH * 60 + weM;
|
||||
|
||||
let isOutside = false;
|
||||
let reason = '';
|
||||
|
||||
if (planDate) {
|
||||
const d = new Date(planDate + 'T12:00:00');
|
||||
const dayOfWeek = d.getDay(); // 0 = Zo, 6 = Za
|
||||
if (dayOfWeek === 0 || dayOfWeek === 6) {
|
||||
isOutside = true;
|
||||
reason = 'Het gekozen tijdstip valt in het weekend.';
|
||||
}
|
||||
}
|
||||
|
||||
if (startMin < wStartMin || endMin > wEndMin || startMin >= wEndMin) {
|
||||
isOutside = true;
|
||||
reason = `Het gekozen tijdstip (${start} - ${end}) valt buiten de gezette werktijden (${wStart} - ${wEnd}).`;
|
||||
}
|
||||
|
||||
return {
|
||||
isOutside,
|
||||
reason,
|
||||
start,
|
||||
end,
|
||||
duration: dur,
|
||||
workdayStart: wStart,
|
||||
workdayEnd: wEnd,
|
||||
date: planDate
|
||||
};
|
||||
}
|
||||
|
||||
let _outsideWorkhoursResolver = null;
|
||||
|
||||
function promptOutsideWorkhoursModal(checkResult) {
|
||||
return new Promise((resolve) => {
|
||||
_outsideWorkhoursResolver = resolve;
|
||||
const modal = document.getElementById('outsideWorkhoursModal');
|
||||
const selectedEl = document.getElementById('outsideWorkhoursSelectedSlot');
|
||||
const boundsEl = document.getElementById('outsideWorkhoursBounds');
|
||||
|
||||
if (selectedEl) {
|
||||
selectedEl.textContent = `${checkResult.start} - ${checkResult.end} (${checkResult.duration}m)`;
|
||||
}
|
||||
if (boundsEl) {
|
||||
boundsEl.textContent = `${checkResult.workdayStart} tot ${checkResult.workdayEnd}`;
|
||||
}
|
||||
|
||||
if (modal) {
|
||||
modal.classList.remove('hidden');
|
||||
modal.classList.add('flex');
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
} else {
|
||||
const ok = confirm(`Let op! Je plant buiten werktijden (${checkResult.workdayStart} - ${checkResult.workdayEnd}).\n\nKlik OK (Ja) om toch zo in te plannen, of Annuleren (Nee) om automatisch naar de volgende werkdag te gaan.`);
|
||||
resolve(ok ? 'JA' : 'NEE');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function closeOutsideWorkhoursModal(choice) {
|
||||
const modal = document.getElementById('outsideWorkhoursModal');
|
||||
if (modal) {
|
||||
modal.classList.add('hidden');
|
||||
modal.classList.remove('flex');
|
||||
}
|
||||
if (typeof _outsideWorkhoursResolver === 'function') {
|
||||
const res = _outsideWorkhoursResolver;
|
||||
_outsideWorkhoursResolver = null;
|
||||
res(choice);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zoekt automatisch het eerstvolgende open kwartierblok op de volgende werkdag
|
||||
*/
|
||||
async function findSlotOnNextWorkday(duration, taskId = 0) {
|
||||
const res = await fetch('/api/planner.php?action=find_next_free_slot', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
duration_minutes: duration,
|
||||
task_id: taskId,
|
||||
start_from_next_workday: true
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.success && data.slot) {
|
||||
return data.slot;
|
||||
}
|
||||
throw new Error(data.error || 'Geen vrij open blok gevonden op de volgende werkdag.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Wisselt de actieve plannerdatum geruisloos via AJAX
|
||||
@@ -3964,6 +4207,28 @@ async function submitNewTask() {
|
||||
return;
|
||||
}
|
||||
|
||||
let planDate = activePlannerDate;
|
||||
if (time) {
|
||||
const check = checkWorkdayBounds(planDate, time, endTime, duration);
|
||||
if (check.isOutside) {
|
||||
const answer = await promptOutsideWorkhoursModal(check);
|
||||
if (answer === 'CANCEL') {
|
||||
return;
|
||||
}
|
||||
if (answer === 'NEE') {
|
||||
try {
|
||||
const nextSlot = await findSlotOnNextWorkday(duration, 0);
|
||||
planDate = nextSlot.date;
|
||||
time = nextSlot.start;
|
||||
endTime = nextSlot.end;
|
||||
} catch (err) {
|
||||
alert(err.message || 'Kon geen open blok vinden op de volgende werkdag.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/planner.php?action=add_task', {
|
||||
method: 'POST',
|
||||
@@ -3975,7 +4240,7 @@ async function submitNewTask() {
|
||||
time_block_end: endTime,
|
||||
duration_minutes: duration,
|
||||
sync_to_outlook: syncOutlook,
|
||||
date: activePlannerDate
|
||||
date: planDate
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
@@ -3986,7 +4251,7 @@ async function submitNewTask() {
|
||||
toggleAddTaskForm();
|
||||
const titleInput = document.getElementById('newTaskTitle');
|
||||
if (titleInput) titleInput.value = '';
|
||||
switchPlannerDate(activePlannerDate, null, false);
|
||||
switchPlannerDate(planDate, null, false);
|
||||
} else {
|
||||
alert(data.error || 'Fout bij opslaan van de taak');
|
||||
}
|
||||
@@ -4217,9 +4482,9 @@ async function submitEditTask() {
|
||||
const title = document.getElementById('editTaskTitle').value.trim();
|
||||
const priority = document.getElementById('editTaskPriority').value;
|
||||
const dateInput = document.getElementById('editTaskDate');
|
||||
const taskDate = (dateInput && dateInput.value) ? dateInput.value.trim() : (typeof activePlannerDate !== 'undefined' ? activePlannerDate : new Date().toISOString().slice(0, 10));
|
||||
const startTime = document.getElementById('editTaskStartTime').value.trim();
|
||||
const endTime = document.getElementById('editTaskEndTime').value.trim();
|
||||
let taskDate = (dateInput && dateInput.value) ? dateInput.value.trim() : (typeof activePlannerDate !== 'undefined' ? activePlannerDate : new Date().toISOString().slice(0, 10));
|
||||
let startTime = document.getElementById('editTaskStartTime').value.trim();
|
||||
let endTime = document.getElementById('editTaskEndTime').value.trim();
|
||||
const duration = getSelectedEditTaskDurationMinutes();
|
||||
const saveBtn = document.getElementById('btnSaveEditTask');
|
||||
|
||||
@@ -4228,6 +4493,30 @@ async function submitEditTask() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Controleer of de geplande tijd buiten de gezette werktijden valt
|
||||
if (startTime) {
|
||||
const check = checkWorkdayBounds(taskDate, startTime, endTime, duration);
|
||||
if (check.isOutside) {
|
||||
const answer = await promptOutsideWorkhoursModal(check);
|
||||
if (answer === 'CANCEL') {
|
||||
return;
|
||||
}
|
||||
if (answer === 'NEE') {
|
||||
// Automatisch naar volgende werkdag met eerder gezette voorwaarden
|
||||
try {
|
||||
const nextSlot = await findSlotOnNextWorkday(duration, taskId);
|
||||
taskDate = nextSlot.date;
|
||||
startTime = nextSlot.start;
|
||||
endTime = nextSlot.end;
|
||||
} catch (err) {
|
||||
alert(err.message || 'Kon geen open blok vinden op de volgende werkdag.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Bij 'JA': ga gewoon door met het buiten werktijd ingevulde tijdstip
|
||||
}
|
||||
}
|
||||
|
||||
if (saveBtn) {
|
||||
saveBtn.innerText = 'Opslaan...';
|
||||
saveBtn.disabled = true;
|
||||
|
||||
Reference in New Issue
Block a user