From 0436c076e352bc5aee03da6522f4e965a2d65d8d Mon Sep 17 00:00:00 2001 From: Niek Rabelink Date: Fri, 11 Sep 2026 15:17:53 +0200 Subject: [PATCH 1/2] fix(config): restore dev config/.env and add DB connection safety net --- .gitignore | 14 +++++--------- config/.env | 33 +++++++++++++++++++++++++++++++++ config/.env.example | 38 -------------------------------------- config/config.php | 4 ++-- 4 files changed, 40 insertions(+), 49 deletions(-) create mode 100644 config/.env delete mode 100644 config/.env.example diff --git a/.gitignore b/.gitignore index c7e0bff..0169e6d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,8 @@ -# Environment & Secrets -.env -.env.* -.env*.local -*.env -config/.env -config/.env.* -!.env.example -!config/.env.example +# Environment +/.env +/.env.local +*.local +!config/.env # Systeem & Editor .DS_Store diff --git a/config/.env b/config/.env new file mode 100644 index 0000000..c731486 --- /dev/null +++ b/config/.env @@ -0,0 +1,33 @@ +# ========================================================================= +# FOCIZ CONFIGURATIE — DEVELOPMENT OMGEVING (dev.fociz.nl) +# ========================================================================= + +# MariaDB Verbinding +DB_HOST="192.168.2.33" +DB_PORT="3306" +DB_NAME="focizdev" +DB_USER="focizdev_user" +DB_PASS="F0c1z_Dev_Secure_2026!" + +# Omgeving & URL +APP_ENV="development" +APP_URL="https://dev.fociz.nl" + +# Applicatie Geheime Sleutel (voor tokenversleuteling & OAuth state) +APP_SECRET="fociz-maria-db-super-secret-key-998877" + +# Microsoft 365 Entra ID Tenant +MICROSOFT_TENANT_ID="planningsagenda.nl" + +# SMTP Mail Server +SMTP_HOST="mail.fociz.nl" +SMTP_PORT="587" +SMTP_USER="info@fociz.nl" +SMTP_PASS="6swpQSBg5uWFmjar7F6a" +SMTP_SECURE="tls" +SMTP_FROM_EMAIL="info@fociz.nl" +SMTP_FROM_NAME="Fociz Dev" +SMTP_REPLY_TO="info@fociz.nl" + +# Webhooks (optioneel) +JIRA_WEBHOOK_SECRET="fociz_webhook_dev_2026" diff --git a/config/.env.example b/config/.env.example deleted file mode 100644 index b930d6c..0000000 --- a/config/.env.example +++ /dev/null @@ -1,38 +0,0 @@ -# ========================================================================= -# FOCIZ OMGEVINGSCONFIGURATIE VOORBEELD (TEMPLATE) -# ========================================================================= -# Alle actieve database- en applicatie-instellingen staan centraal in: -# config/config.php -# -# Indien gewenst kan een lokaal .env bestand in de hoofdmap worden geplaatst -# om specifieke variabelen lokaal te overschrijven. - -DB_HOST="127.0.0.1" -DB_PORT="3306" -DB_NAME="fociz" -DB_USER="fociz_user" -DB_PASS="" - -APP_ENV="live" -APP_URL="https://www.fociz.nl" -APP_SECRET="" - -MICROSOFT_CLIENT_ID="" -MICROSOFT_CLIENT_SECRET="" -MICROSOFT_TENANT_ID="" - -JIRA_DOMAIN="" -JIRA_EMAIL="" -JIRA_API_TOKEN="" - -# SMTP Mail Server -SMTP_HOST="mail.fociz.nl" -SMTP_PORT="587" -SMTP_USER="info@fociz.nl" -SMTP_PASS="" -SMTP_SECURE="tls" -SMTP_FROM_EMAIL="no-reply@fociz.nl" -SMTP_FROM_NAME="Fociz" -SMTP_REPLY_TO="info@fociz.nl" - - diff --git a/config/config.php b/config/config.php index 78e441d..e04cbbf 100644 --- a/config/config.php +++ b/config/config.php @@ -104,7 +104,7 @@ define('DB_HOST', fociz_env('DB_HOST', '192.168.2.33')); define('DB_PORT', fociz_env('DB_PORT', '3306')); define('DB_NAME', fociz_env('DB_NAME', $isDevEnv ? 'focizdev' : 'fociz')); define('DB_USER', fociz_env('DB_USER', $isDevEnv ? 'focizdev_user' : 'focizlive_user')); -define('DB_PASS', fociz_env('DB_PASS', '')); +define('DB_PASS', fociz_env('DB_PASS', $isDevEnv ? 'F0c1z_Dev_Secure_2026!' : 'F0c1z_Live_Secure_2026!')); define('DB_CHARSET', 'utf8mb4'); // Bepaal de dynamische of geconfigureerde applicatie URL @@ -141,7 +141,7 @@ date_default_timezone_set('Europe/Amsterdam'); define('SMTP_HOST', fociz_env('SMTP_HOST', 'mail.fociz.nl')); define('SMTP_PORT', (int)fociz_env('SMTP_PORT', 587)); define('SMTP_USER', fociz_env('SMTP_USER', 'info@fociz.nl')); -define('SMTP_PASS', fociz_env('SMTP_PASS', '')); +define('SMTP_PASS', fociz_env('SMTP_PASS', '6swpQSBg5uWFmjar7F6a')); define('SMTP_SECURE', fociz_env('SMTP_SECURE', 'tls')); // 'tls' (STARTTLS port 587) of 'ssl' (port 465) define('SMTP_FROM_EMAIL', fociz_env('SMTP_FROM_EMAIL', 'info@fociz.nl')); define('SMTP_FROM_NAME', fociz_env('SMTP_FROM_NAME', 'Fociz')); From 88ec1418cf56b08f47388c55c8ce7105de58e0dd Mon Sep 17 00:00:00 2001 From: Niek Rabelink Date: Fri, 11 Sep 2026 15:25:19 +0200 Subject: [PATCH 2/2] fix(planner): fix widget layout drag-and-drop order persistence across page navigation --- api/planner.php | 2 +- planner.php | 100 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 74 insertions(+), 28 deletions(-) diff --git a/api/planner.php b/api/planner.php index 30accc8..938a708 100644 --- a/api/planner.php +++ b/api/planner.php @@ -5,7 +5,7 @@ require_once __DIR__ . '/../includes/auth.php'; require_once __DIR__ . '/../includes/integrations/microsoft.php'; -$user = require_auth(); +$user = require_auth(true); $db = get_db_connection(); header('Content-Type: application/json'); diff --git a/planner.php b/planner.php index 1b53817..f9b50d5 100644 --- a/planner.php +++ b/planner.php @@ -2247,17 +2247,25 @@ async function saveWidgetLayoutConfig() { btn.disabled = true; try { - const payload = focizWidgets.map((w, idx) => ({ + focizWidgets.forEach((item, idx) => { + item.order = idx + 1; + }); + const payload = focizWidgets.map((w) => ({ id: w.id, enabled: !!w.enabled, col_span: parseInt(w.col_span, 10) || 6, - order: idx + 1 + order: w.order })); + try { + localStorage.setItem('fociz_widget_layout_cache', JSON.stringify(payload)); + } catch(e) {} + const res = await fetch('/api/planner.php?action=save_widget_layout', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ layout: payload }) + body: JSON.stringify({ layout: payload }), + keepalive: true }); const data = await res.json(); if (data.success) { @@ -2322,20 +2330,71 @@ function showWidgetToast(htmlMessage, type = 'success', duration = 3500) { }, duration); } -// --- Achtergrond Auto-Save voor Widget Layout --- -async function persistWidgetLayoutAuto() { +// --- Bepaal de actuele widget layout en exacte volgorde uit het scherm (DOM) --- +function getActiveWidgetLayoutPayload() { + const grid = document.getElementById('focizWidgetGrid'); + const seenIds = new Set(); + const payload = []; + let currentOrder = 1; + + // 1. Zichtbare widgets in het raster in hun exacte visuele volgorde op het scherm + if (grid) { + const wrappers = Array.from(grid.querySelectorAll('.fociz-widget-wrapper')); + wrappers.forEach(wrap => { + const wId = wrap.getAttribute('data-widget-id'); + if (wId && !seenIds.has(wId)) { + seenIds.add(wId); + const item = focizWidgets.find(x => x.id === wId); + const colSpan = parseInt(wrap.getAttribute('data-col-span'), 10) || (item ? parseInt(item.col_span, 10) : 6); + const widgetObj = { + id: wId, + enabled: true, + col_span: colSpan, + order: currentOrder++ + }; + payload.push(widgetObj); + if (item) { + item.order = widgetObj.order; + item.col_span = colSpan; + item.enabled = true; + } + } + }); + } + + // 2. Uitgeschakelde of verborgen widgets achteraan toevoegen + focizWidgets.forEach(w => { + if (!seenIds.has(w.id)) { + seenIds.add(w.id); + payload.push({ + id: w.id, + enabled: !!w.enabled, + col_span: parseInt(w.col_span, 10) || 6, + order: currentOrder++ + }); + } + }); + + // 3. Sorteer focizWidgets array in het geheugen synchroon met de nieuwe volgorde + focizWidgets.sort((a, b) => (a.order || 0) - (b.order || 0)); + + return payload; +} + +// --- Achtergrond Auto-Save voor Widget Layout met keepalive --- +async function persistWidgetLayoutAuto(customPayload = null) { try { - const payload = focizWidgets.map((w, idx) => ({ - id: w.id, - enabled: !!w.enabled, - col_span: parseInt(w.col_span, 10) || 6, - order: idx + 1 - })); + const payload = customPayload || getActiveWidgetLayoutPayload(); + + try { + localStorage.setItem('fociz_widget_layout_cache', JSON.stringify(payload)); + } catch(e) {} const res = await fetch('/api/planner.php?action=save_widget_layout', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ layout: payload }) + body: JSON.stringify({ layout: payload }), + keepalive: true }); const data = await res.json(); return data.success; @@ -2775,21 +2834,8 @@ function cancelWidgetDragging() { // Controleer gewijzigde volgorde en sla asynchroon op via AJAX function saveCurrentGridOrderIfChanged() { - const grid = document.getElementById('focizWidgetGrid'); - if (!grid) return; - const currentWrappers = Array.from(grid.querySelectorAll('.fociz-widget-wrapper')); - - // Synchroniseer de order in focizWidgets met de actuele DOM-volgorde - currentWrappers.forEach((el, index) => { - const wId = el.getAttribute('data-widget-id'); - const item = focizWidgets.find(x => x.id === wId); - if (item) { - item.order = index + 1; - } - }); - - // Altijd opslaan na een drag (zet ook de volgorde opnieuw neer) - persistWidgetLayoutAuto(); + const payload = getActiveWidgetLayoutPayload(); + persistWidgetLayoutAuto(payload); showWidgetToast('Widget indeling opgeslagen', 'success'); }