+
@@ -382,16 +392,16 @@ for ($h = $startHour; $h <= $endHour; $h++) {
-
+
Vorige week
-
+
Vandaag
-
+
Volgende week
@@ -414,7 +424,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
type="date"
id="jumpDateInput"
value="= htmlspecialchars($selectedDate) ?>"
- onchange="if(this.value) window.location.href='planner.php?date=' + this.value;"
+ onchange="if(this.value) switchPlannerDate(this.value, event);"
class="bg-slate-50 dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-1.5 text-xs text-slate-800 dark:text-slate-200 focus:outline-none focus:ring-2 focus:ring-indigo-500/30 font-medium cursor-pointer shadow-2xs"
>
@@ -425,6 +435,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
+ true,
+ 'selectedDate' => $selectedDate,
+ 'formattedDate' => $formattedSelectedDate,
+ 'weekStart' => $weekStart,
+ 'weekEnd' => $weekEnd,
+ 'weekNumber' => $weekNumber,
+ 'yearNumber' => $yearNumber,
+ 'formattedWeek' => $formattedWeekRange,
+ 'syncHash' => $initialSyncHash,
+ 'focusGoal' => $dailyPlan['focus_goal'] ?? '',
+ 'dailyNotes' => $dailyPlan['notes'] ?? '',
+ 'title' => 'Fociz — Dagplanning (' . $formattedSelectedDate . ')',
+ 'html' => $contentHtml,
+ ]);
+ exit;
+}
+?>
@@ -1134,8 +1167,103 @@ function selectFocusTask(title) {
document.getElementById('activeTaskDisplay').innerText = title;
}
+// --- Globale Planner Status & Naadloos AJAX Datumbeheer ---
+let activePlannerDate = '= $selectedDate ?>';
+let weekStartDate = '= $weekStart ?>';
+let weekEndDate = '= $weekEnd ?>';
+let currentSyncHash = '= $initialSyncHash ?? '' ?>';
+let isDateSwitching = false;
+
+/**
+ * Wisselt de actieve plannerdatum geruisloos via AJAX
+ * Behoudt de huidige schermhoogte (scrollpositie) en voorkomt flitsen/herladen
+ */
+async function switchPlannerDate(newDate, event = null, pushState = true) {
+ if (event && event.preventDefault) {
+ event.preventDefault();
+ }
+ if (!newDate || isDateSwitching) return;
+
+ const container = document.getElementById('plannerContentArea');
+ if (!container) {
+ window.location.href = 'planner.php?date=' + encodeURIComponent(newDate);
+ return;
+ }
+
+ // Onthoud exact de huidige scrollpositie
+ const currentScrollY = window.scrollY;
+ isDateSwitching = true;
+
+ // Subtiele visuele feedback zonder layout-shift
+ container.classList.add('opacity-60', 'pointer-events-none');
+
+ try {
+ const response = await fetch(`planner.php?date=${encodeURIComponent(newDate)}&ajax=1`, {
+ headers: {
+ 'X-Requested-With': 'XMLHttpRequest'
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP fout ${response.status}`);
+ }
+
+ const data = await response.json();
+ if (!data || !data.success || !data.html) {
+ throw new Error(data?.error || 'Ongeldige serverrespons');
+ }
+
+ // Vervang de dynamische plannerinhoud geruisloos
+ container.innerHTML = data.html;
+
+ // Werk globale variabelen bij
+ activePlannerDate = data.selectedDate;
+ if (data.weekStart) weekStartDate = data.weekStart;
+ if (data.weekEnd) weekEndDate = data.weekEnd;
+ if (data.syncHash) currentSyncHash = data.syncHash;
+
+ // Werk paginatitel bij
+ if (data.title) {
+ document.title = data.title;
+ }
+
+ // Werk URL bij in adresbalk zonder paginaherlaad
+ if (pushState && window.history && window.history.pushState) {
+ const newUrl = `planner.php?date=${encodeURIComponent(newDate)}`;
+ window.history.pushState({ date: newDate }, data.title || '', newUrl);
+ }
+
+ // Render Lucide SVG-iconen in de nieuwe inhoud
+ if (typeof lucide !== 'undefined' && lucide.createIcons) {
+ lucide.createIcons();
+ }
+
+ // Garandeer dat het scherm exact op dezelfde scrollhoogte blijft
+ window.scrollTo({
+ top: currentScrollY,
+ behavior: 'instant'
+ });
+
+ } catch (err) {
+ console.error('Fout bij wisselen van datum via AJAX:', err);
+ // Veilige fallback bij netwerkonderbreking
+ window.location.href = 'planner.php?date=' + encodeURIComponent(newDate);
+ } finally {
+ isDateSwitching = false;
+ container.classList.remove('opacity-60', 'pointer-events-none');
+ }
+}
+
+// Browser Terug/Vooruit knoppen opvangen (popstate)
+window.addEventListener('popstate', (event) => {
+ const urlParams = new URLSearchParams(window.location.search);
+ const dateFromUrl = urlParams.get('date');
+ if (dateFromUrl && dateFromUrl !== activePlannerDate) {
+ switchPlannerDate(dateFromUrl, null, false);
+ }
+});
+
// --- Dagdoel & Taken AJAX ---
-const activePlannerDate = '= $selectedDate ?>';
async function saveGoal() {
const focusGoal = document.getElementById('focusGoalInput').value;
@@ -1348,7 +1476,10 @@ async function submitNewTask() {
if (syncOutlook && !data.outlook_synced) {
alert('Let op: De taak is opgeslagen in Fociz, maar kon niet direct naar Microsoft Outlook worden verzonden:\n\n' + (data.outlook_error || 'Controleer uw verbinding in Mijn Profiel.'));
}
- location.reload();
+ toggleAddTaskForm();
+ const titleInput = document.getElementById('newTaskTitle');
+ if (titleInput) titleInput.value = '';
+ switchPlannerDate(activePlannerDate, null, false);
} else {
alert(data.error || 'Fout bij opslaan van de taak');
}
@@ -1528,7 +1659,8 @@ async function submitEditTask() {
});
const data = await res.json();
if (data.success) {
- location.reload();
+ closeEditTaskModal();
+ switchPlannerDate(activePlannerDate, null, false);
} else {
alert(data.error || 'Kon taak niet bijwerken');
if (saveBtn) {
@@ -1599,7 +1731,7 @@ async function quickImportJira(btn, title, jiraKey, url) {
const data = await res.json();
if (data.success) {
btn.innerHTML = '
';
- location.reload();
+ switchPlannerDate(activePlannerDate, null, false);
} else {
btn.innerHTML = originalHtml;
btn.disabled = false;
@@ -1618,7 +1750,7 @@ async function toggleTask(taskId, isCompleted) {
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ task_id: taskId, is_completed: isCompleted })
});
- location.reload();
+ switchPlannerDate(activePlannerDate, null, false);
}
async function deleteTask(taskId) {
@@ -1628,7 +1760,7 @@ async function deleteTask(taskId) {
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ task_id: taskId })
});
- document.getElementById(`task-row-${taskId}`)?.remove();
+ switchPlannerDate(activePlannerDate, null, false);
}
// --- AI Co-Pilot Slimme Dagplanning (Release v1.5) ---
@@ -1652,7 +1784,7 @@ async function aiSmartSchedule(btn) {
if (data.success) {
alert(`Succes! AI Co-Pilot heeft ${data.scheduled_count} ta(a)k(en) optimaal ingepland op je tijdlijn.`);
- location.reload();
+ switchPlannerDate(activePlannerDate, null, false);
} else {
alert(data.error || 'Kon dagplanning niet genereren via AI');
if (btn) {
@@ -1672,10 +1804,7 @@ async function aiSmartSchedule(btn) {
}
// --- Outlook 365 Auto-Sync & Achtergrond Controle ---
const isOutlookConnected = = $isOutlookConnected ? 'true' : 'false' ?>;
-let currentSyncHash = '= $initialSyncHash ?? '' ?>';
const syncIntervalSeconds = = (int)($syncIntervalSeconds ?? 30) ?>;
-const weekStartDate = '= $weekStart ?>';
-const weekEndDate = '= $weekEnd ?>';
let isSyncCheckActive = false;
async function checkOutlookChanges(isManual = false) {
@@ -1708,10 +1837,8 @@ async function checkOutlookChanges(isManual = false) {
if (data.has_changes) {
if (statusText) statusText.innerText = 'Wijzigingen bijwerken...';
- saveTimerStateBeforeReload();
- setTimeout(() => {
- location.reload();
- }, 400);
+ await switchPlannerDate(activePlannerDate, null, false);
+ if (statusText) statusText.innerText = 'Outlook 365 Live';
return;
} else {
currentSyncHash = data.hash;