Refactor code structure for improved readability and maintainability

This commit is contained in:
2026-09-09 16:30:11 +02:00
parent 4cb94d3897
commit 64a7a3bcf0
7 changed files with 235 additions and 133 deletions
+2
View File
@@ -27,6 +27,8 @@ if (empty($_SESSION['user_id']) && $stateUserId) {
$_SESSION['user_email'] = $recoveredUser['email']; $_SESSION['user_email'] = $recoveredUser['email'];
$_SESSION['user_role'] = $recoveredUser['role']; $_SESSION['user_role'] = $recoveredUser['role'];
$_SESSION['is_2fa_verified'] = true; $_SESSION['is_2fa_verified'] = true;
$_SESSION['auth_date'] = date('Y-m-d');
$_SESSION['session_expires_at'] = strtotime('today 23:59:59');
issue_remember_token((int)$recoveredUser['id']); issue_remember_token((int)$recoveredUser['id']);
} }
} catch (Throwable $e) { } catch (Throwable $e) {
+3 -1
View File
@@ -75,12 +75,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$db->commit(); $db->commit();
// Start sessie // Start dagsessie (geldig tot 23:59:59)
$_SESSION['user_id'] = $newUserId; $_SESSION['user_id'] = $newUserId;
$_SESSION['user_name'] = $name; $_SESSION['user_name'] = $name;
$_SESSION['user_email'] = $invite['email']; $_SESSION['user_email'] = $invite['email'];
$_SESSION['user_role'] = $invite['role']; $_SESSION['user_role'] = $invite['role'];
$_SESSION['is_2fa_verified'] = true; $_SESSION['is_2fa_verified'] = true;
$_SESSION['auth_date'] = date('Y-m-d');
$_SESSION['session_expires_at'] = strtotime('today 23:59:59');
issue_remember_token($newUserId); issue_remember_token($newUserId);
unset($_SESSION['invite_totp_secret']); unset($_SESSION['invite_totp_secret']);
+15 -2
View File
@@ -20,6 +20,10 @@ if ($currentUser) {
} }
$error = null; $error = null;
$infoMessage = null;
if (isset($_GET['expired'])) {
$infoMessage = "Uw dagsessie is om 23:59 beëindigd. Log opnieuw in om een nieuwe werkdag te starten.";
}
$step = isset($_SESSION['pending_2fa_user_id']) ? 2 : 1; $step = isset($_SESSION['pending_2fa_user_id']) ? 2 : 1;
// Terug naar stap 1 // Terug naar stap 1
@@ -95,14 +99,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
} }
if ($isValid) { if ($isValid) {
// Volledige login succesvol // Volledige login succesvol (geldig tot 23:59:59 van vandaag)
$_SESSION['user_id'] = $user['id']; $_SESSION['user_id'] = $user['id'];
$_SESSION['user_name'] = $user['name']; $_SESSION['user_name'] = $user['name'];
$_SESSION['user_email'] = $user['email']; $_SESSION['user_email'] = $user['email'];
$_SESSION['user_role'] = $user['role']; $_SESSION['user_role'] = $user['role'];
$_SESSION['is_2fa_verified'] = true; $_SESSION['is_2fa_verified'] = true;
$_SESSION['auth_date'] = date('Y-m-d');
$_SESSION['session_expires_at'] = strtotime('today 23:59:59');
// Activeer persistente remember token (30 dagen blijf ingelogd) // Activeer dagspecifieke remember token (verloopt vannacht om 23:59:59)
issue_remember_token((int)$user['id']); issue_remember_token((int)$user['id']);
unset($_SESSION['pending_2fa_user_id'], $_SESSION['pending_2fa_user_email'], $_SESSION['pending_2fa_user_name']); unset($_SESSION['pending_2fa_user_id'], $_SESSION['pending_2fa_user_email'], $_SESSION['pending_2fa_user_name']);
@@ -178,6 +184,13 @@ $pageTitle = "Fociz — Inloggen";
</p> </p>
</div> </div>
<?php if ($infoMessage): ?>
<div class="mb-6 p-4 rounded-2xl bg-sky-500/10 border border-sky-500/30 flex items-start space-x-3 text-sky-800 dark:text-sky-300 text-xs sm:text-sm">
<i data-lucide="info" class="w-5 h-5 flex-shrink-0 mt-0.5 text-sky-600 dark:text-sky-400"></i>
<span><?= htmlspecialchars($infoMessage) ?></span>
</div>
<?php endif; ?>
<?php if ($error): ?> <?php if ($error): ?>
<div class="mb-6 p-4 rounded-2xl bg-red-500/10 border border-red-500/30 flex items-start space-x-3 text-red-700 dark:text-red-400 text-sm"> <div class="mb-6 p-4 rounded-2xl bg-red-500/10 border border-red-500/30 flex items-start space-x-3 text-red-700 dark:text-red-400 text-sm">
<i data-lucide="alert-triangle" class="w-5 h-5 flex-shrink-0 mt-0.5"></i> <i data-lucide="alert-triangle" class="w-5 h-5 flex-shrink-0 mt-0.5"></i>
+3 -1
View File
@@ -62,12 +62,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$adminId = (int)$db->lastInsertId(); $adminId = (int)$db->lastInsertId();
// Automatische sessie starten // Automatische dagsessie starten (geldig tot 23:59:59)
$_SESSION['user_id'] = $adminId; $_SESSION['user_id'] = $adminId;
$_SESSION['user_name'] = $name; $_SESSION['user_name'] = $name;
$_SESSION['user_email'] = $email; $_SESSION['user_email'] = $email;
$_SESSION['user_role'] = 'ADMIN'; $_SESSION['user_role'] = 'ADMIN';
$_SESSION['is_2fa_verified'] = true; $_SESSION['is_2fa_verified'] = true;
$_SESSION['auth_date'] = date('Y-m-d');
$_SESSION['session_expires_at'] = strtotime('today 23:59:59');
issue_remember_token($adminId); issue_remember_token($adminId);
unset($_SESSION['setup_totp_secret']); unset($_SESSION['setup_totp_secret']);
+42 -11
View File
@@ -30,15 +30,17 @@ function is_https_request(): bool {
function start_secure_session(): void { function start_secure_session(): void {
if (session_status() === PHP_SESSION_NONE) { if (session_status() === PHP_SESSION_NONE) {
// Zorg voor een ruime sessieduur (30 dagen) // Dagsessie: verloopt iedere nacht om 23:59:59 (blijft niet meerdere dagen staan)
ini_set('session.gc_maxlifetime', '2592000'); $secondsUntilMidnight = max(60, strtotime('today 23:59:59') - time());
ini_set('session.cookie_lifetime', '2592000');
ini_set('session.gc_maxlifetime', (string)$secondsUntilMidnight);
ini_set('session.cookie_lifetime', (string)$secondsUntilMidnight);
ini_set('session.use_strict_mode', '1'); ini_set('session.use_strict_mode', '1');
ini_set('session.use_only_cookies', '1'); ini_set('session.use_only_cookies', '1');
$isSecure = is_https_request(); $isSecure = is_https_request();
session_set_cookie_params([ session_set_cookie_params([
'lifetime' => 30 * 24 * 60 * 60, // 30 dagen 'lifetime' => $secondsUntilMidnight, // Verloopt vannacht om 23:59:59
'path' => '/', 'path' => '/',
'domain' => '', 'domain' => '',
'secure' => $isSecure, 'secure' => $isSecure,
@@ -117,12 +119,14 @@ function ensure_theme_column(PDO $db): void {
} }
/** /**
* Genereert en bewaart een persistente 'Onthoud mij' token in MariaDB en plaatst een veilige cookie * Genereert en bewaart een dagspecifieke login token in MariaDB en plaatst een veilige cookie.
* Verloopt altijd dezelfde nacht om 23:59:59 zodat sessies niet meerdere dagen blijven staan.
*/ */
function issue_remember_token(int $userId): string { function issue_remember_token(int $userId): string {
$rawToken = bin2hex(random_bytes(32)); $rawToken = bin2hex(random_bytes(32));
$tokenHash = hash('sha256', $rawToken); $tokenHash = hash('sha256', $rawToken);
$expiresAt = date('Y-m-d H:i:s', time() + (30 * 86400)); // 30 dagen geldig $midnightTs = strtotime('today 23:59:59');
$expiresAt = date('Y-m-d 23:59:59', $midnightTs);
$db = get_db_connection(); $db = get_db_connection();
ensure_remember_token_columns($db); ensure_remember_token_columns($db);
@@ -132,7 +136,7 @@ function issue_remember_token(int $userId): string {
$isSecure = is_https_request(); $isSecure = is_https_request();
setcookie('fociz_remember', $rawToken, [ setcookie('fociz_remember', $rawToken, [
'expires' => time() + (30 * 86400), 'expires' => $midnightTs, // Verloopt vannacht om 23:59:59
'path' => '/', 'path' => '/',
'secure' => $isSecure, 'secure' => $isSecure,
'httponly' => true, 'httponly' => true,
@@ -158,11 +162,33 @@ function clear_remember_cookie(): void {
/** /**
* Haalt de huidige ingelogde gebruiker op uit de database. * Haalt de huidige ingelogde gebruiker op uit de database.
* Herstelt automatisch de sessie als een geldige 'fociz_remember' cookie aanwezig is. * Garandeert dat de sessie strikt om 23:59:59 gereset wordt en nooit meerdere dagen blijft staan.
*/ */
function get_logged_in_user(): ?array { function get_logged_in_user(): ?array {
start_secure_session(); start_secure_session();
$today = date('Y-m-d');
$now = time();
// Controleer of de sessie van een eerdere dag is of voorbij 23:59:59
if (!empty($_SESSION['auth_date']) && $_SESSION['auth_date'] !== $today) {
$_SESSION = [];
clear_remember_cookie();
if (session_status() === PHP_SESSION_ACTIVE) {
@session_regenerate_id(true);
}
return null;
}
if (!empty($_SESSION['session_expires_at']) && $now > (int)$_SESSION['session_expires_at']) {
$_SESSION = [];
clear_remember_cookie();
if (session_status() === PHP_SESSION_ACTIVE) {
@session_regenerate_id(true);
}
return null;
}
$db = get_db_connection(); $db = get_db_connection();
ensure_remember_token_columns($db); ensure_remember_token_columns($db);
@@ -172,13 +198,16 @@ function get_logged_in_user(): ?array {
$stmt->execute([$_SESSION['user_id']]); $stmt->execute([$_SESSION['user_id']]);
$user = $stmt->fetch(); $user = $stmt->fetch();
if ($user) { if ($user) {
$_SESSION['auth_date'] = $today;
$_SESSION['session_expires_at'] = strtotime('today 23:59:59');
return $user; return $user;
} }
// Gebruiker bestaat niet meer in database // Gebruiker bestaat niet meer in database
$_SESSION = []; $_SESSION = [];
clear_remember_cookie();
} }
// 2. Controleer persistente 'remember me' cookie (voorkomt ongewenst uitloggen bij refresh of herstart) // 2. Controleer dagspecifieke cookie (uitsluitend geldig voor vandaag tot 23:59:59)
if (!empty($_COOKIE['fociz_remember'])) { if (!empty($_COOKIE['fociz_remember'])) {
$rawToken = trim($_COOKIE['fociz_remember']); $rawToken = trim($_COOKIE['fociz_remember']);
$tokenHash = hash('sha256', $rawToken); $tokenHash = hash('sha256', $rawToken);
@@ -192,14 +221,16 @@ function get_logged_in_user(): ?array {
$user = $stmt->fetch(); $user = $stmt->fetch();
if ($user) { if ($user) {
// Herstel volledige PHP sessie // Herstel PHP sessie voor de huidige werkdag
$_SESSION['user_id'] = $user['id']; $_SESSION['user_id'] = $user['id'];
$_SESSION['user_name'] = $user['name']; $_SESSION['user_name'] = $user['name'];
$_SESSION['user_email'] = $user['email']; $_SESSION['user_email'] = $user['email'];
$_SESSION['user_role'] = $user['role']; $_SESSION['user_role'] = $user['role'];
$_SESSION['is_2fa_verified'] = true; $_SESSION['is_2fa_verified'] = true;
$_SESSION['auth_date'] = $today;
$_SESSION['session_expires_at'] = strtotime('today 23:59:59');
// Verleng direct de geldigheid van de remember token voor nog eens 30 dagen // Verleng uitsluitend tot 23:59:59 van vandaag
issue_remember_token((int)$user['id']); issue_remember_token((int)$user['id']);
return $user; return $user;
+42
View File
@@ -57,6 +57,21 @@ $currentUserTheme = !empty($currentUser['id']) ? get_user_theme((int)$currentUse
</script> </script>
<!-- Lucide Icons --> <!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script> <script src="https://unpkg.com/lucide@latest"></script>
<!-- Dagsessie Expiratie Watchdog: reset iedere nacht om 23:59:59 -->
<script>
(function() {
try {
const now = new Date();
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
const msUntilMidnight = midnight.getTime() - now.getTime();
if (msUntilMidnight > 0) {
setTimeout(function() {
window.location.href = '/auth/login.php?expired=1';
}, msUntilMidnight);
}
} catch(e) {}
})();
</script>
<style> <style>
html.dark body { html.dark body {
background-color: #0c0f17; background-color: #0c0f17;
@@ -77,6 +92,33 @@ $currentUserTheme = !empty($currentUser['id']) ? get_user_theme((int)$currentUse
html:not(.dark) ::-webkit-scrollbar-track { background: #f8fafc; } html:not(.dark) ::-webkit-scrollbar-track { background: #f8fafc; }
html:not(.dark) ::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; } html:not(.dark) ::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }
html:not(.dark) ::-webkit-scrollbar-thumb:hover { background: #94a3b8; } html:not(.dark) ::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
/* Modern Block & Card Design System */
.fociz-card {
background: rgba(255, 255, 255, 0.95);
border: 1px solid rgba(226, 232, 240, 0.9);
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.04), 0 1px 2px -1px rgba(0, 0, 0, 0.04);
border-radius: 1rem;
backdrop-filter: blur(12px);
transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
html.dark .fociz-card {
background: rgba(17, 22, 34, 0.88);
border: 1px solid rgba(30, 41, 59, 0.7);
box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.35);
}
.fociz-card-interactive {
transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.fociz-card-interactive:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.08), 0 8px 10px -6px rgba(0, 0, 0, 0.06);
border-color: rgba(99, 102, 241, 0.4);
}
html.dark .fociz-card-interactive:hover {
box-shadow: 0 12px 28px -5px rgba(0, 0, 0, 0.5), 0 0 20px rgba(99, 102, 241, 0.15);
border-color: rgba(99, 102, 241, 0.5);
}
</style> </style>
</head> </head>
<body class="min-h-screen flex flex-col antialiased selection:bg-indigo-500 selection:text-white transition-colors duration-150"> <body class="min-h-screen flex flex-col antialiased selection:bg-indigo-500 selection:text-white transition-colors duration-150">
+128 -118
View File
@@ -260,19 +260,19 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<div class="space-y-6 max-w-7xl mx-auto"> <div class="space-y-6 max-w-7xl mx-auto">
<!-- Top Banner: Datum, Hoofddoel & Integraties Status --> <!-- Top Banner: Datum, Hoofddoel & Integraties Status -->
<div class="bg-white dark:bg-slate-900/90 border border-slate-200/80 dark:border-slate-800/60 rounded-2xl p-6 sm:p-7 shadow-xs backdrop-blur-sm transition"> <div class="fociz-card p-6 sm:p-7 relative overflow-hidden">
<div class="flex flex-col lg:flex-row lg:items-center justify-between gap-4"> <div class="flex flex-col lg:flex-row lg:items-center justify-between gap-4">
<div> <div>
<div class="flex items-center space-x-2 text-indigo-600 dark:text-indigo-400 text-xs font-semibold uppercase tracking-wider mb-1"> <div class="flex items-center space-x-2 text-indigo-600 dark:text-indigo-400 text-xs font-bold uppercase tracking-wider mb-1">
<i data-lucide="calendar" class="w-4 h-4"></i> <i data-lucide="calendar" class="w-4 h-4"></i>
<span><?= htmlspecialchars($formattedSelectedDate) ?></span> <span><?= htmlspecialchars($formattedSelectedDate) ?></span>
<?php if ($isTodaySelected): ?> <?php if ($isTodaySelected): ?>
<span class="px-2 py-0.5 rounded-full text-[10px] font-bold bg-indigo-50 text-indigo-700 dark:bg-indigo-500/15 dark:text-indigo-300">VANDAAG</span> <span class="px-2.5 py-0.5 rounded-full text-[10px] font-extrabold bg-indigo-50 text-indigo-700 dark:bg-indigo-500/15 dark:text-indigo-300 ring-1 ring-indigo-500/30">VANDAAG</span>
<?php else: ?> <?php else: ?>
<span class="px-2 py-0.5 rounded-full text-[10px] font-semibold bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400">GEKOZEN DAG</span> <span class="px-2.5 py-0.5 rounded-full text-[10px] font-bold bg-slate-100 dark:bg-slate-800/80 text-slate-600 dark:text-slate-400">GEKOZEN DAG</span>
<?php endif; ?> <?php endif; ?>
</div> </div>
<h1 class="text-2xl sm:text-3xl font-black text-slate-900 dark:text-white tracking-tight"> <h1 class="text-2xl sm:text-3xl font-black tracking-tight text-slate-900 dark:text-white">
Dagplanning & Structuur Dagplanning & Structuur
</h1> </h1>
</div> </div>
@@ -280,28 +280,28 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<!-- Integratie Status Badges --> <!-- Integratie Status Badges -->
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<?php if ($isOutlookConnected): ?> <?php if ($isOutlookConnected): ?>
<div id="outlookSyncBadge" class="flex items-center space-x-2 px-3 py-1.5 rounded-xl bg-sky-50 dark:bg-sky-500/10 border border-sky-200/80 dark:border-sky-500/20 text-sky-800 dark:text-sky-300 text-xs font-medium shadow-2xs transition"> <div id="outlookSyncBadge" class="flex items-center space-x-2 px-3.5 py-1.5 rounded-xl bg-sky-50 dark:bg-sky-500/10 border border-sky-200/80 dark:border-sky-500/20 text-sky-800 dark:text-sky-300 text-xs font-semibold shadow-2xs transition">
<span id="outlookSyncDot" class="w-2 h-2 rounded-full bg-sky-500"></span> <span id="outlookSyncDot" class="w-2 h-2 rounded-full bg-sky-500"></span>
<span id="outlookSyncStatusText">Outlook 365 Live</span> <span id="outlookSyncStatusText">Outlook 365 Live</span>
<span id="outlookLastSyncText" class="text-[10px] text-sky-600/70 dark:text-sky-400/60 font-mono hidden sm:inline">(synced <span id="syncTimeDisplay"><?= date('H:i') ?></span>)</span> <span id="outlookLastSyncText" class="text-[10px] text-sky-600/80 dark:text-sky-400/70 font-mono hidden sm:inline">(synced <span id="syncTimeDisplay"><?= date('H:i') ?></span>)</span>
<button id="manualSyncBtn" onclick="triggerManualSync()" title="Nu handmatig synchroniseren met Outlook" class="p-0.5 hover:bg-sky-100 dark:hover:bg-sky-500/20 text-sky-600 hover:text-sky-900 dark:text-sky-400 dark:hover:text-white rounded transition cursor-pointer"> <button id="manualSyncBtn" onclick="triggerManualSync()" title="Nu handmatig synchroniseren met Outlook" class="p-0.5 hover:bg-sky-100 dark:hover:bg-sky-500/20 text-sky-600 hover:text-sky-900 dark:text-sky-400 dark:hover:text-white rounded transition cursor-pointer">
<i id="manualSyncIcon" data-lucide="refresh-cw" class="w-3 h-3"></i> <i id="manualSyncIcon" data-lucide="refresh-cw" class="w-3 h-3"></i>
</button> </button>
</div> </div>
<?php else: ?> <?php else: ?>
<a href="/profile.php" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800/80 dark:hover:bg-slate-700 border border-slate-200 dark:border-slate-700 text-slate-700 dark:text-slate-300 hover:text-slate-900 dark:hover:text-white text-xs font-medium transition shadow-2xs"> <a href="/profile.php" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800/80 dark:hover:bg-slate-700 border border-slate-200 dark:border-slate-700 text-slate-700 dark:text-slate-300 hover:text-slate-900 dark:hover:text-white text-xs font-semibold transition shadow-2xs">
<i data-lucide="link-2" class="w-3.5 h-3.5 text-sky-500"></i> <i data-lucide="link-2" class="w-3.5 h-3.5 text-sky-500"></i>
<span>Koppel Outlook</span> <span>Koppel Outlook</span>
</a> </a>
<?php endif; ?> <?php endif; ?>
<?php if ($isJiraLive): ?> <?php if ($isJiraLive): ?>
<a href="#jiraPanel" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-slate-100 dark:bg-slate-800/70 border border-slate-200 dark:border-slate-700 text-slate-700 dark:text-slate-300 hover:text-slate-900 dark:hover:text-white text-xs font-medium transition shadow-2xs"> <a href="#jiraPanel" class="flex items-center space-x-1.5 px-3.5 py-1.5 rounded-xl bg-slate-100 dark:bg-slate-800/80 border border-slate-200 dark:border-slate-700 text-slate-700 dark:text-slate-300 hover:text-slate-900 dark:hover:text-white text-xs font-semibold transition shadow-2xs">
<span class="w-2 h-2 rounded-full bg-indigo-500 animate-pulse"></span> <span class="w-2 h-2 rounded-full bg-indigo-500 animate-pulse"></span>
<span>Jira: <?= count($jiraIssues) ?> tickets</span> <span>Jira: <?= count($jiraIssues) ?> tickets</span>
</a> </a>
<?php else: ?> <?php else: ?>
<a href="/profile.php" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800/80 dark:hover:bg-slate-700 border border-slate-200 dark:border-slate-700 text-slate-700 dark:text-slate-300 hover:text-slate-900 dark:hover:text-white text-xs font-medium transition shadow-2xs"> <a href="/profile.php" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800/80 dark:hover:bg-slate-700 border border-slate-200 dark:border-slate-700 text-slate-700 dark:text-slate-300 hover:text-slate-900 dark:hover:text-white text-xs font-semibold transition shadow-2xs">
<i data-lucide="trello" class="w-3.5 h-3.5 text-indigo-500"></i> <i data-lucide="trello" class="w-3.5 h-3.5 text-indigo-500"></i>
<span>Koppel Jira</span> <span>Koppel Jira</span>
</a> </a>
@@ -309,26 +309,32 @@ for ($h = $startHour; $h <= $endHour; $h++) {
</div> </div>
</div> </div>
<!-- Dagdoel invoerveld --> <!-- Dagdoel Focus Spotlight Blok -->
<div class="mt-5 pt-4 border-t border-slate-100 dark:border-slate-800/60"> <div class="mt-6 p-4 sm:p-5 rounded-2xl bg-gradient-to-r from-indigo-500/[0.08] via-sky-500/[0.04] to-transparent dark:from-indigo-500/[0.14] dark:via-sky-500/[0.06] dark:to-transparent border border-indigo-500/20 dark:border-indigo-500/30 shadow-xs relative overflow-hidden">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 uppercase tracking-wider mb-1.5 flex items-center space-x-1.5"> <div class="flex items-center space-x-2 mb-2">
<i data-lucide="target" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i> <div class="w-6 h-6 rounded-lg bg-indigo-600 text-white flex items-center justify-center shadow-xs">
<span>Mijn Belangrijkste Dagdoel voor <?= htmlspecialchars($dutchFullDays[(int)date('N', $selectedTs)]) ?></span> <i data-lucide="target" class="w-3.5 h-3.5"></i>
</label> </div>
<div class="flex items-center space-x-2"> <label for="focusGoalInput" class="text-xs font-bold text-indigo-950 dark:text-indigo-200 uppercase tracking-wider">
<input Focus van de Dag &bull; <?= htmlspecialchars($dutchFullDays[(int)date('N', $selectedTs)]) ?>
type="text" </label>
id="focusGoalInput" </div>
value="<?= htmlspecialchars($dailyPlan['focus_goal'] ?? '') ?>" <div class="flex items-center gap-2">
placeholder="Wat moet er deze dag absoluut gebeuren voor succes?" <div class="relative flex-1">
class="flex-1 bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800 rounded-xl px-4 py-2.5 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-500 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500/30 focus:border-indigo-500 font-medium transition" <input
> type="text"
id="focusGoalInput"
value="<?= htmlspecialchars($dailyPlan['focus_goal'] ?? '') ?>"
placeholder="Wat moet er deze dag absoluut gebeuren voor succes?"
class="w-full bg-white/95 dark:bg-[#0c0f17]/95 border border-slate-200/90 dark:border-slate-800/90 rounded-xl px-4 py-2.5 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-500 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500/40 focus:border-indigo-500 font-medium transition shadow-2xs"
>
</div>
<button <button
onclick="saveGoal()" onclick="saveGoal()"
id="saveGoalBtn" id="saveGoalBtn"
class="px-4 py-2.5 bg-indigo-600 hover:bg-indigo-500 text-white font-semibold text-xs rounded-xl transition flex items-center space-x-1 shadow-sm shadow-indigo-600/20 flex-shrink-0 cursor-pointer" class="px-5 py-2.5 bg-gradient-to-r from-indigo-600 to-indigo-500 hover:from-indigo-500 hover:to-indigo-400 text-white font-semibold text-xs rounded-xl transition flex items-center space-x-1.5 shadow-sm shadow-indigo-600/30 flex-shrink-0 cursor-pointer"
> >
<i data-lucide="check-circle-2" class="w-4 h-4"></i> <i data-lucide="check" class="w-4 h-4 stroke-[2.5]"></i>
<span>Opslaan</span> <span>Opslaan</span>
</button> </button>
</div> </div>
@@ -336,20 +342,20 @@ for ($h = $startHour; $h <= $endHour; $h++) {
</div> </div>
<!-- Week Navigatie & Dagselector --> <!-- Week Navigatie & Dagselector -->
<div class="bg-white dark:bg-slate-900/90 border border-slate-200/80 dark:border-slate-800/60 rounded-2xl p-5 sm:p-6 shadow-xs backdrop-blur-sm transition"> <div class="fociz-card p-5 sm:p-6">
<div class="flex flex-col md:flex-row md:items-center justify-between gap-4 pb-4 mb-4 border-b border-slate-100 dark:border-slate-800/60"> <div class="flex flex-col md:flex-row md:items-center justify-between gap-4 pb-4 mb-4 border-b border-slate-100 dark:border-slate-800/60">
<!-- Navigatie controls --> <!-- Navigatie controls -->
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<a href="planner.php?date=<?= $prevWeekDate ?>" class="flex items-center space-x-1.5 px-3 py-1.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-300 text-xs font-semibold transition shadow-2xs" title="Vorige week (Maandag <?= date('j M', strtotime($prevWeekDate)) ?>)"> <a href="planner.php?date=<?= $prevWeekDate ?>" class="flex items-center space-x-1.5 px-3.5 py-1.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800/80 dark:hover:bg-slate-700/80 text-slate-700 dark:text-slate-300 text-xs font-semibold transition shadow-2xs" title="Vorige week (Maandag <?= date('j M', strtotime($prevWeekDate)) ?>)">
<i data-lucide="chevron-left" class="w-4 h-4"></i> <i data-lucide="chevron-left" class="w-4 h-4"></i>
<span class="hidden sm:inline">Vorige week</span> <span class="hidden sm:inline">Vorige week</span>
</a> </a>
<a href="planner.php?date=<?= $today ?>" class="px-3 py-1.5 rounded-xl <?= $isTodaySelected ? 'bg-slate-900 text-white dark:bg-white dark:text-slate-900 font-bold' : 'bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 font-semibold' ?> text-xs transition shadow-2xs" title="Spring direct naar vandaag"> <a href="planner.php?date=<?= $today ?>" class="px-3.5 py-1.5 rounded-xl <?= $isTodaySelected ? 'bg-slate-900 text-white dark:bg-white dark:text-slate-900 font-bold shadow-xs' : 'bg-slate-100 hover:bg-slate-200 dark:bg-slate-800/80 dark:hover:bg-slate-700/80 text-slate-700 dark:text-slate-300 font-semibold shadow-2xs' ?> text-xs transition" title="Spring direct naar vandaag">
Vandaag Vandaag
</a> </a>
<a href="planner.php?date=<?= $nextWeekDate ?>" class="flex items-center space-x-1.5 px-3 py-1.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-300 text-xs font-semibold transition shadow-2xs" title="Volgende week (Maandag <?= date('j M', strtotime($nextWeekDate)) ?>)"> <a href="planner.php?date=<?= $nextWeekDate ?>" class="flex items-center space-x-1.5 px-3.5 py-1.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800/80 dark:hover:bg-slate-700/80 text-slate-700 dark:text-slate-300 text-xs font-semibold transition shadow-2xs" title="Volgende week (Maandag <?= date('j M', strtotime($nextWeekDate)) ?>)">
<span class="hidden sm:inline">Volgende week</span> <span class="hidden sm:inline">Volgende week</span>
<i data-lucide="chevron-right" class="w-4 h-4"></i> <i data-lucide="chevron-right" class="w-4 h-4"></i>
</a> </a>
@@ -357,7 +363,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<!-- Week Titel & Datumrange --> <!-- Week Titel & Datumrange -->
<div class="text-center md:text-left"> <div class="text-center md:text-left">
<div class="text-xs font-semibold uppercase tracking-wider text-indigo-600 dark:text-indigo-400"> <div class="text-xs font-bold uppercase tracking-wider text-indigo-600 dark:text-indigo-400">
Week <?= $weekNumber ?> &bull; <?= $yearNumber ?> Week <?= $weekNumber ?> &bull; <?= $yearNumber ?>
</div> </div>
<div class="text-base font-black text-slate-900 dark:text-white"> <div class="text-base font-black text-slate-900 dark:text-white">
@@ -373,58 +379,58 @@ for ($h = $startHour; $h <= $endHour; $h++) {
id="jumpDateInput" id="jumpDateInput"
value="<?= htmlspecialchars($selectedDate) ?>" value="<?= htmlspecialchars($selectedDate) ?>"
onchange="if(this.value) window.location.href='planner.php?date=' + this.value;" onchange="if(this.value) window.location.href='planner.php?date=' + this.value;"
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" 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"
> >
</div> </div>
</div> </div>
<!-- 7 Dagen Weekstrook --> <!-- 7 Dagen Weekstrook -->
<div class="grid grid-cols-2 sm:grid-cols-4 md:grid-cols-7 gap-2.5"> <div class="grid grid-cols-2 sm:grid-cols-4 md:grid-cols-7 gap-3">
<?php foreach ($weekDays as $wd): ?> <?php foreach ($weekDays as $wd): ?>
<a <a
href="planner.php?date=<?= $wd['date'] ?>" href="planner.php?date=<?= $wd['date'] ?>"
class="group relative flex flex-col p-3 rounded-xl border transition text-left <?= $wd['is_selected'] class="fociz-card-interactive group relative flex flex-col p-3.5 rounded-2xl border transition-all text-left <?= $wd['is_selected']
? 'bg-indigo-50/80 dark:bg-indigo-500/10 border-indigo-500/40 ring-1 ring-indigo-500/30 shadow-xs' ? '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'
: 'bg-slate-50/70 dark:bg-slate-950/40 border-slate-200/80 dark:border-slate-800/60 hover:border-slate-300 dark:hover:border-slate-700 hover:bg-white dark:hover:bg-slate-900/60 shadow-2xs' ?>" : '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' ?>"
> >
<div class="flex items-center justify-between mb-1.5"> <div class="flex items-center justify-between mb-1.5">
<span class="text-[11px] font-semibold uppercase tracking-wider <?= $wd['is_selected'] ? 'text-indigo-700 dark:text-indigo-400 font-bold' : 'text-slate-500 dark:text-slate-400' ?>"> <span class="text-[11px] font-bold uppercase tracking-wider <?= $wd['is_selected'] ? 'text-indigo-600 dark:text-indigo-400' : 'text-slate-500 dark:text-slate-400' ?>">
<?= $wd['short_name'] ?> <?= $wd['short_name'] ?>
</span> </span>
<?php if ($wd['is_today']): ?> <?php if ($wd['is_today']): ?>
<span class="px-1.5 py-0.5 rounded-full text-[9px] font-bold uppercase bg-indigo-600 text-white"> <span class="px-2 py-0.5 rounded-full text-[9px] font-extrabold uppercase bg-indigo-600 text-white shadow-xs">
Nu Nu
</span> </span>
<?php endif; ?> <?php endif; ?>
</div> </div>
<div class="flex items-baseline space-x-1 mb-2"> <div class="flex items-baseline space-x-1.5 mb-3">
<span class="text-xl font-black <?= $wd['is_selected'] ? 'text-indigo-600 dark:text-indigo-400' : 'text-slate-900 dark:text-white' ?>"> <span class="text-2xl font-black <?= $wd['is_selected'] ? 'text-indigo-600 dark:text-indigo-400' : 'text-slate-900 dark:text-white' ?>">
<?= $wd['day_num'] ?> <?= $wd['day_num'] ?>
</span> </span>
<span class="text-[10px] font-medium text-slate-400 dark:text-slate-500"> <span class="text-[11px] font-semibold text-slate-400 dark:text-slate-500 uppercase">
<?= $wd['month_short'] ?> <?= $wd['month_short'] ?>
</span> </span>
</div> </div>
<!-- Indicatoren voor taken en meetings op deze dag --> <!-- Mini chips voor taken en meetings op deze dag -->
<div class="flex flex-col gap-1 mt-auto pt-1.5 border-t border-slate-200/60 dark:border-slate-800/60 text-[10px]"> <div class="flex flex-col gap-1.5 mt-auto pt-2 border-t border-slate-200/60 dark:border-slate-800/60 text-[10px]">
<div class="flex items-center justify-between text-slate-600 dark:text-slate-400"> <div class="flex items-center justify-between px-2 py-1 rounded-lg bg-white/70 dark:bg-slate-900/60 border border-slate-200/50 dark:border-slate-800/50 text-slate-600 dark:text-slate-400">
<span class="flex items-center space-x-1"> <span class="flex items-center space-x-1">
<i data-lucide="check-square" class="w-3 h-3 text-slate-400 dark:text-slate-500"></i> <i data-lucide="check-square" class="w-3 h-3 text-indigo-500"></i>
<span>Taken</span> <span>Taken</span>
</span> </span>
<span class="font-semibold <?= $wd['task_count'] > 0 ? ($wd['completed_count'] === $wd['task_count'] ? 'text-indigo-600 dark:text-indigo-400' : 'text-slate-700 dark:text-slate-300') : 'text-slate-400' ?>"> <span class="font-bold <?= $wd['task_count'] > 0 ? ($wd['completed_count'] === $wd['task_count'] ? 'text-indigo-600 dark:text-indigo-400' : 'text-slate-800 dark:text-slate-200') : 'text-slate-400' ?>">
<?= $wd['completed_count'] ?>/<?= $wd['task_count'] ?> <?= $wd['completed_count'] ?>/<?= $wd['task_count'] ?>
</span> </span>
</div> </div>
<div class="flex items-center justify-between text-slate-600 dark:text-slate-400"> <div class="flex items-center justify-between px-2 py-1 rounded-lg bg-sky-50/70 dark:bg-sky-500/10 border border-sky-200/50 dark:border-sky-500/20 text-sky-800 dark:text-sky-300">
<span class="flex items-center space-x-1"> <span class="flex items-center space-x-1">
<i data-lucide="calendar" class="w-3 h-3 text-sky-500"></i> <i data-lucide="calendar" class="w-3 h-3 text-sky-500"></i>
<span>Agenda</span> <span>Agenda</span>
</span> </span>
<span class="font-semibold <?= $wd['meeting_count'] > 0 ? 'text-sky-600 dark:text-sky-400' : 'text-slate-400' ?>"> <span class="font-bold">
<?= $wd['meeting_count'] ?> <?= $wd['meeting_count'] ?>
</span> </span>
</div> </div>
@@ -440,75 +446,76 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<!-- Linker kolom: Focus Timer & Taken --> <!-- Linker kolom: Focus Timer & Taken -->
<div class="lg:col-span-7 space-y-6 min-w-0"> <div class="lg:col-span-7 space-y-6 min-w-0">
<!-- Focus Modus Timer --> <!-- Focus Modus Timer Workstation -->
<div class="bg-white dark:bg-slate-900/90 border border-slate-200/80 dark:border-slate-800/60 rounded-2xl p-6 shadow-xs relative overflow-hidden backdrop-blur-sm transition"> <div class="fociz-card p-6 sm:p-7 relative overflow-hidden">
<div class="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-4">
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-3">
<div class="w-8 h-8 rounded-xl bg-amber-50 dark:bg-amber-500/10 text-amber-500 flex items-center justify-center font-bold"> <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 font-bold shadow-xs">
<i data-lucide="flame" class="w-4 h-4"></i> <i data-lucide="flame" class="w-5 h-5"></i>
</div> </div>
<div> <div>
<h3 class="text-sm font-bold text-slate-900 dark:text-white uppercase tracking-wider">Focus Modus</h3> <h3 class="text-sm font-bold text-slate-900 dark:text-white uppercase tracking-wider">Focus Modus</h3>
<p class="text-[11px] text-slate-500 dark:text-slate-400">Pomodoro & geconcentreerd werken</p> <p class="text-[11px] text-slate-500 dark:text-slate-400">Pomodoro werkstation & concentratie</p>
</div> </div>
</div> </div>
<div class="flex bg-slate-100 dark:bg-slate-950/80 p-1 rounded-xl border border-slate-200/80 dark:border-slate-800 text-xs"> <div class="flex bg-slate-100/90 dark:bg-[#0c0f17]/90 p-1 rounded-xl border border-slate-200/80 dark:border-slate-800/80 text-xs">
<button onclick="setTimerPreset(<?= (int)$workdaySettings['pomodoro_focus'] ?>)" id="btnPresetFocus" class="px-2.5 py-1 rounded-lg font-semibold bg-indigo-600 text-white shadow-xs transition"><?= (int)$workdaySettings['pomodoro_focus'] ?>m Focus</button> <button onclick="setTimerPreset(<?= (int)$workdaySettings['pomodoro_focus'] ?>)" id="btnPresetFocus" class="px-3 py-1.5 rounded-lg font-bold bg-indigo-600 text-white shadow-xs transition"><?= (int)$workdaySettings['pomodoro_focus'] ?>m Focus</button>
<button onclick="setTimerPreset(<?= (int)$workdaySettings['pomodoro_deep'] ?>)" id="btnPresetDeep" class="px-2.5 py-1 rounded-lg font-medium text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-200 transition"><?= (int)$workdaySettings['pomodoro_deep'] ?>m Deep</button> <button onclick="setTimerPreset(<?= (int)$workdaySettings['pomodoro_deep'] ?>)" id="btnPresetDeep" class="px-3 py-1.5 rounded-lg font-semibold text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-200 transition"><?= (int)$workdaySettings['pomodoro_deep'] ?>m Deep</button>
<button onclick="setTimerPreset(<?= (int)$workdaySettings['pomodoro_break'] ?>)" id="btnPresetBreak" class="px-2.5 py-1 rounded-lg font-medium text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-200 transition"><?= (int)$workdaySettings['pomodoro_break'] ?>m Pauze</button> <button onclick="setTimerPreset(<?= (int)$workdaySettings['pomodoro_break'] ?>)" id="btnPresetBreak" class="px-3 py-1.5 rounded-lg font-semibold text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-200 transition"><?= (int)$workdaySettings['pomodoro_break'] ?>m Pauze</button>
</div> </div>
</div> </div>
<div class="text-center my-6"> <div class="text-center my-6 relative">
<div id="timerDisplay" class="text-5xl sm:text-6xl font-black font-mono tracking-tight text-slate-900 dark:text-white mb-2"><?= sprintf('%02d:00', (int)$workdaySettings['pomodoro_focus']) ?></div> <div id="timerDisplay" class="text-6xl sm:text-7xl font-black font-mono tracking-tight text-slate-900 dark:text-white mb-2"><?= sprintf('%02d:00', (int)$workdaySettings['pomodoro_focus']) ?></div>
<div class="min-h-[22px] text-xs text-slate-500 dark:text-slate-400 truncate max-w-sm mx-auto flex items-center justify-center space-x-1"> <div class="min-h-[26px] text-xs text-slate-500 dark:text-slate-400 truncate max-w-md mx-auto flex items-center justify-center space-x-1.5 px-3.5 py-1 rounded-full bg-slate-100/80 dark:bg-slate-950/80 border border-slate-200/70 dark:border-slate-800/70 w-fit">
<span class="text-indigo-600 dark:text-indigo-400 font-medium">Actieve focus:</span> <span class="w-2 h-2 rounded-full bg-emerald-500 animate-pulse"></span>
<span id="activeTaskDisplay" class="text-slate-800 dark:text-slate-200 font-semibold">Kies een taak hieronder</span> <span class="text-indigo-600 dark:text-indigo-400 font-semibold">Doeltaak:</span>
<span id="activeTaskDisplay" class="text-slate-800 dark:text-slate-200 font-bold truncate max-w-[260px]">Kies een taak hieronder</span>
</div> </div>
<div class="w-full bg-slate-100 dark:bg-slate-950/80 h-1.5 rounded-full overflow-hidden mt-4 border border-slate-200/80 dark:border-slate-800/80"> <div class="w-full bg-slate-100 dark:bg-slate-950 h-2 rounded-full overflow-hidden mt-5 border border-slate-200/80 dark:border-slate-800">
<div id="timerProgress" class="h-full bg-gradient-to-r from-indigo-600 to-sky-400 transition-all duration-300 rounded-full" style="width: 0%"></div> <div id="timerProgress" class="h-full bg-gradient-to-r from-indigo-500 via-sky-500 to-indigo-600 transition-all duration-300 rounded-full shadow-[0_0_12px_rgba(99,102,241,0.35)]" style="width: 0%"></div>
</div> </div>
</div> </div>
<div class="flex items-center justify-center space-x-3"> <div class="flex items-center justify-center space-x-3">
<button id="timerToggleBtn" onclick="toggleTimer()" class="flex items-center space-x-2 px-6 py-2.5 rounded-xl font-semibold text-sm bg-indigo-600 hover:bg-indigo-500 text-white transition shadow-sm shadow-indigo-600/20 cursor-pointer"> <button id="timerToggleBtn" onclick="toggleTimer()" class="flex items-center space-x-2 px-7 py-3 rounded-xl font-bold text-sm bg-gradient-to-r from-indigo-600 to-indigo-500 hover:from-indigo-500 hover:to-indigo-400 text-white transition shadow-md shadow-indigo-600/30 hover:scale-[1.02] active:scale-[0.98] cursor-pointer">
<i data-lucide="play" class="w-4 h-4 fill-current"></i> <i data-lucide="play" class="w-4 h-4 fill-current"></i>
<span id="timerToggleText">Start Focus</span> <span id="timerToggleText">Start Focus</span>
</button> </button>
<button onclick="resetTimer()" class="p-2.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800/80 dark:hover:bg-slate-700 text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-200 transition border border-slate-200 dark:border-slate-700/60 cursor-pointer" title="Reset"> <button onclick="resetTimer()" class="p-3 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800/80 dark:hover:bg-slate-700 text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-100 transition border border-slate-200 dark:border-slate-700/80 cursor-pointer shadow-2xs" title="Reset">
<i data-lucide="rotate-ccw" class="w-4 h-4"></i> <i data-lucide="rotate-ccw" class="w-4 h-4"></i>
</button> </button>
</div> </div>
</div> </div>
<!-- Takenlijst --> <!-- Takenlijst Blok -->
<div class="bg-white dark:bg-slate-900/90 border border-slate-200/80 dark:border-slate-800/60 rounded-2xl p-6 shadow-xs backdrop-blur-sm transition"> <div class="fociz-card p-6 sm:p-7">
<div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-100 dark:border-slate-800/60"> <div class="flex items-center justify-between mb-5 pb-3 border-b border-slate-100 dark:border-slate-800/60">
<div> <div>
<h3 class="text-sm font-bold text-slate-900 dark:text-white uppercase tracking-wider flex items-center space-x-2"> <h3 class="text-sm font-bold text-slate-900 dark:text-white uppercase tracking-wider flex items-center space-x-2">
<span>Dagtaken & Prioriteiten</span> <span>Dagtaken & Prioriteiten</span>
<span class="text-xs font-normal text-slate-500 dark:text-slate-400">(<?= count($tasks) ?>)</span> <span class="px-2 py-0.5 rounded-full text-xs font-bold bg-indigo-50 text-indigo-700 dark:bg-indigo-500/15 dark:text-indigo-300 ring-1 ring-indigo-500/20"><?= count($tasks) ?></span>
</h3> </h3>
</div> </div>
<button onclick="toggleAddTaskForm()" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-semibold transition shadow-sm shadow-indigo-600/20 cursor-pointer"> <button onclick="toggleAddTaskForm()" class="flex items-center space-x-1.5 px-3.5 py-1.5 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-bold transition shadow-sm shadow-indigo-600/25 cursor-pointer">
<i data-lucide="plus" class="w-4 h-4"></i> <i data-lucide="plus" class="w-4 h-4"></i>
<span>Nieuwe Taak</span> <span>Nieuwe Taak</span>
</button> </button>
</div> </div>
<!-- Nieuwe taak formulier (verborgen by default) --> <!-- Nieuwe taak formulier (verborgen by default) -->
<div id="addTaskForm" class="hidden mb-4 p-4 rounded-xl bg-slate-50 dark:bg-slate-950/80 border border-indigo-500/30 space-y-3 transition"> <div id="addTaskForm" class="hidden mb-5 p-5 rounded-2xl bg-slate-50/90 dark:bg-[#0c0f17]/90 border border-indigo-500/30 shadow-xs space-y-3.5 transition">
<div> <div>
<label class="block text-[11px] font-medium text-slate-600 dark:text-slate-400 mb-1">Taaktitel</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Taaktitel</label>
<input type="text" id="newTaskTitle" placeholder="Wat moet er vandaag gedaan worden?" class="w-full bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-2 text-slate-900 dark:text-white text-xs placeholder-slate-400 dark:placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"> <input type="text" id="newTaskTitle" placeholder="Wat moet er vandaag gedaan worden?" class="w-full bg-white dark:bg-[#111624] border border-slate-300 dark:border-slate-800 rounded-xl px-3.5 py-2 text-slate-900 dark:text-white text-xs placeholder-slate-400 dark:placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-indigo-500">
</div> </div>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3"> <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3">
<div> <div>
<label class="block text-[11px] font-semibold text-slate-700 dark:text-slate-300 mb-1">Prioriteit</label> <label class="block text-[11px] font-semibold text-slate-700 dark:text-slate-300 mb-1">Prioriteit</label>
<select id="newTaskPriority" class="w-full bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-800 rounded-xl px-2.5 py-1.5 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500"> <select id="newTaskPriority" class="w-full bg-white dark:bg-[#111624] border border-slate-300 dark:border-slate-800 rounded-xl px-2.5 py-2 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500">
<option value="P1">P1 - Brandend / Focus</option> <option value="P1">P1 - Brandend / Focus</option>
<option value="P2" selected>P2 - Belangrijk (Standaard)</option> <option value="P2" selected>P2 - Belangrijk (Standaard)</option>
<option value="P3">P3 - Regulier / Lage druk</option> <option value="P3">P3 - Regulier / Lage druk</option>
@@ -517,8 +524,8 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<div> <div>
<label class="block text-[11px] font-semibold text-slate-700 dark:text-slate-300 mb-1">Starttijd</label> <label class="block text-[11px] font-semibold text-slate-700 dark:text-slate-300 mb-1">Starttijd</label>
<div class="relative"> <div class="relative">
<input type="text" id="newTaskTime" placeholder="Bijv. 09:30" class="w-full bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-800 rounded-xl pl-2.5 pr-7 py-1.5 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500" oninput="onNewTaskTimeOrDurationChange('start')"> <input type="text" id="newTaskTime" placeholder="Bijv. 09:30" class="w-full bg-white dark:bg-[#111624] border border-slate-300 dark:border-slate-800 rounded-xl pl-3 pr-7 py-2 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500" oninput="onNewTaskTimeOrDurationChange('start')">
<i data-lucide="clock" class="w-3.5 h-3.5 text-slate-400 absolute right-2.5 top-2 pointer-events-none"></i> <i data-lucide="clock" class="w-3.5 h-3.5 text-slate-400 absolute right-2.5 top-2.5 pointer-events-none"></i>
</div> </div>
</div> </div>
<div> <div>
@@ -527,8 +534,8 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<span class="text-[9px] text-indigo-600 dark:text-indigo-400 font-medium">Vrij invulbaar</span> <span class="text-[9px] text-indigo-600 dark:text-indigo-400 font-medium">Vrij invulbaar</span>
</div> </div>
<div class="relative"> <div class="relative">
<input type="text" id="newTaskEndTime" placeholder="Bijv. 09:40" class="w-full bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-800 rounded-xl pl-2.5 pr-7 py-1.5 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500" oninput="onNewTaskTimeOrDurationChange('end')"> <input type="text" id="newTaskEndTime" placeholder="Bijv. 09:40" class="w-full bg-white dark:bg-[#111624] border border-slate-300 dark:border-slate-800 rounded-xl pl-3 pr-7 py-2 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500" oninput="onNewTaskTimeOrDurationChange('end')">
<i data-lucide="clock-arrow-down" class="w-3.5 h-3.5 text-slate-400 absolute right-2.5 top-2 pointer-events-none"></i> <i data-lucide="clock-arrow-down" class="w-3.5 h-3.5 text-slate-400 absolute right-2.5 top-2.5 pointer-events-none"></i>
</div> </div>
</div> </div>
<div> <div>
@@ -540,7 +547,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<?php <?php
$defDuration = (int)($workdaySettings['default_task_duration'] ?? 30); $defDuration = (int)($workdaySettings['default_task_duration'] ?? 30);
?> ?>
<select id="newTaskDuration" class="w-full bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-800 rounded-xl px-2.5 py-1.5 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500" onchange="onNewTaskTimeOrDurationChange('duration')"> <select id="newTaskDuration" class="w-full bg-white dark:bg-[#111624] border border-slate-300 dark:border-slate-800 rounded-xl px-2.5 py-2 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500" onchange="onNewTaskTimeOrDurationChange('duration')">
<option value="5" <?= $defDuration === 5 ? 'selected' : '' ?>>5 minuten</option> <option value="5" <?= $defDuration === 5 ? 'selected' : '' ?>>5 minuten</option>
<option value="10" <?= $defDuration === 10 ? 'selected' : '' ?>>10 minuten</option> <option value="10" <?= $defDuration === 10 ? 'selected' : '' ?>>10 minuten</option>
<option value="15" <?= $defDuration === 15 ? 'selected' : '' ?>>15 minuten</option> <option value="15" <?= $defDuration === 15 ? 'selected' : '' ?>>15 minuten</option>
@@ -553,16 +560,16 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<option value="120" <?= $defDuration === 120 ? 'selected' : '' ?>>120 minuten (2 uur)</option> <option value="120" <?= $defDuration === 120 ? 'selected' : '' ?>>120 minuten (2 uur)</option>
<option value="custom">Aangepast...</option> <option value="custom">Aangepast...</option>
</select> </select>
<input type="number" id="newTaskCustomDuration" min="1" max="720" placeholder="Min" class="hidden w-20 bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-800 rounded-xl px-2 py-1.5 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500" oninput="onNewTaskTimeOrDurationChange('custom_duration')"> <input type="number" id="newTaskCustomDuration" min="1" max="720" placeholder="Min" class="hidden w-20 bg-white dark:bg-[#111624] border border-slate-300 dark:border-slate-800 rounded-xl px-2 py-2 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500" oninput="onNewTaskTimeOrDurationChange('custom_duration')">
</div> </div>
</div> </div>
</div> </div>
<?php if ($isOutlookConnected): ?> <?php if ($isOutlookConnected): ?>
<div class="p-2.5 rounded-xl bg-sky-50/70 dark:bg-sky-950/30 border border-sky-200/70 dark:border-sky-800/40"> <div class="p-3 rounded-xl bg-sky-50/80 dark:bg-sky-950/40 border border-sky-200/70 dark:border-sky-800/50">
<label class="flex items-center space-x-2 text-xs text-sky-900 dark:text-sky-200 cursor-pointer select-none"> <label class="flex items-center space-x-2 text-xs text-sky-900 dark:text-sky-200 cursor-pointer select-none">
<input type="checkbox" id="newTaskSyncOutlook" checked class="w-4 h-4 rounded text-indigo-600 focus:ring-indigo-500 border-slate-300 dark:border-slate-700"> <input type="checkbox" id="newTaskSyncOutlook" checked class="w-4 h-4 rounded text-indigo-600 focus:ring-indigo-500 border-slate-300 dark:border-slate-700">
<span class="flex items-center space-x-1.5 font-medium"> <span class="flex items-center space-x-1.5 font-semibold">
<i data-lucide="calendar" class="w-3.5 h-3.5 text-sky-500"></i> <i data-lucide="calendar" class="w-3.5 h-3.5 text-sky-500"></i>
<span>Direct inplannen in Microsoft Outlook agenda</span> <span>Direct inplannen in Microsoft Outlook agenda</span>
</span> </span>
@@ -571,20 +578,22 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<?php endif; ?> <?php endif; ?>
<div class="flex space-x-2 pt-1"> <div class="flex space-x-2 pt-1">
<button onclick="submitNewTask()" class="px-4 py-1.5 bg-indigo-600 hover:bg-indigo-500 text-white font-semibold rounded-lg text-xs transition cursor-pointer">Opslaan</button> <button onclick="submitNewTask()" class="px-5 py-2 bg-indigo-600 hover:bg-indigo-500 text-white font-bold rounded-xl text-xs transition cursor-pointer shadow-xs">Opslaan</button>
<button onclick="toggleAddTaskForm()" class="px-3 py-1.5 bg-slate-200 hover:bg-slate-300 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-400 rounded-lg text-xs transition cursor-pointer">Annuleren</button> <button onclick="toggleAddTaskForm()" class="px-4 py-2 bg-slate-200 hover:bg-slate-300 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-400 rounded-xl text-xs transition cursor-pointer">Annuleren</button>
</div> </div>
</div> </div>
<!-- Taken weergave --> <!-- Taken weergave -->
<div class="space-y-2" id="tasksContainer"> <div class="space-y-2.5" id="tasksContainer">
<?php if (empty($tasks)): ?> <?php if (empty($tasks)): ?>
<div class="text-center py-8 text-slate-400 dark:text-slate-500 text-xs"> <div class="text-center py-10 text-slate-400 dark:text-slate-500 text-xs">
Nog geen taken gepland voor <?= htmlspecialchars($formattedSelectedDate) ?>. Klik op 'Nieuwe Taak' of importeer een Jira ticket hieronder. <i data-lucide="check-circle" class="w-8 h-8 text-slate-300 dark:text-slate-700 mx-auto mb-2"></i>
<p>Nog geen taken gepland voor <?= htmlspecialchars($formattedSelectedDate) ?>.</p>
<p class="text-[11px] mt-0.5">Klik op 'Nieuwe Taak' of importeer een Jira ticket hieronder.</p>
</div> </div>
<?php else: ?> <?php else: ?>
<?php foreach ($tasks as $task): ?> <?php foreach ($tasks as $task): ?>
<div class="group flex items-center justify-between p-3 rounded-xl border <?= $task['is_completed'] ? 'bg-slate-50/50 dark:bg-slate-950/30 border-slate-200 dark:border-slate-900 opacity-60' : 'bg-white dark:bg-slate-950/40 border-slate-200/80 dark:border-slate-800/70 hover:border-slate-300 dark:hover:border-slate-700' ?> transition shadow-2xs" id="task-row-<?= $task['id'] ?>"> <div class="fociz-card-interactive group flex items-center justify-between p-3.5 rounded-2xl border <?= $task['is_completed'] ? 'bg-slate-50/50 dark:bg-slate-950/25 border-slate-200/60 dark:border-slate-800/40 opacity-60' : 'bg-white/95 dark:bg-[#111624]/90 border-slate-200/80 dark:border-slate-800/80 hover:border-indigo-400 dark:hover:border-indigo-500/50 shadow-2xs hover:shadow-xs' ?> <?= $task['priority'] === 'P1' ? 'border-l-4 border-l-rose-500' : ($task['priority'] === 'P2' ? 'border-l-4 border-l-amber-500' : 'border-l-4 border-l-indigo-400 dark:border-l-indigo-500') ?> transition min-w-0" id="task-row-<?= $task['id'] ?>">
<div class="flex items-center space-x-3 truncate mr-2"> <div class="flex items-center space-x-3 truncate mr-2">
<button onclick="toggleTask(<?= $task['id'] ?>, <?= $task['is_completed'] ? 0 : 1 ?>)" class="w-5 h-5 rounded-lg border flex items-center justify-center transition <?= $task['is_completed'] ? 'bg-indigo-600 border-indigo-600 text-white font-bold' : 'border-slate-300 dark:border-slate-700 hover:border-indigo-500 bg-white dark:bg-slate-900' ?>"> <button onclick="toggleTask(<?= $task['id'] ?>, <?= $task['is_completed'] ? 0 : 1 ?>)" class="w-5 h-5 rounded-lg border flex items-center justify-center transition <?= $task['is_completed'] ? 'bg-indigo-600 border-indigo-600 text-white font-bold' : 'border-slate-300 dark:border-slate-700 hover:border-indigo-500 bg-white dark:bg-slate-900' ?>">
<?php if ($task['is_completed']): ?> <?php if ($task['is_completed']): ?>
@@ -604,7 +613,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<span>OUTLOOK</span> <span>OUTLOOK</span>
</span> </span>
<?php endif; ?> <?php endif; ?>
<span class="text-xs font-medium truncate <?= $task['is_completed'] ? 'line-through text-slate-400 dark:text-slate-500' : 'text-slate-800 dark:text-slate-200' ?>"> <span class="text-xs font-semibold truncate <?= $task['is_completed'] ? 'line-through text-slate-400 dark:text-slate-500' : 'text-slate-800 dark:text-slate-200' ?>">
<?= htmlspecialchars($task['title']) ?> <?= htmlspecialchars($task['title']) ?>
</span> </span>
</div> </div>
@@ -668,19 +677,19 @@ for ($h = $startHour; $h <= $endHour; $h++) {
</div> </div>
<!-- Jira Snelle Import Widget --> <!-- Jira Snelle Import Widget -->
<div id="jiraPanel" class="bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-6 shadow-xs backdrop-blur-sm transition"> <div id="jiraPanel" class="fociz-card p-6">
<div class="flex items-center justify-between pb-3 border-b border-slate-100 dark:border-slate-800 mb-3"> <div class="flex items-center justify-between pb-3 border-b border-slate-100 dark:border-slate-800 mb-3">
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<i data-lucide="trello" class="w-4 h-4 text-sky-500"></i> <i data-lucide="trello" class="w-4 h-4 text-sky-500"></i>
<h3 class="text-xs font-semibold text-slate-900 dark:text-white uppercase tracking-wider"> <h3 class="text-xs font-bold text-slate-900 dark:text-white uppercase tracking-wider">
Mijn Jira Tickets Mijn Jira Tickets
</h3> </h3>
<span class="px-2 py-0.5 rounded-full text-[10px] font-semibold <?= $isJiraLive ? 'bg-sky-50 dark:bg-sky-500/15 text-sky-700 dark:text-sky-400 border border-sky-200 dark:border-sky-500/30' : 'bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400' ?>"> <span class="px-2 py-0.5 rounded-full text-[10px] font-bold <?= $isJiraLive ? 'bg-sky-50 dark:bg-sky-500/15 text-sky-700 dark:text-sky-400 border border-sky-200 dark:border-sky-500/30' : 'bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400' ?>">
<?= count($jiraIssues) ?> <?= count($jiraIssues) ?>
</span> </span>
</div> </div>
<a href="/profile.php" class="text-xs text-slate-500 dark:text-slate-400 hover:text-indigo-600 dark:hover:text-indigo-400 transition flex items-center space-x-1"> <a href="/profile.php" class="text-xs text-slate-500 dark:text-slate-400 hover:text-indigo-600 dark:hover:text-indigo-400 transition flex items-center space-x-1 font-medium">
<span>Beheren</span> <span>Beheren</span>
<i data-lucide="chevron-right" class="w-3.5 h-3.5"></i> <i data-lucide="chevron-right" class="w-3.5 h-3.5"></i>
</a> </a>
@@ -693,7 +702,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<?php else: ?> <?php else: ?>
<div class="space-y-2 max-h-64 overflow-y-auto pr-1"> <div class="space-y-2 max-h-64 overflow-y-auto pr-1">
<?php foreach (array_slice($jiraIssues, 0, 6) as $issue): ?> <?php foreach (array_slice($jiraIssues, 0, 6) as $issue): ?>
<div class="flex items-center justify-between p-2.5 rounded-xl bg-slate-50/70 dark:bg-slate-900/60 border border-slate-200/80 dark:border-slate-800/80 hover:border-slate-300 dark:hover:border-slate-700 transition shadow-xs"> <div class="fociz-card-interactive flex items-center justify-between p-2.5 rounded-xl bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-200/80 dark:border-slate-800/80 hover:border-indigo-300 dark:hover:border-indigo-600/50 transition shadow-2xs">
<div class="truncate mr-2"> <div class="truncate mr-2">
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<span class="font-mono text-[10px] font-bold text-sky-700 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-1.5 py-0.5 rounded"> <span class="font-mono text-[10px] font-bold text-sky-700 dark:text-sky-400 bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 px-1.5 py-0.5 rounded">
@@ -723,28 +732,28 @@ for ($h = $startHour; $h <= $endHour; $h++) {
</div> </div>
<!-- Dagnotities & Reflectie --> <!-- Dagnotities & Reflectie -->
<div class="bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-6 shadow-xs backdrop-blur-sm transition"> <div class="fociz-card p-6">
<div class="flex items-center space-x-2 mb-3"> <div class="flex items-center space-x-2 mb-3">
<i data-lucide="book-open" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i> <i data-lucide="book-open" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
<h3 class="text-xs font-semibold text-slate-900 dark:text-white uppercase tracking-wider">Dagnotities & Kladblok</h3> <h3 class="text-xs font-bold text-slate-900 dark:text-white uppercase tracking-wider">Dagnotities & Kladblok</h3>
</div> </div>
<textarea <textarea
id="dailyNotesInput" id="dailyNotesInput"
rows="3" rows="3"
placeholder="Belangrijke aantekeningen, reflecties of snelle memo's voor vandaag..." placeholder="Belangrijke aantekeningen, reflecties of snelle memo's voor vandaag..."
onblur="saveGoal()" onblur="saveGoal()"
class="w-full bg-slate-50/70 dark:bg-slate-900/60 border border-slate-200 dark:border-slate-800 rounded-xl p-3 text-slate-900 dark:text-white text-xs placeholder-slate-400 dark:placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 resize-none transition" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-200 dark:border-slate-800 rounded-xl p-3 text-slate-900 dark:text-white text-xs placeholder-slate-400 dark:placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 resize-none transition shadow-2xs"
><?= htmlspecialchars($dailyPlan['notes'] ?? '') ?></textarea> ><?= htmlspecialchars($dailyPlan['notes'] ?? '') ?></textarea>
</div> </div>
</div> </div>
<!-- Rechter kolom: Timeblocking & Outlook Tijdlijn --> <!-- Rechter kolom: Timeblocking & Outlook Tijdlijn -->
<div class="lg:col-span-5 space-y-6 min-w-0"> <div class="lg:col-span-5 space-y-6 min-w-0">
<div class="bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-5 sm:p-6 shadow-xs backdrop-blur-sm transition overflow-hidden"> <div class="fociz-card p-5 sm:p-6 overflow-hidden">
<div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-100 dark:border-slate-800"> <div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-100 dark:border-slate-800">
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<i data-lucide="clock" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i> <i data-lucide="clock" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
<h3 class="text-xs font-semibold text-slate-900 dark:text-white uppercase tracking-wider">Tijdlijn & Time-blocking</h3> <h3 class="text-xs font-bold text-slate-900 dark:text-white uppercase tracking-wider">Tijdlijn & Time-blocking</h3>
</div> </div>
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<?php if ($aiSettings['ai_enabled'] && $aiSettings['has_key']): ?> <?php if ($aiSettings['ai_enabled'] && $aiSettings['has_key']): ?>
@@ -754,7 +763,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
</button> </button>
<?php endif; ?> <?php endif; ?>
<?php if ($isOutlookConnected): ?> <?php if ($isOutlookConnected): ?>
<span class="px-2 py-0.5 rounded bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 text-sky-700 dark:text-sky-400 text-[10px] font-semibold">Outlook 365</span> <span class="px-2 py-0.5 rounded-lg bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 text-sky-700 dark:text-sky-400 text-[10px] font-semibold">Outlook 365</span>
<?php endif; ?> <?php endif; ?>
<span class="text-xs text-slate-500 dark:text-slate-400 font-mono"><?= $hours[0] ?> – <?= end($hours) ?></span> <span class="text-xs text-slate-500 dark:text-slate-400 font-mono"><?= $hours[0] ?> – <?= end($hours) ?></span>
</div> </div>
@@ -777,16 +786,16 @@ for ($h = $startHour; $h <= $endHour; $h++) {
}); });
?> ?>
<div class="flex items-start group min-h-[48px] border-b border-slate-100 dark:border-slate-800/40 pb-2.5 last:border-0 min-w-0"> <div class="flex items-start group min-h-[48px] border-b border-slate-100 dark:border-slate-800/40 pb-2.5 last:border-0 min-w-0">
<div class="w-12 sm:w-14 text-xs font-mono font-medium text-slate-500 dark:text-slate-400 pt-1 flex-shrink-0"> <div class="w-12 sm:w-14 text-xs font-mono font-semibold text-slate-500 dark:text-slate-400 pt-1.5 flex-shrink-0">
<?= $hour ?> <?= $hour ?>
</div> </div>
<div class="flex-1 space-y-1.5 min-w-0"> <div class="flex-1 space-y-1.5 min-w-0">
<?php if ($isLunchSlot): ?> <?php if ($isLunchSlot): ?>
<!-- Automatische Lunchpauze Reservering (Release v1.4) --> <!-- Automatische Lunchpauze Reservering (Release v1.4) -->
<div class="p-2.5 rounded-xl bg-amber-50/80 dark:bg-amber-950/25 border border-amber-200/80 dark:border-amber-800/40 text-amber-950 dark:text-amber-200 text-xs shadow-xs flex items-center justify-between min-w-0"> <div class="p-3 rounded-xl bg-amber-500/10 dark:bg-amber-500/15 border-l-4 border-l-amber-500 border border-amber-500/20 text-amber-900 dark:text-amber-200 text-xs shadow-2xs flex items-center justify-between min-w-0 transition-all">
<div class="flex items-center space-x-2.5 min-w-0"> <div class="flex items-center space-x-2.5 min-w-0">
<span class="px-2 py-0.5 rounded-md bg-amber-500/15 text-amber-800 dark:text-amber-300 font-mono text-[10px] font-bold flex-shrink-0"> <span class="px-2 py-0.5 rounded-md bg-amber-500/20 text-amber-900 dark:text-amber-200 font-mono text-[10px] font-bold flex-shrink-0">
<?= htmlspecialchars($lunchStart) ?> - <?= htmlspecialchars($lunchEnd) ?> <?= htmlspecialchars($lunchStart) ?> - <?= htmlspecialchars($lunchEnd) ?>
</span> </span>
<span class="font-semibold text-xs flex items-center space-x-1.5 truncate"> <span class="font-semibold text-xs flex items-center space-x-1.5 truncate">
@@ -800,7 +809,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<!-- Outlook meetings --> <!-- Outlook meetings -->
<?php foreach ($slotEvents as $evt): ?> <?php foreach ($slotEvents as $evt): ?>
<div class="p-2.5 rounded-xl bg-sky-50/80 dark:bg-sky-950/30 border border-sky-200/80 dark:border-sky-800/40 text-sky-950 dark:text-sky-100 text-xs shadow-xs min-w-0 overflow-hidden"> <div class="p-3 rounded-xl bg-sky-500/[0.07] dark:bg-sky-500/[0.12] border-l-4 border-l-sky-500 border border-sky-500/20 text-sky-950 dark:text-sky-100 text-xs shadow-2xs min-w-0 overflow-hidden transition-all hover:bg-sky-500/[0.10] dark:hover:bg-sky-500/[0.16]">
<div class="flex items-start justify-between gap-2.5 min-w-0"> <div class="flex items-start justify-between gap-2.5 min-w-0">
<div class="flex items-start space-x-2 min-w-0 flex-1"> <div class="flex items-start space-x-2 min-w-0 flex-1">
<span class="px-2 py-0.5 rounded-md bg-sky-500/15 text-sky-800 dark:text-sky-300 font-mono text-[10px] font-bold flex-shrink-0 whitespace-nowrap mt-0.5"> <span class="px-2 py-0.5 rounded-md bg-sky-500/15 text-sky-800 dark:text-sky-300 font-mono text-[10px] font-bold flex-shrink-0 whitespace-nowrap mt-0.5">
@@ -829,7 +838,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<!-- Geplande taken --> <!-- Geplande taken -->
<?php foreach ($slotTasks as $t): ?> <?php foreach ($slotTasks as $t): ?>
<div class="p-2.5 rounded-xl border text-xs min-w-0 overflow-hidden transition <?= $t['is_completed'] ? 'bg-slate-50 dark:bg-slate-900/40 border-slate-200 dark:border-slate-800 text-slate-400 dark:text-slate-500 line-through' : 'bg-white dark:bg-[#111622] border-slate-200/80 dark:border-slate-800 text-slate-900 dark:text-slate-100 shadow-xs' ?>"> <div class="p-3 rounded-xl border-l-4 <?= $t['priority'] === 'P1' ? 'border-l-rose-500' : ($t['priority'] === 'P2' ? 'border-l-amber-500' : 'border-l-indigo-400') ?> <?= $t['is_completed'] ? 'bg-slate-100/60 dark:bg-slate-900/40 border border-slate-200 dark:border-slate-800 text-slate-400 dark:text-slate-500 line-through' : 'bg-white/80 dark:bg-[#0c0f17]/70 border border-slate-200/90 dark:border-slate-800 text-slate-900 dark:text-slate-100 shadow-2xs hover:shadow-xs' ?> text-xs min-w-0 overflow-hidden transition-all">
<div class="flex items-start justify-between gap-2.5 min-w-0"> <div class="flex items-start justify-between gap-2.5 min-w-0">
<div class="flex items-start space-x-2 min-w-0 flex-1"> <div class="flex items-start space-x-2 min-w-0 flex-1">
<span class="px-2 py-0.5 rounded-md bg-indigo-50 dark:bg-indigo-500/10 text-indigo-700 dark:text-indigo-300 border border-indigo-200 dark:border-indigo-500/20 font-mono text-[10px] font-bold flex-shrink-0 whitespace-nowrap mt-0.5"> <span class="px-2 py-0.5 rounded-md bg-indigo-50 dark:bg-indigo-500/10 text-indigo-700 dark:text-indigo-300 border border-indigo-200 dark:border-indigo-500/20 font-mono text-[10px] font-bold flex-shrink-0 whitespace-nowrap mt-0.5">
@@ -860,8 +869,9 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<?php endforeach; ?> <?php endforeach; ?>
<?php if (empty($slotEvents) && empty($slotTasks) && !$isLunchSlot): ?> <?php if (empty($slotEvents) && empty($slotTasks) && !$isLunchSlot): ?>
<button onclick="quickSchedule('<?= $hour ?>')" class="w-full text-left py-1.5 px-2.5 rounded-xl border border-dashed border-slate-200 dark:border-slate-800 hover:border-indigo-300 dark:hover:border-indigo-700/60 hover:bg-indigo-50/40 dark:hover:bg-indigo-950/20 text-slate-400 dark:text-slate-500 hover:text-indigo-600 dark:hover:text-indigo-400 text-xs transition cursor-pointer"> <button onclick="quickSchedule('<?= $hour ?>')" class="w-full text-left py-2 px-3 rounded-xl border border-dashed border-slate-200 dark:border-slate-800/80 hover:border-indigo-400 dark:hover:border-indigo-500/50 hover:bg-indigo-500/[0.04] dark:hover:bg-indigo-500/[0.08] text-slate-400 dark:text-slate-500 hover:text-indigo-600 dark:hover:text-indigo-400 text-xs font-medium transition flex items-center justify-between group/slot cursor-pointer">
+ Plan taak om <?= $hour ?> <span>+ Plan taak om <?= $hour ?></span>
<i data-lucide="plus" class="w-3.5 h-3.5 opacity-0 group-hover/slot:opacity-100 transition-opacity"></i>
</button> </button>
<?php endif; ?> <?php endif; ?>
</div> </div>
@@ -874,8 +884,8 @@ for ($h = $startHour; $h <= $endHour; $h++) {
</div> </div>
<!-- Modal: Taak & Tijdblok Bewerken (Vrij invullen van tijden & duur) --> <!-- Modal: Taak & Tijdblok Bewerken (Vrij invullen van tijden & duur) -->
<div id="editTaskModal" class="fixed inset-0 z-50 bg-slate-900/60 backdrop-blur-xs hidden items-center justify-center p-4"> <div id="editTaskModal" class="fixed inset-0 z-50 bg-slate-950/70 backdrop-blur-sm hidden items-center justify-center p-4">
<div class="bg-white dark:bg-[#111622] border border-slate-200/90 dark:border-slate-800 rounded-2xl p-6 w-full max-w-lg shadow-2xl space-y-4"> <div class="fociz-card p-6 w-full max-w-lg shadow-2xl space-y-4">
<div class="flex items-center justify-between pb-3 border-b border-slate-100 dark:border-slate-800/80"> <div class="flex items-center justify-between pb-3 border-b border-slate-100 dark:border-slate-800/80">
<div class="flex items-center space-x-2.5"> <div class="flex items-center space-x-2.5">
<div class="w-8 h-8 rounded-xl bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 text-indigo-600 dark:text-indigo-400 flex items-center justify-center"> <div class="w-8 h-8 rounded-xl bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 text-indigo-600 dark:text-indigo-400 flex items-center justify-center">
@@ -895,13 +905,13 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Taaktitel</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Taaktitel</label>
<input type="text" id="editTaskTitle" class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-2 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500"> <input type="text" id="editTaskTitle" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-2 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs">
</div> </div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3"> <div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Prioriteit</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Prioriteit</label>
<select id="editTaskPriority" class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl px-2.5 py-2 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500"> <select id="editTaskPriority" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-2.5 py-2 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs">
<option value="P1">P1 - Brandend / Focus</option> <option value="P1">P1 - Brandend / Focus</option>
<option value="P2">P2 - Belangrijk (Standaard)</option> <option value="P2">P2 - Belangrijk (Standaard)</option>
<option value="P3">P3 - Regulier / Lage druk</option> <option value="P3">P3 - Regulier / Lage druk</option>
@@ -913,7 +923,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<span id="editTaskDurationDisplay" class="text-[11px] font-mono font-bold text-indigo-600 dark:text-indigo-400">30m</span> <span id="editTaskDurationDisplay" class="text-[11px] font-mono font-bold text-indigo-600 dark:text-indigo-400">30m</span>
</div> </div>
<div class="flex items-center space-x-1.5"> <div class="flex items-center space-x-1.5">
<select id="editTaskDuration" class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl px-2.5 py-2 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500" onchange="onEditTaskTimeOrDurationChange('duration')"> <select id="editTaskDuration" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-2.5 py-2 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs" onchange="onEditTaskTimeOrDurationChange('duration')">
<option value="5">5 minuten</option> <option value="5">5 minuten</option>
<option value="10">10 minuten</option> <option value="10">10 minuten</option>
<option value="15">15 minuten</option> <option value="15">15 minuten</option>
@@ -926,7 +936,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<option value="120">120 minuten (2 uur)</option> <option value="120">120 minuten (2 uur)</option>
<option value="custom">Aangepast...</option> <option value="custom">Aangepast...</option>
</select> </select>
<input type="number" id="editTaskCustomDuration" min="1" max="720" placeholder="Min" class="hidden w-20 bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl px-2 py-2 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500" oninput="onEditTaskTimeOrDurationChange('custom_duration')"> <input type="number" id="editTaskCustomDuration" min="1" max="720" placeholder="Min" class="hidden w-20 bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-2 py-2 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs" oninput="onEditTaskTimeOrDurationChange('custom_duration')">
</div> </div>
</div> </div>
</div> </div>
@@ -935,7 +945,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Starttijd</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Starttijd</label>
<div class="relative"> <div class="relative">
<input type="text" id="editTaskStartTime" placeholder="Bijv. 09:30" class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl pl-3 pr-8 py-2 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500" oninput="onEditTaskTimeOrDurationChange('start')"> <input type="text" id="editTaskStartTime" placeholder="Bijv. 09:30" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl pl-3 pr-8 py-2 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs" oninput="onEditTaskTimeOrDurationChange('start')">
<i data-lucide="clock" class="w-4 h-4 text-slate-400 absolute right-2.5 top-2.5 pointer-events-none"></i> <i data-lucide="clock" class="w-4 h-4 text-slate-400 absolute right-2.5 top-2.5 pointer-events-none"></i>
</div> </div>
</div> </div>
@@ -945,13 +955,13 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<span class="text-[9px] text-indigo-600 dark:text-indigo-400 font-medium">Vrij invulbaar</span> <span class="text-[9px] text-indigo-600 dark:text-indigo-400 font-medium">Vrij invulbaar</span>
</div> </div>
<div class="relative"> <div class="relative">
<input type="text" id="editTaskEndTime" placeholder="Bijv. 09:40" class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl pl-3 pr-8 py-2 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500" oninput="onEditTaskTimeOrDurationChange('end')"> <input type="text" id="editTaskEndTime" placeholder="Bijv. 09:40" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl pl-3 pr-8 py-2 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs" oninput="onEditTaskTimeOrDurationChange('end')">
<i data-lucide="clock-arrow-down" class="w-4 h-4 text-slate-400 absolute right-2.5 top-2.5 pointer-events-none"></i> <i data-lucide="clock-arrow-down" class="w-4 h-4 text-slate-400 absolute right-2.5 top-2.5 pointer-events-none"></i>
</div> </div>
</div> </div>
</div> </div>
<div id="editTaskOutlookNotice" class="hidden p-2.5 rounded-xl bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 text-sky-800 dark:text-sky-300 text-[11px] flex items-center space-x-2"> <div id="editTaskOutlookNotice" class="hidden p-3 rounded-xl bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 text-sky-800 dark:text-sky-300 text-[11px] flex items-center space-x-2">
<i data-lucide="refresh-cw" class="w-3.5 h-3.5 flex-shrink-0"></i> <i data-lucide="refresh-cw" class="w-3.5 h-3.5 flex-shrink-0"></i>
<span>Deze taak is gekoppeld aan Outlook 365. Wijzigingen worden automatisch in uw Outlook agenda gesynchroniseerd.</span> <span>Deze taak is gekoppeld aan Outlook 365. Wijzigingen worden automatisch in uw Outlook agenda gesynchroniseerd.</span>
</div> </div>