Compare commits

..

11 Commits

Author SHA1 Message Date
NiekRabelink 9de4c3b1d2 Delete .gitattributes 2026-09-09 14:42:25 +00:00
NiekRabelink 677126e7f6 Update .gitattributes 2026-09-09 14:40:09 +00:00
NiekRabelink 333e9c2451 Update .gitattributes 2026-09-09 14:39:27 +00:00
NiekRabelink ce7b2762df Update .gitignore 2026-09-09 14:39:11 +00:00
NiekRabelink d11f11c2c8 Update .gitignore 2026-09-09 14:38:38 +00:00
NiekRabelink 262a8f8b42 Delete config/env.example 2026-09-09 14:37:11 +00:00
NiekRabelink 68c0d9fe60 Delete config/config.php 2026-09-09 14:37:06 +00:00
NiekRabelink 2b94f3dd46 Upload files to "config" 2026-09-09 14:06:27 +00:00
NiekRabelink 8dbd0b251f Delete config/config.php 2026-09-09 14:06:04 +00:00
NiekRabelink a09d99ea88 Delete config/.env.example 2026-09-09 14:05:59 +00:00
NiekRabelink 434df2754c Merge pull request 'Dev' (#18) from dev into main
Reviewed-on: #18
2026-09-09 14:05:24 +00:00
19 changed files with 548 additions and 578 deletions
-3
View File
@@ -1,3 +0,0 @@
# Zorg dat omgevingsspecifieke bestanden nooit worden overschreven bij merges tussen dev en main
+15 -11
View File
@@ -176,7 +176,7 @@ require_once __DIR__ . '/includes/header.php';
<div class="space-y-8 max-w-7xl mx-auto pb-12"> <div class="space-y-8 max-w-7xl mx-auto pb-12">
<!-- Top Header Banner --> <!-- Top Header Banner -->
<div class="relative overflow-hidden fociz-card p-6 sm:p-8"> <div class="relative overflow-hidden bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-6 sm:p-8 shadow-xs backdrop-blur-xl transition">
<div class="absolute -top-24 -right-24 w-80 h-80 bg-indigo-500/10 rounded-full blur-3xl pointer-events-none"></div> <div class="absolute -top-24 -right-24 w-80 h-80 bg-indigo-500/10 rounded-full blur-3xl pointer-events-none"></div>
<div class="absolute -bottom-24 -left-24 w-80 h-80 bg-sky-500/10 rounded-full blur-3xl pointer-events-none"></div> <div class="absolute -bottom-24 -left-24 w-80 h-80 bg-sky-500/10 rounded-full blur-3xl pointer-events-none"></div>
@@ -217,7 +217,7 @@ require_once __DIR__ . '/includes/header.php';
<!-- Stat kaarten rij --> <!-- Stat kaarten rij -->
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4"> <div class="grid grid-cols-2 lg:grid-cols-4 gap-4">
<div class="fociz-card p-5 flex items-center space-x-4"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-5 flex items-center space-x-4 shadow-xs transition">
<div class="w-12 h-12 rounded-xl bg-indigo-50 dark:bg-indigo-950/40 border border-indigo-200 dark:border-indigo-800/60 flex items-center justify-center text-indigo-600 dark:text-indigo-400 flex-shrink-0"> <div class="w-12 h-12 rounded-xl bg-indigo-50 dark:bg-indigo-950/40 border border-indigo-200 dark:border-indigo-800/60 flex items-center justify-center text-indigo-600 dark:text-indigo-400 flex-shrink-0">
<i data-lucide="users" class="w-6 h-6"></i> <i data-lucide="users" class="w-6 h-6"></i>
</div> </div>
@@ -228,7 +228,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
</div> </div>
<div class="fociz-card p-5 flex items-center space-x-4"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-5 flex items-center space-x-4 shadow-xs transition">
<div class="w-12 h-12 rounded-xl bg-sky-50 dark:bg-sky-950/40 border border-sky-200 dark:border-sky-800/60 flex items-center justify-center text-sky-600 dark:text-sky-400 flex-shrink-0"> <div class="w-12 h-12 rounded-xl bg-sky-50 dark:bg-sky-950/40 border border-sky-200 dark:border-sky-800/60 flex items-center justify-center text-sky-600 dark:text-sky-400 flex-shrink-0">
<i data-lucide="calendar" class="w-6 h-6"></i> <i data-lucide="calendar" class="w-6 h-6"></i>
</div> </div>
@@ -239,7 +239,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
</div> </div>
<div class="fociz-card p-5 flex items-center space-x-4"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-5 flex items-center space-x-4 shadow-xs transition">
<div class="w-12 h-12 rounded-xl bg-indigo-50 dark:bg-indigo-950/40 border border-indigo-200 dark:border-indigo-800/60 flex items-center justify-center text-indigo-600 dark:text-indigo-400 flex-shrink-0"> <div class="w-12 h-12 rounded-xl bg-indigo-50 dark:bg-indigo-950/40 border border-indigo-200 dark:border-indigo-800/60 flex items-center justify-center text-indigo-600 dark:text-indigo-400 flex-shrink-0">
<i data-lucide="check-square" class="w-6 h-6"></i> <i data-lucide="check-square" class="w-6 h-6"></i>
</div> </div>
@@ -250,7 +250,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
</div> </div>
<div class="fociz-card p-5 flex items-center space-x-4"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-5 flex items-center space-x-4 shadow-xs transition">
<div class="w-12 h-12 rounded-xl bg-amber-50 dark:bg-amber-950/40 border border-amber-200 dark:border-amber-800/60 flex items-center justify-center text-amber-600 dark:text-amber-400 flex-shrink-0"> <div class="w-12 h-12 rounded-xl bg-amber-50 dark:bg-amber-950/40 border border-amber-200 dark:border-amber-800/60 flex items-center justify-center text-amber-600 dark:text-amber-400 flex-shrink-0">
<i data-lucide="mail" class="w-6 h-6"></i> <i data-lucide="mail" class="w-6 h-6"></i>
</div> </div>
@@ -269,7 +269,7 @@ require_once __DIR__ . '/includes/header.php';
<div class="lg:col-span-8 space-y-8"> <div class="lg:col-span-8 space-y-8">
<!-- 1. Microsoft 365 Azure App Registratie --> <!-- 1. Microsoft 365 Azure App Registratie -->
<div class="fociz-card p-6 sm:p-7"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-6 sm:p-7 shadow-xs transition">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-6 border-b border-slate-100 dark:border-slate-800/80"> <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-6 border-b border-slate-100 dark:border-slate-800/80">
<div class="flex items-center space-x-3.5"> <div class="flex items-center space-x-3.5">
<div class="w-12 h-12 rounded-xl bg-sky-50 dark:bg-sky-950/40 border border-sky-200 dark:border-sky-800/60 flex items-center justify-center text-sky-600 dark:text-sky-400 font-bold shadow-xs"> <div class="w-12 h-12 rounded-xl bg-sky-50 dark:bg-sky-950/40 border border-sky-200 dark:border-sky-800/60 flex items-center justify-center text-sky-600 dark:text-sky-400 font-bold shadow-xs">
@@ -409,7 +409,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
<!-- 2. Atlassian Jira Bedrijfsinstellingen --> <!-- 2. Atlassian Jira Bedrijfsinstellingen -->
<div class="fociz-card p-6 sm:p-7"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-6 sm:p-7 shadow-xs transition">
<div class="flex items-center space-x-3.5 pb-6 border-b border-slate-100 dark:border-slate-800/80"> <div class="flex items-center space-x-3.5 pb-6 border-b border-slate-100 dark:border-slate-800/80">
<div class="w-12 h-12 rounded-xl bg-indigo-50 dark:bg-indigo-950/40 border border-indigo-200 dark:border-indigo-800/60 flex items-center justify-center text-indigo-600 dark:text-indigo-400 font-bold shadow-xs"> <div class="w-12 h-12 rounded-xl bg-indigo-50 dark:bg-indigo-950/40 border border-indigo-200 dark:border-indigo-800/60 flex items-center justify-center text-indigo-600 dark:text-indigo-400 font-bold shadow-xs">
<i data-lucide="trello" class="w-6 h-6"></i> <i data-lucide="trello" class="w-6 h-6"></i>
@@ -453,7 +453,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
<!-- 3. Organisatie Werkdag Standaarden (Release v1.4) --> <!-- 3. Organisatie Werkdag Standaarden (Release v1.4) -->
<div class="fociz-card p-6 sm:p-7 space-y-6"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-6 sm:p-7 shadow-xs space-y-6 transition">
<div class="flex items-center justify-between pb-4 border-b border-slate-100 dark:border-slate-800/80"> <div class="flex items-center justify-between pb-4 border-b border-slate-100 dark:border-slate-800/80">
<div class="flex items-center space-x-3.5"> <div class="flex items-center space-x-3.5">
<div class="w-12 h-12 rounded-xl bg-indigo-50 dark:bg-indigo-950/40 border border-indigo-200 dark:border-indigo-800/60 flex items-center justify-center text-indigo-600 dark:text-indigo-400 font-bold shadow-xs"> <div class="w-12 h-12 rounded-xl bg-indigo-50 dark:bg-indigo-950/40 border border-indigo-200 dark:border-indigo-800/60 flex items-center justify-center text-indigo-600 dark:text-indigo-400 font-bold shadow-xs">
@@ -542,9 +542,13 @@ require_once __DIR__ . '/includes/header.php';
<div> <div>
<label class="block text-[11px] font-medium text-slate-600 dark:text-slate-400 mb-1">Standaard tijdslot</label> <label class="block text-[11px] font-medium text-slate-600 dark:text-slate-400 mb-1">Standaard tijdslot</label>
<select name="default_task_duration" class="w-full bg-white dark:bg-[#111622] border border-slate-300 dark:border-slate-700 rounded-xl px-3 py-1.5 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-1 focus:ring-indigo-500"> <select name="default_task_duration" class="w-full bg-white dark:bg-[#111622] border border-slate-300 dark:border-slate-700 rounded-xl px-3 py-1.5 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-1 focus:ring-indigo-500">
<<<<<<< HEAD
<option value="10" <?= $workdaySettings['default_task_duration'] == 10 ? 'selected' : '' ?>>10 minuten</option> <option value="10" <?= $workdaySettings['default_task_duration'] == 10 ? 'selected' : '' ?>>10 minuten</option>
<option value="15" <?= $workdaySettings['default_task_duration'] == 15 ? 'selected' : '' ?>>15 minuten</option> <option value="15" <?= $workdaySettings['default_task_duration'] == 15 ? 'selected' : '' ?>>15 minuten</option>
<option value="20" <?= $workdaySettings['default_task_duration'] == 20 ? 'selected' : '' ?>>20 minuten</option> <option value="20" <?= $workdaySettings['default_task_duration'] == 20 ? 'selected' : '' ?>>20 minuten</option>
=======
<option value="15" <?= $workdaySettings['default_task_duration'] == 15 ? 'selected' : '' ?>>15 minuten</option>
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
<option value="30" <?= $workdaySettings['default_task_duration'] == 30 ? 'selected' : '' ?>>30 minuten (Standaard)</option> <option value="30" <?= $workdaySettings['default_task_duration'] == 30 ? 'selected' : '' ?>>30 minuten (Standaard)</option>
<option value="45" <?= $workdaySettings['default_task_duration'] == 45 ? 'selected' : '' ?>>45 minuten</option> <option value="45" <?= $workdaySettings['default_task_duration'] == 45 ? 'selected' : '' ?>>45 minuten</option>
<option value="60" <?= $workdaySettings['default_task_duration'] == 60 ? 'selected' : '' ?>>60 minuten (1 uur)</option> <option value="60" <?= $workdaySettings['default_task_duration'] == 60 ? 'selected' : '' ?>>60 minuten (1 uur)</option>
@@ -565,7 +569,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
<!-- 4. AI & Brainstorm Co-Pilot (Release v1.5) --> <!-- 4. AI & Brainstorm Co-Pilot (Release v1.5) -->
<div class="fociz-card p-6 sm:p-7 space-y-6"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-6 sm:p-7 shadow-xs space-y-6 transition">
<div class="flex items-center justify-between pb-4 border-b border-slate-100 dark:border-slate-800/80"> <div class="flex items-center justify-between pb-4 border-b border-slate-100 dark:border-slate-800/80">
<div class="flex items-center space-x-3.5"> <div class="flex items-center space-x-3.5">
<div class="w-12 h-12 rounded-xl bg-amber-50 dark:bg-amber-950/40 border border-amber-200 dark:border-amber-800/60 flex items-center justify-center text-amber-600 dark:text-amber-400 font-bold shadow-xs"> <div class="w-12 h-12 rounded-xl bg-amber-50 dark:bg-amber-950/40 border border-amber-200 dark:border-amber-800/60 flex items-center justify-center text-amber-600 dark:text-amber-400 font-bold shadow-xs">
@@ -626,7 +630,7 @@ require_once __DIR__ . '/includes/header.php';
<div class="lg:col-span-4 space-y-6"> <div class="lg:col-span-4 space-y-6">
<!-- Team Status Overzicht --> <!-- Team Status Overzicht -->
<div class="fociz-card p-6 space-y-5"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-6 shadow-xs space-y-5 transition">
<div class="flex items-center justify-between pb-4 border-b border-slate-100 dark:border-slate-800/80"> <div class="flex items-center justify-between pb-4 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">
<i data-lucide="activity" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i> <i data-lucide="activity" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
@@ -671,7 +675,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
<!-- Systeem Gezondheid & Beveiliging --> <!-- Systeem Gezondheid & Beveiliging -->
<div class="fociz-card p-6 space-y-4"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-6 shadow-xs space-y-4 transition">
<div class="flex items-center space-x-2 text-teal-600 dark:text-teal-400 text-xs font-semibold"> <div class="flex items-center space-x-2 text-teal-600 dark:text-teal-400 text-xs font-semibold">
<i data-lucide="shield-check" class="w-4 h-4"></i> <i data-lucide="shield-check" class="w-4 h-4"></i>
<span>Systeem & Beveiliging</span> <span>Systeem & Beveiliging</span>
+57 -4
View File
@@ -38,8 +38,13 @@ try {
$title = trim($data['title'] ?? ''); $title = trim($data['title'] ?? '');
$priority = in_array($data['priority'] ?? '', ['P1', 'P2', 'P3']) ? $data['priority'] : 'P2'; $priority = in_array($data['priority'] ?? '', ['P1', 'P2', 'P3']) ? $data['priority'] : 'P2';
$timeBlockStart = !empty($data['time_block_start']) ? trim($data['time_block_start']) : null; $timeBlockStart = !empty($data['time_block_start']) ? trim($data['time_block_start']) : null;
<<<<<<< HEAD
$timeBlockEnd = !empty($data['time_block_end']) ? trim($data['time_block_end']) : null; $timeBlockEnd = !empty($data['time_block_end']) ? trim($data['time_block_end']) : null;
$durationMinutes = (int)($data['duration_minutes'] ?? 0); $durationMinutes = (int)($data['duration_minutes'] ?? 0);
=======
$durationMinutes = (int)($data['duration_minutes'] ?? 30);
if ($durationMinutes <= 0) $durationMinutes = 30;
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
$date = !empty($data['date']) ? trim($data['date']) : $today; $date = !empty($data['date']) ? trim($data['date']) : $today;
$syncOutlook = !empty($data['sync_to_outlook']); $syncOutlook = !empty($data['sync_to_outlook']);
@@ -48,6 +53,7 @@ try {
exit; exit;
} }
<<<<<<< HEAD
// Als zowel start- als eindtijd zijn opgegeven, bereken exact de minuten // Als zowel start- als eindtijd zijn opgegeven, bereken exact de minuten
if (!empty($timeBlockStart) && !empty($timeBlockEnd)) { if (!empty($timeBlockStart) && !empty($timeBlockEnd)) {
$t1 = strtotime("2000-01-01 {$timeBlockStart}"); $t1 = strtotime("2000-01-01 {$timeBlockStart}");
@@ -71,6 +77,9 @@ try {
// negeer // negeer
} }
} }
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
// Haal of maak daily plan op // Haal of maak daily plan op
$stmtPlan = $db->prepare(" $stmtPlan = $db->prepare("
INSERT INTO daily_plans (user_id, plan_date) INSERT INTO daily_plans (user_id, plan_date)
@@ -83,6 +92,10 @@ try {
$source = !empty($data['source']) ? substr(trim($data['source']), 0, 50) : 'FOCIZ'; $source = !empty($data['source']) ? substr(trim($data['source']), 0, 50) : 'FOCIZ';
$externalId = !empty($data['external_id']) ? substr(trim($data['external_id']), 0, 255) : null; $externalId = !empty($data['external_id']) ? substr(trim($data['external_id']), 0, 255) : null;
$externalUrl = !empty($data['external_url']) ? trim($data['external_url']) : null; $externalUrl = !empty($data['external_url']) ? trim($data['external_url']) : null;
<<<<<<< HEAD
=======
$timeBlockEnd = null;
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
$outlookSyncError = null; $outlookSyncError = null;
// Als synchronisatie naar Outlook gewenst is (of source is OUTLOOK) en nog geen extern ID heeft // Als synchronisatie naar Outlook gewenst is (of source is OUTLOOK) en nog geen extern ID heeft
@@ -97,7 +110,10 @@ try {
'description' => "Gepland via Fociz Dagplanning ({$priority})", 'description' => "Gepland via Fociz Dagplanning ({$priority})",
'date' => $date, 'date' => $date,
'start_time' => $timeBlockStart, 'start_time' => $timeBlockStart,
<<<<<<< HEAD
'end_time' => $timeBlockEnd, 'end_time' => $timeBlockEnd,
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
'duration_minutes' => $durationMinutes, 'duration_minutes' => $durationMinutes,
]); ]);
@@ -106,11 +122,30 @@ try {
$externalId = $msResult['event_id']; $externalId = $msResult['event_id'];
$externalUrl = $msResult['web_link'] ?? 'https://outlook.office.com'; $externalUrl = $msResult['web_link'] ?? 'https://outlook.office.com';
$timeBlockStart = $msResult['start_time'] ?? $timeBlockStart; $timeBlockStart = $msResult['start_time'] ?? $timeBlockStart;
<<<<<<< HEAD
$timeBlockEnd = $msResult['end_time'] ?? $timeBlockEnd; $timeBlockEnd = $msResult['end_time'] ?? $timeBlockEnd;
=======
$timeBlockEnd = $msResult['end_time'] ?? null;
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
} else { } else {
$outlookSyncError = $msResult['error'] ?? 'Kon afspraak niet aanmaken in Microsoft Outlook'; $outlookSyncError = $msResult['error'] ?? 'Kon afspraak niet aanmaken in Microsoft Outlook';
} }
} }
<<<<<<< HEAD
=======
// Bereken timeBlockEnd indien nog niet gezet maar wel starttijd bekend
if (!empty($timeBlockStart) && empty($timeBlockEnd)) {
try {
$dtEnd = new DateTime("{$date} {$timeBlockStart}:00", new DateTimeZone('Europe/Amsterdam'));
$dtEnd->modify("+{$durationMinutes} minutes");
$timeBlockEnd = $dtEnd->format('H:i');
} catch (Throwable $e) {
// negeer
}
}
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
$stmt = $db->prepare(" $stmt = $db->prepare("
INSERT INTO tasks (user_id, daily_plan_id, title, priority, time_block_start, time_block_end, duration_minutes, status, source, external_id, external_url) INSERT INTO tasks (user_id, daily_plan_id, title, priority, time_block_start, time_block_end, duration_minutes, status, source, external_id, external_url)
VALUES (?, ?, ?, ?, ?, ?, ?, 'TODO', ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, 'TODO', ?, ?, ?)
@@ -127,14 +162,13 @@ try {
'time_block_start' => $timeBlockStart, 'time_block_start' => $timeBlockStart,
'time_block_end' => $timeBlockEnd, 'time_block_end' => $timeBlockEnd,
'duration_minutes' => $durationMinutes, 'duration_minutes' => $durationMinutes,
'is_completed' => 0, <<<<<<< HEAD
'status' => 'TODO',
'source' => $source, 'source' => $source,
'external_id' => $externalId, 'external_id' => $externalId,
'external_url' => $externalUrl, 'external_url' => $externalUrl
], ],
'outlook_synced' => ($source === 'OUTLOOK' && !empty($externalId)), 'outlook_synced' => ($source === 'OUTLOOK' && !empty($externalId)),
'outlook_error' => $outlookSyncError, 'outlook_error' => $outlookSyncError
]); ]);
exit; exit;
} }
@@ -214,6 +248,16 @@ try {
'time_block_start' => $timeBlockStart, 'time_block_start' => $timeBlockStart,
'time_block_end' => $timeBlockEnd, 'time_block_end' => $timeBlockEnd,
'duration_minutes' => $durationMinutes 'duration_minutes' => $durationMinutes
=======
'is_completed' => 0,
'status' => 'TODO',
'source' => $source,
'external_id' => $externalId,
'external_url' => $externalUrl,
],
'outlook_synced' => ($source === 'OUTLOOK' && !empty($externalId)),
'outlook_error' => $outlookSyncError,
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
]); ]);
exit; exit;
} }
@@ -256,7 +300,10 @@ try {
$planDate = $task['plan_date'] ?: $today; $planDate = $task['plan_date'] ?: $today;
$startTime = !empty($task['time_block_start']) ? $task['time_block_start'] : ($data['time_block_start'] ?? '09:00'); $startTime = !empty($task['time_block_start']) ? $task['time_block_start'] : ($data['time_block_start'] ?? '09:00');
<<<<<<< HEAD
$endTime = !empty($task['time_block_end']) ? $task['time_block_end'] : null; $endTime = !empty($task['time_block_end']) ? $task['time_block_end'] : null;
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
$duration = (int)($task['duration_minutes'] ?: 30); $duration = (int)($task['duration_minutes'] ?: 30);
$msResult = microsoft_create_event($user['id'], [ $msResult = microsoft_create_event($user['id'], [
@@ -264,7 +311,10 @@ try {
'description' => "Gepland via Fociz Dagplanning (" . $task['priority'] . ")", 'description' => "Gepland via Fociz Dagplanning (" . $task['priority'] . ")",
'date' => $planDate, 'date' => $planDate,
'start_time' => $startTime, 'start_time' => $startTime,
<<<<<<< HEAD
'end_time' => $endTime, 'end_time' => $endTime,
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
'duration_minutes' => $duration, 'duration_minutes' => $duration,
]); ]);
@@ -344,6 +394,7 @@ try {
exit; exit;
} }
<<<<<<< HEAD
// 6. Realtime Outlook synchronisatie & controle op gewijzigde/gewiste items // 6. Realtime Outlook synchronisatie & controle op gewijzigde/gewiste items
if ($action === 'check_outlook_sync') { if ($action === 'check_outlook_sync') {
$rawInput = file_get_contents('php://input'); $rawInput = file_get_contents('php://input');
@@ -452,6 +503,8 @@ try {
exit; exit;
} }
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
echo json_encode(['error' => 'Onbekende actie']); echo json_encode(['error' => 'Onbekende actie']);
} catch (Exception $e) { } catch (Exception $e) {
http_response_code(500); http_response_code(500);
-4
View File
@@ -254,10 +254,6 @@
isFetchingEvents = true; isFetchingEvents = true;
try { try {
const res = await fetch('/api/notifications.php?action=get_events', { cache: 'no-store' }); const res = await fetch('/api/notifications.php?action=get_events', { cache: 'no-store' });
if (res.status === 401) {
window.location.href = '/auth/login.php?expired=1';
return;
}
if (res.ok) { if (res.ok) {
const data = await res.json(); const data = await res.json();
if (data && data.success) { if (data && data.success) {
+1 -3
View File
@@ -27,9 +27,7 @@ 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'); issue_remember_token((int)$recoveredUser['id']);
$_SESSION['session_expires_at'] = strtotime('today 23:59:59');
clear_remember_cookie();
} }
} catch (Throwable $e) { } catch (Throwable $e) {
// Foutafhandeling // Foutafhandeling
+2 -4
View File
@@ -75,15 +75,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$db->commit(); $db->commit();
// Start dagsessie (geldig tot 23:59:59) // Start sessie
$_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'); issue_remember_token($newUserId);
$_SESSION['session_expires_at'] = strtotime('today 23:59:59');
clear_remember_cookie();
unset($_SESSION['invite_totp_secret']); unset($_SESSION['invite_totp_secret']);
header('Location: /planner.php'); header('Location: /planner.php');
+3 -16
View File
@@ -20,10 +20,6 @@ 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
@@ -99,17 +95,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
} }
if ($isValid) { if ($isValid) {
// Volledige login succesvol (geldig tot 23:59:59 van vandaag) // Volledige login succesvol
$_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');
// Zorg dat er geen persistente remember cookies worden gebruikt // Activeer persistente remember token (30 dagen blijf ingelogd)
clear_remember_cookie(); 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']);
@@ -184,13 +178,6 @@ $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>
+2 -4
View File
@@ -62,15 +62,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$adminId = (int)$db->lastInsertId(); $adminId = (int)$db->lastInsertId();
// Automatische dagsessie starten (geldig tot 23:59:59) // Automatische sessie starten
$_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'); issue_remember_token($adminId);
$_SESSION['session_expires_at'] = strtotime('today 23:59:59');
clear_remember_cookie();
unset($_SESSION['setup_totp_secret']); unset($_SESSION['setup_totp_secret']);
$success = true; $success = true;
+25 -25
View File
@@ -42,21 +42,21 @@ require_once __DIR__ . '/includes/header.php';
<div class="space-y-6 max-w-7xl mx-auto"> <div class="space-y-6 max-w-7xl mx-auto">
<!-- Header --> <!-- Header -->
<div class="fociz-card p-6 sm:p-7 flex flex-col sm:flex-row sm:items-center justify-between gap-4"> <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-6 sm:p-7 shadow-xs transition">
<div> <div>
<div class="flex items-center space-x-2 text-indigo-600 dark:text-indigo-400 text-xs font-bold uppercase tracking-wider mb-1"> <div class="flex items-center space-x-2 text-indigo-600 dark:text-indigo-400 text-xs font-semibold uppercase tracking-wider mb-1">
<i data-lucide="lightbulb" class="w-4 h-4"></i> <i data-lucide="lightbulb" class="w-4 h-4"></i>
<span>Creatie & Innovatie</span> <span>Creatie & Innovatie</span>
</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-bold text-slate-900 dark:text-white tracking-tight">
Brainstorm Sessies Brainstorm Sessies
</h1> </h1>
<p class="text-slate-500 dark:text-slate-400 text-xs sm:text-sm mt-1 max-w-2xl"> <p class="text-slate-500 dark:text-slate-400 text-xs sm:text-sm mt-1">
Brainstorm met collega's, verzamel ideeën en knelpunten, en transformeer ze direct tot een werkbare roadmap. Brainstorm met collega's, verzamel ideeën en knelpunten, en transformeer ze direct tot een werkbare roadmap.
</p> </p>
</div> </div>
<button onclick="document.getElementById('newSessionModal').classList.remove('hidden')" class="flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-bold transition shadow-xs flex-shrink-0 cursor-pointer"> <button onclick="document.getElementById('newSessionModal').classList.remove('hidden')" class="flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-semibold transition shadow-xs flex-shrink-0 cursor-pointer">
<i data-lucide="plus" class="w-4 h-4"></i> <i data-lucide="plus" class="w-4 h-4"></i>
<span>Nieuwe Sessie Starten</span> <span>Nieuwe Sessie Starten</span>
</button> </button>
@@ -71,25 +71,25 @@ require_once __DIR__ . '/includes/header.php';
<!-- Grid met sessies --> <!-- Grid met sessies -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
<?php if (empty($sessions)): ?> <?php if (empty($sessions)): ?>
<div class="col-span-full fociz-card p-12 text-center shadow-xs"> <div class="col-span-full bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-12 text-center shadow-xs">
<i data-lucide="lightbulb" class="w-12 h-12 text-slate-300 dark:text-slate-700 mx-auto mb-3"></i> <i data-lucide="lightbulb" class="w-12 h-12 text-slate-300 dark:text-slate-700 mx-auto mb-3"></i>
<h3 class="text-base font-bold text-slate-900 dark:text-white">Nog geen brainstormsessies gestart</h3> <h3 class="text-base font-semibold text-slate-900 dark:text-white">Nog geen brainstormsessies gestart</h3>
<p class="text-xs text-slate-500 dark:text-slate-400 mt-1 max-w-sm mx-auto"> <p class="text-xs text-slate-500 dark:text-slate-400 mt-1 max-w-sm mx-auto">
Start uw eerste brainstormsessie om ideeën te verzamelen en ze met één klik om te vormen naar planningsitems. Start uw eerste brainstormsessie om ideeën te verzamelen en ze met één klik om te vormen naar planningsitems.
</p> </p>
<button onclick="document.getElementById('newSessionModal').classList.remove('hidden')" class="mt-4 px-4 py-2 bg-indigo-600 hover:bg-indigo-500 text-white font-bold rounded-xl text-xs transition cursor-pointer shadow-xs"> <button onclick="document.getElementById('newSessionModal').classList.remove('hidden')" class="mt-4 px-4 py-2 bg-indigo-600 hover:bg-indigo-500 text-white font-semibold rounded-xl text-xs transition cursor-pointer shadow-xs">
Sessie Starten Sessie Starten
</button> </button>
</div> </div>
<?php else: ?> <?php else: ?>
<?php foreach ($sessions as $sess): ?> <?php foreach ($sessions as $sess): ?>
<a href="/brainstorm_canvas.php?id=<?= $sess['id'] ?>" class="group fociz-card-interactive p-5 flex flex-col justify-between hover:border-indigo-400 dark:hover:border-indigo-500/60"> <a href="/brainstorm_canvas.php?id=<?= $sess['id'] ?>" class="group bg-white hover:bg-slate-50/70 dark:bg-[#111622] dark:hover:bg-[#151b2a] border border-slate-200/80 hover:border-indigo-300 dark:border-slate-800 dark:hover:border-indigo-700/60 rounded-2xl p-5 shadow-xs hover:shadow-sm transition flex flex-col justify-between">
<div> <div>
<div class="flex items-center justify-between mb-3"> <div class="flex items-center justify-between mb-3">
<span class="px-2.5 py-0.5 rounded-lg bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 text-indigo-700 dark:text-indigo-400 font-semibold text-[11px]"> <span class="px-2.5 py-0.5 rounded-md bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 text-indigo-700 dark:text-indigo-400 font-medium text-[11px]">
<?= htmlspecialchars($sess['theme']) ?> <?= htmlspecialchars($sess['theme']) ?>
</span> </span>
<span class="flex items-center space-x-1 text-slate-400 dark:text-slate-500 text-xs font-medium"> <span class="flex items-center space-x-1 text-slate-400 dark:text-slate-500 text-xs">
<i data-lucide="message-square" class="w-3.5 h-3.5"></i> <i data-lucide="message-square" class="w-3.5 h-3.5"></i>
<span><?= $sess['cards_count'] ?> kaarten</span> <span><?= $sess['cards_count'] ?> kaarten</span>
</span> </span>
@@ -107,8 +107,8 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
<div class="mt-5 pt-4 border-t border-slate-100 dark:border-slate-800/80 flex items-center justify-between text-xs text-slate-500 dark:text-slate-400"> <div class="mt-5 pt-4 border-t border-slate-100 dark:border-slate-800/80 flex items-center justify-between text-xs text-slate-500 dark:text-slate-400">
<span class="truncate">Door <?= htmlspecialchars($sess['creator_name']) ?></span> <span>Door <?= htmlspecialchars($sess['creator_name']) ?></span>
<div class="flex items-center space-x-1 text-indigo-600 dark:text-indigo-400 group-hover:translate-x-1 transition font-bold flex-shrink-0 ml-2"> <div class="flex items-center space-x-1 text-indigo-600 dark:text-indigo-400 group-hover:translate-x-1 transition font-medium">
<span>Open canvas</span> <span>Open canvas</span>
<i data-lucide="arrow-right" class="w-3.5 h-3.5"></i> <i data-lucide="arrow-right" class="w-3.5 h-3.5"></i>
</div> </div>
@@ -120,15 +120,15 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
<!-- Modal: Nieuwe sessie --> <!-- Modal: Nieuwe sessie -->
<div id="newSessionModal" class="hidden fixed inset-0 z-50 bg-slate-950/70 backdrop-blur-sm flex items-center justify-center p-4"> <div id="newSessionModal" class="hidden fixed inset-0 z-50 bg-slate-950/60 backdrop-blur-xs flex items-center justify-center p-4">
<div class="fociz-card p-6 sm:p-7 shadow-2xl max-w-lg w-full space-y-4"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800 rounded-2xl p-6 sm:p-7 shadow-xl max-w-lg w-full transition">
<div class="flex items-center justify-between 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">
<h3 class="text-sm font-bold text-slate-900 dark:text-white flex items-center space-x-2"> <h3 class="text-sm font-semibold text-slate-900 dark:text-white flex items-center space-x-2">
<i data-lucide="sparkles" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i> <i data-lucide="sparkles" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
<span>Nieuwe Brainstormsessie</span> <span>Nieuwe Brainstormsessie</span>
</h3> </h3>
<button onclick="document.getElementById('newSessionModal').classList.add('hidden')" class="p-1.5 text-slate-400 hover:text-slate-600 dark:hover:text-white rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition cursor-pointer"> <button onclick="document.getElementById('newSessionModal').classList.add('hidden')" class="text-slate-400 hover:text-slate-600 dark:hover:text-white cursor-pointer">
<i data-lucide="x" class="w-4 h-4"></i> <i data-lucide="x" class="w-5 h-5"></i>
</button> </button>
</div> </div>
@@ -137,13 +137,13 @@ require_once __DIR__ . '/includes/header.php';
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Onderwerp / Titel</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Onderwerp / Titel</label>
<input type="text" name="title" required placeholder="Bijv. Q4 Automatisering & Klantreis" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3.5 py-2.5 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 shadow-2xs"> <input type="text" name="title" required placeholder="Bijv. Q4 Automatisering & Klantreis" class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 dark:border-slate-800 rounded-xl px-3.5 py-2.5 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 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">Thema / Categorie</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Thema / Categorie</label>
<select name="theme" 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"> <select name="theme" class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 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">
<option value="Product & Strategie">Product & Strategie</option> <option value="Product & Strategie">Product & Strategie</option>
<option value="Procesverbetering">Procesverbetering</option> <option value="Procesverbetering">Procesverbetering</option>
<option value="Klant & Service">Klant & Service</option> <option value="Klant & Service">Klant & Service</option>
@@ -153,15 +153,15 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Doel / Beschrijving</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Doel / Beschrijving</label>
<input type="text" name="description" placeholder="Doel van deze sessie..." class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 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 shadow-2xs"> <input type="text" name="description" placeholder="Doel van deze sessie..." class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 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> </div>
<div class="flex space-x-2 pt-2 border-t border-slate-100 dark:border-slate-800/80"> <div class="flex space-x-2 pt-2">
<button type="submit" class="flex-1 bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-2.5 px-4 rounded-xl text-xs transition cursor-pointer shadow-xs"> <button type="submit" class="flex-1 bg-indigo-600 hover:bg-indigo-500 text-white font-semibold py-2.5 px-4 rounded-xl text-xs transition cursor-pointer shadow-xs">
Sessie Aanmaken & Canvas Openen Sessie Aanmaken & Canvas Openen
</button> </button>
<button type="button" onclick="document.getElementById('newSessionModal').classList.add('hidden')" class="px-4 py-2.5 bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-xl text-xs font-semibold transition cursor-pointer"> <button type="button" onclick="document.getElementById('newSessionModal').classList.add('hidden')" class="px-4 py-2.5 bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-xl text-xs transition cursor-pointer">
Annuleren Annuleren
</button> </button>
</div> </div>
+41 -41
View File
@@ -71,19 +71,19 @@ $categories = [
<div class="space-y-6 max-w-7xl mx-auto"> <div class="space-y-6 max-w-7xl mx-auto">
<!-- Top Bar --> <!-- Top Bar -->
<div class="fociz-card p-5 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 bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-5 shadow-xs transition">
<div class="flex items-center space-x-4"> <div class="flex items-center space-x-4">
<a href="/brainstorm.php" class="p-2.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white transition cursor-pointer"> <a href="/brainstorm.php" class="p-2.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white transition cursor-pointer">
<i data-lucide="arrow-left" class="w-5 h-5"></i> <i data-lucide="arrow-left" class="w-5 h-5"></i>
</a> </a>
<div> <div>
<div class="flex items-center space-x-2 text-xs"> <div class="flex items-center space-x-2 text-xs">
<span class="px-2.5 py-0.5 rounded-lg bg-indigo-50 dark:bg-indigo-500/10 text-indigo-700 dark:text-indigo-400 font-bold border border-indigo-200 dark:border-indigo-500/20"> <span class="px-2.5 py-0.5 rounded-md bg-indigo-50 dark:bg-indigo-500/10 text-indigo-700 dark:text-indigo-400 font-semibold border border-indigo-200 dark:border-indigo-500/20">
<?= htmlspecialchars($session['theme']) ?> <?= htmlspecialchars($session['theme']) ?>
</span> </span>
<span class="text-slate-400 dark:text-slate-500">Gestart door <?= htmlspecialchars($session['creator_name']) ?></span> <span class="text-slate-400 dark:text-slate-500">Gestart door <?= htmlspecialchars($session['creator_name']) ?></span>
</div> </div>
<h1 class="text-xl sm:text-2xl font-black text-slate-900 dark:text-white tracking-tight mt-0.5"> <h1 class="text-xl sm:text-2xl font-bold text-slate-900 dark:text-white tracking-tight mt-0.5">
<?= htmlspecialchars($session['title']) ?> <?= htmlspecialchars($session['title']) ?>
</h1> </h1>
</div> </div>
@@ -91,24 +91,24 @@ $categories = [
<div class="flex flex-wrap items-center gap-2.5"> <div class="flex flex-wrap items-center gap-2.5">
<?php if ($aiSettings['ai_enabled'] && $aiSettings['has_key']): ?> <?php if ($aiSettings['ai_enabled'] && $aiSettings['has_key']): ?>
<button onclick="aiGenerateIdeas(this)" class="flex items-center space-x-1.5 px-3 py-2 rounded-xl bg-violet-50 hover:bg-violet-100 dark:bg-violet-950/50 dark:hover:bg-violet-900/50 text-violet-700 dark:text-violet-300 border border-violet-200 dark:border-violet-800/60 text-xs font-bold transition cursor-pointer shadow-xs" title="Genereer 4 innovatieve ideeën via AI Co-Pilot"> <button onclick="aiGenerateIdeas(this)" class="flex items-center space-x-1.5 px-3 py-2 rounded-xl bg-violet-50 hover:bg-violet-100 dark:bg-violet-950/50 dark:hover:bg-violet-900/50 text-violet-700 dark:text-violet-300 border border-violet-200 dark:border-violet-800/60 text-xs font-semibold transition cursor-pointer shadow-xs" title="Genereer 4 innovatieve ideeën via AI Co-Pilot">
<i data-lucide="sparkles" class="w-4 h-4 text-violet-500"></i> <i data-lucide="sparkles" class="w-4 h-4 text-violet-500"></i>
<span>💡 AI Ideeën</span> <span>💡 AI Ideeën</span>
</button> </button>
<button onclick="aiCategorizeCards(this)" class="flex items-center space-x-1.5 px-3 py-2 rounded-xl bg-indigo-50 hover:bg-indigo-100 dark:bg-indigo-950/50 dark:hover:bg-indigo-900/50 text-indigo-700 dark:text-indigo-300 border border-indigo-200 dark:border-indigo-800/60 text-xs font-bold transition cursor-pointer shadow-xs" title="Sorteer alle kaartjes automatisch in Ideeën, Knelpunten, Oplossingen of Quick Wins"> <button onclick="aiCategorizeCards(this)" class="flex items-center space-x-1.5 px-3 py-2 rounded-xl bg-indigo-50 hover:bg-indigo-100 dark:bg-indigo-950/50 dark:hover:bg-indigo-900/50 text-indigo-700 dark:text-indigo-300 border border-indigo-200 dark:border-indigo-800/60 text-xs font-semibold transition cursor-pointer shadow-xs" title="Sorteer alle kaartjes automatisch in Ideeën, Knelpunten, Oplossingen of Quick Wins">
<i data-lucide="wand-2" class="w-4 h-4 text-indigo-500"></i> <i data-lucide="wand-2" class="w-4 h-4 text-indigo-500"></i>
<span>✨ Auto-Categoriseer</span> <span>✨ Auto-Categoriseer</span>
</button> </button>
<?php endif; ?> <?php endif; ?>
<button onclick="openAddCardModal()" class="flex items-center space-x-1.5 px-3.5 py-2 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-200 text-xs font-bold border border-slate-200 dark:border-slate-700 transition cursor-pointer shadow-xs"> <button onclick="openAddCardModal()" class="flex items-center space-x-1.5 px-3.5 py-2 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-200 text-xs font-semibold border border-slate-200 dark:border-slate-700 transition cursor-pointer shadow-xs">
<i data-lucide="plus" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i> <i data-lucide="plus" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
<span>Nieuwe Kaart</span> <span>Nieuwe Kaart</span>
</button> </button>
<!-- De Kernfeature: Zet om naar Roadmap! --> <!-- De Kernfeature: Zet om naar Roadmap! -->
<button onclick="openConvertModal()" class="flex items-center space-x-2 px-4 py-2 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-bold transition shadow-xs cursor-pointer"> <button onclick="openConvertModal()" class="flex items-center space-x-2 px-4 py-2 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-semibold transition shadow-xs cursor-pointer">
<i data-lucide="map" class="w-4 h-4"></i> <i data-lucide="map" class="w-4 h-4"></i>
<span>Zet om naar Roadmap</span> <span>Zet om naar Roadmap</span>
</button> </button>
@@ -120,14 +120,14 @@ $categories = [
<?php foreach ($categories as $catKey => $catConfig): <?php foreach ($categories as $catKey => $catConfig):
$catCards = array_filter($cards, fn($c) => $c['category'] === $catKey); $catCards = array_filter($cards, fn($c) => $c['category'] === $catKey);
?> ?>
<div class="fociz-card p-4 flex flex-col min-h-[500px]"> <div class="bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-4 flex flex-col min-h-[500px] shadow-xs transition">
<!-- Column Header --> <!-- Column Header -->
<div class="flex items-center justify-between pb-3 mb-3 border-b border-slate-100 dark:border-slate-800"> <div class="flex items-center justify-between pb-3 mb-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="<?= $catConfig['icon'] ?>" class="w-4 h-4 text-<?= $catConfig['color'] ?>-500"></i> <i data-lucide="<?= $catConfig['icon'] ?>" class="w-4 h-4 text-<?= $catConfig['color'] ?>-500"></i>
<h3 class="text-xs font-bold text-slate-900 dark:text-white uppercase tracking-wider"><?= $catConfig['title'] ?></h3> <h3 class="text-xs font-semibold text-slate-900 dark:text-white uppercase tracking-wider"><?= $catConfig['title'] ?></h3>
</div> </div>
<span class="text-xs font-mono font-bold px-2 py-0.5 rounded-full bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400 border border-slate-200 dark:border-slate-700"> <span class="text-xs font-mono font-semibold px-2 py-0.5 rounded-full bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400">
<?= count($catCards) ?> <?= count($catCards) ?>
</span> </span>
</div> </div>
@@ -135,22 +135,22 @@ $categories = [
<!-- Cards Container --> <!-- Cards Container -->
<div class="flex-1 space-y-3"> <div class="flex-1 space-y-3">
<?php if (empty($catCards)): ?> <?php if (empty($catCards)): ?>
<div class="py-8 text-center text-slate-400 dark:text-slate-600 text-xs font-medium"> <div class="py-8 text-center text-slate-400 dark:text-slate-600 text-xs">
Nog geen kaarten in deze categorie. Nog geen kaarten in deze categorie.
</div> </div>
<?php else: ?> <?php else: ?>
<?php foreach ($catCards as $card): ?> <?php foreach ($catCards as $card): ?>
<div class="group relative rounded-xl p-4 border <?= $catConfig['border'] ?> <?= $catConfig['bg'] ?> backdrop-blur-sm shadow-2xs transition hover:-translate-y-0.5" id="card-<?= $card['id'] ?>"> <div class="group relative rounded-xl p-4 border <?= $catConfig['border'] ?> <?= $catConfig['bg'] ?> backdrop-blur-sm shadow-xs transition hover:-translate-y-0.5" id="card-<?= $card['id'] ?>">
<!-- Top: Checkbox voor selectie + Roadmap badge --> <!-- Top: Checkbox voor selectie + Roadmap badge -->
<div class="flex items-center justify-between mb-2"> <div class="flex items-center justify-between mb-2">
<label class="flex items-center space-x-2 cursor-pointer"> <label class="flex items-center space-x-2 cursor-pointer">
<input type="checkbox" value="<?= $card['id'] ?>" data-content="<?= htmlspecialchars($card['content'], ENT_QUOTES) ?>" class="card-checkbox w-4 h-4 rounded bg-white dark:bg-slate-900 border-slate-300 dark:border-slate-700 text-indigo-600 focus:ring-0"> <input type="checkbox" value="<?= $card['id'] ?>" data-content="<?= htmlspecialchars($card['content'], ENT_QUOTES) ?>" class="card-checkbox w-4 h-4 rounded bg-white dark:bg-slate-900 border-slate-300 dark:border-slate-700 text-indigo-600 focus:ring-0">
<span class="text-[10px] text-slate-500 dark:text-slate-400 font-medium">Selecteer</span> <span class="text-[10px] text-slate-500 dark:text-slate-400">Selecteer</span>
</label> </label>
<?php if (!empty($card['converted_to_roadmap_item_id'])): ?> <?php if (!empty($card['converted_to_roadmap_item_id'])): ?>
<span class="px-2 py-0.5 rounded-md bg-teal-50 dark:bg-teal-500/15 text-teal-700 dark:text-teal-400 font-bold text-[10px] flex items-center space-x-1 border border-teal-200 dark:border-teal-500/20"> <span class="px-2 py-0.5 rounded-md bg-teal-50 dark:bg-teal-500/15 text-teal-700 dark:text-teal-400 font-semibold text-[10px] flex items-center space-x-1 border border-teal-200 dark:border-teal-500/20">
<i data-lucide="check" class="w-3 h-3"></i> <i data-lucide="check" class="w-3 h-3"></i>
<span>Op Roadmap</span> <span>Op Roadmap</span>
</span> </span>
@@ -185,7 +185,7 @@ $categories = [
</div> </div>
<!-- Quick add button at column bottom --> <!-- Quick add button at column bottom -->
<button onclick="openAddCardModal('<?= $catKey ?>')" class="mt-3 w-full py-2 rounded-xl border border-dashed border-slate-200 dark:border-slate-800 hover:border-indigo-300 dark:hover:border-indigo-700/60 text-slate-400 hover:text-indigo-600 dark:hover:text-indigo-400 text-xs font-semibold transition flex items-center justify-center space-x-1 cursor-pointer"> <button onclick="openAddCardModal('<?= $catKey ?>')" class="mt-3 w-full py-2 rounded-xl border border-dashed border-slate-200 dark:border-slate-800 hover:border-indigo-300 dark:hover:border-indigo-700/60 text-slate-400 hover:text-indigo-600 dark:hover:text-indigo-400 text-xs transition flex items-center justify-center space-x-1 cursor-pointer">
<i data-lucide="plus" class="w-3.5 h-3.5"></i> <i data-lucide="plus" class="w-3.5 h-3.5"></i>
<span>Kaart toevoegen</span> <span>Kaart toevoegen</span>
</button> </button>
@@ -195,22 +195,22 @@ $categories = [
</div> </div>
<!-- Modal: Nieuwe Kaart Toevoegen --> <!-- Modal: Nieuwe Kaart Toevoegen -->
<div id="addCardModal" class="hidden fixed inset-0 z-50 bg-slate-950/70 backdrop-blur-sm flex items-center justify-center p-4"> <div id="addCardModal" class="hidden fixed inset-0 z-50 bg-slate-950/60 backdrop-blur-xs flex items-center justify-center p-4">
<div class="fociz-card p-6 shadow-2xl max-w-md w-full space-y-4"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800 rounded-2xl p-6 shadow-xl max-w-md w-full transition">
<div class="flex items-center justify-between 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">
<h3 class="text-sm font-bold text-slate-900 dark:text-white flex items-center space-x-2"> <h3 class="text-sm font-semibold text-slate-900 dark:text-white flex items-center space-x-2">
<i data-lucide="sticky-note" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i> <i data-lucide="sticky-note" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
<span>Brainstormkaart Toevoegen</span> <span>Brainstormkaart Toevoegen</span>
</h3> </h3>
<button onclick="closeAddCardModal()" class="p-1.5 text-slate-400 hover:text-slate-600 dark:hover:text-white rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition cursor-pointer"> <button onclick="closeAddCardModal()" class="text-slate-400 hover:text-slate-600 dark:hover:text-white cursor-pointer">
<i data-lucide="x" class="w-4 h-4"></i> <i data-lucide="x" class="w-5 h-5"></i>
</button> </button>
</div> </div>
<div class="space-y-4"> <div class="space-y-4">
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Categorie</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Categorie</label>
<select id="modalCardCategory" 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"> <select id="modalCardCategory" class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 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">
<option value="Ideeën">💡 Ideeën & Concepten</option> <option value="Ideeën">💡 Ideeën & Concepten</option>
<option value="Knelpunten">⚠️ Knelpunten & Uitdagingen</option> <option value="Knelpunten">⚠️ Knelpunten & Uitdagingen</option>
<option value="Oplossingen">🚀 Oplossingen & Features</option> <option value="Oplossingen">🚀 Oplossingen & Features</option>
@@ -220,14 +220,14 @@ $categories = [
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Idee / Beschrijving</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Idee / Beschrijving</label>
<textarea id="modalCardContent" rows="4" placeholder="Schrijf hier uw inzicht, idee of knelpunt..." class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 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 shadow-2xs"></textarea> <textarea id="modalCardContent" rows="4" placeholder="Schrijf hier uw inzicht, idee of knelpunt..." class="w-full bg-slate-50 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"></textarea>
</div> </div>
<div class="flex space-x-2 pt-2 border-t border-slate-100 dark:border-slate-800/80"> <div class="flex space-x-2 pt-2">
<button onclick="submitNewCard()" class="flex-1 bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-2.5 px-4 rounded-xl text-xs transition cursor-pointer shadow-xs"> <button onclick="submitNewCard()" class="flex-1 bg-indigo-600 hover:bg-indigo-500 text-white font-semibold py-2.5 px-4 rounded-xl text-xs transition cursor-pointer shadow-xs">
Plaats op Canvas Plaats op Canvas
</button> </button>
<button onclick="closeAddCardModal()" class="px-4 py-2.5 bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-xl text-xs font-semibold transition cursor-pointer"> <button onclick="closeAddCardModal()" class="px-4 py-2.5 bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-xl text-xs transition cursor-pointer">
Annuleren Annuleren
</button> </button>
</div> </div>
@@ -236,20 +236,20 @@ $categories = [
</div> </div>
<!-- Modal: Zet om naar Roadmap --> <!-- Modal: Zet om naar Roadmap -->
<div id="convertModal" class="hidden fixed inset-0 z-50 bg-slate-950/70 backdrop-blur-sm flex items-center justify-center p-4"> <div id="convertModal" class="hidden fixed inset-0 z-50 bg-slate-950/60 backdrop-blur-xs flex items-center justify-center p-4">
<div class="fociz-card p-6 shadow-2xl max-w-lg w-full space-y-4"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800 rounded-2xl p-6 shadow-xl max-w-lg w-full transition">
<div class="flex items-center justify-between 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">
<h3 class="text-sm font-bold text-slate-900 dark:text-white flex items-center space-x-2"> <h3 class="text-sm font-semibold text-slate-900 dark:text-white flex items-center space-x-2">
<i data-lucide="map" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i> <i data-lucide="map" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
<span>Zet Brainstorm om naar Roadmap</span> <span>Zet Brainstorm om naar Roadmap</span>
</h3> </h3>
<button onclick="closeConvertModal()" class="p-1.5 text-slate-400 hover:text-slate-600 dark:hover:text-white rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition cursor-pointer"> <button onclick="closeConvertModal()" class="text-slate-400 hover:text-slate-600 dark:hover:text-white cursor-pointer">
<i data-lucide="x" class="w-4 h-4"></i> <i data-lucide="x" class="w-5 h-5"></i>
</button> </button>
</div> </div>
<div class="space-y-4"> <div class="space-y-4">
<div class="bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 rounded-xl p-3 text-xs text-indigo-800 dark:text-indigo-300 font-semibold"> <div class="bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 rounded-xl p-3 text-xs text-indigo-800 dark:text-indigo-300">
<span id="selectedCountText" class="font-bold">0</span> kaarten geselecteerd om om te zetten naar planbare roadmap items. <span id="selectedCountText" class="font-bold">0</span> kaarten geselecteerd om om te zetten naar planbare roadmap items.
</div> </div>
@@ -259,7 +259,7 @@ $categories = [
<i data-lucide="sparkles" class="w-4 h-4 text-violet-500 flex-shrink-0"></i> <i data-lucide="sparkles" class="w-4 h-4 text-violet-500 flex-shrink-0"></i>
<span class="text-[11px] font-medium leading-tight">Laat AI Co-Pilot kwartaal, type & prioriteit adviseren</span> <span class="text-[11px] font-medium leading-tight">Laat AI Co-Pilot kwartaal, type & prioriteit adviseren</span>
</div> </div>
<button type="button" onclick="aiSuggestRoadmapMeta(this)" id="aiSuggestBtn" class="px-2.5 py-1 bg-violet-600 hover:bg-violet-700 text-white rounded-lg text-xs font-bold transition flex items-center space-x-1 cursor-pointer flex-shrink-0 shadow-xs"> <button type="button" onclick="aiSuggestRoadmapMeta(this)" id="aiSuggestBtn" class="px-2.5 py-1 bg-violet-600 hover:bg-violet-700 text-white rounded-lg text-xs font-semibold transition flex items-center space-x-1 cursor-pointer flex-shrink-0 shadow-xs">
<span>✨ AI Advies</span> <span>✨ AI Advies</span>
</button> </button>
</div> </div>
@@ -268,7 +268,7 @@ $categories = [
<div class="grid grid-cols-2 gap-3"> <div class="grid grid-cols-2 gap-3">
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Doel Kwartaal</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Doel Kwartaal</label>
<select id="roadmapQuarter" 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"> <select id="roadmapQuarter" class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 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">
<option value="Q1">Q1 (Jan - Mrt)</option> <option value="Q1">Q1 (Jan - Mrt)</option>
<option value="Q2">Q2 (Apr - Jun)</option> <option value="Q2">Q2 (Apr - Jun)</option>
<option value="Q3" selected>Q3 (Jul - Sep)</option> <option value="Q3" selected>Q3 (Jul - Sep)</option>
@@ -278,7 +278,7 @@ $categories = [
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Item Type</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Item Type</label>
<select id="roadmapType" 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"> <select id="roadmapType" class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 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">
<option value="FEATURE" selected>Feature / Functionaliteit</option> <option value="FEATURE" selected>Feature / Functionaliteit</option>
<option value="EPIC">Epic (Groot project)</option> <option value="EPIC">Epic (Groot project)</option>
<option value="MILESTONE">Mijlpaal</option> <option value="MILESTONE">Mijlpaal</option>
@@ -290,7 +290,7 @@ $categories = [
<div class="grid grid-cols-2 gap-3"> <div class="grid 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="roadmapPriority" 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"> <select id="roadmapPriority" class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 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">
<option value="HIGH" selected>Hoog (Belangrijke milestone)</option> <option value="HIGH" selected>Hoog (Belangrijke milestone)</option>
<option value="CRITICAL">Kritiek (Must-have)</option> <option value="CRITICAL">Kritiek (Must-have)</option>
<option value="MEDIUM">Normaal</option> <option value="MEDIUM">Normaal</option>
@@ -300,16 +300,16 @@ $categories = [
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Streefdatum (Deadline)</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Streefdatum (Deadline)</label>
<input type="date" id="roadmapDueDate" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-1.5 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs"> <input type="date" id="roadmapDueDate" class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-1.5 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500">
</div> </div>
</div> </div>
<div class="flex space-x-2 pt-2 border-t border-slate-100 dark:border-slate-800/80"> <div class="flex space-x-2 pt-2">
<button onclick="submitConvertToRoadmap()" class="flex-1 bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-2.5 px-4 rounded-xl text-xs transition shadow-xs flex items-center justify-center space-x-2 cursor-pointer"> <button onclick="submitConvertToRoadmap()" class="flex-1 bg-indigo-600 hover:bg-indigo-500 text-white font-semibold py-2.5 px-4 rounded-xl text-xs transition shadow-xs flex items-center justify-center space-x-2 cursor-pointer">
<i data-lucide="check-circle" class="w-4 h-4"></i> <i data-lucide="check-circle" class="w-4 h-4"></i>
<span>Definitief Toevoegen aan Roadmap</span> <span>Definitief Toevoegen aan Roadmap</span>
</button> </button>
<button onclick="closeConvertModal()" class="px-4 py-2.5 bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-xl text-xs font-semibold transition cursor-pointer"> <button onclick="closeConvertModal()" class="px-4 py-2.5 bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-xl text-xs transition cursor-pointer">
Annuleren Annuleren
</button> </button>
</div> </div>
-26
View File
@@ -1,26 +0,0 @@
# 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: 'development' (knippert rood) of 'live' (knippert groen)
APP_ENV="development"
# Applicatie URL (voor uitnodigingslinks en OAuth redirects: https://dev.fociz.nl of https://fociz.nl)
APP_URL="https://dev.fociz.nl"
# Applicatie Geheime Sleutel (willekeurige tekenreeks)
APP_SECRET="fociz-maria-db-super-secret-key-998877"
# Microsoft 365 / Outlook (Optionele globale defaults; kan ook via web UI worden ingesteld)
MICROSOFT_CLIENT_ID=""
MICROSOFT_CLIENT_SECRET=""
MICROSOFT_TENANT_ID="common"
# Atlassian Jira Cloud (Optionele globale defaults; kan ook via web UI worden ingesteld)
JIRA_DOMAIN=""
JIRA_EMAIL=""
JIRA_API_TOKEN=""
-115
View File
@@ -1,115 +0,0 @@
<?php
/**
* Fociz Applicatie- en Databaseconfiguratie
* Laadt automatisch .env (of .env.example indien .env niet bestaat)
*/
$envVars = [];
// 1. Zoek naar .env of val terug op config/.env.example
$envCandidates = [
__DIR__ . '/../.env',
__DIR__ . '/.env.example',
__DIR__ . '/../.env.example',
];
foreach ($envCandidates as $envFile) {
if (file_exists($envFile)) {
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if ($lines !== false) {
foreach ($lines as $line) {
$line = trim($line);
// Negeer lege regels en commentaarregels (# of //)
if ($line === '' || str_starts_with($line, '#') || str_starts_with($line, '//')) {
continue;
}
if (strpos($line, '=') !== false) {
list($name, $value) = explode('=', $line, 2);
$name = trim($name);
$value = trim($value);
// Verwijder omlijstende aanhalingstekens (" of ')
$value = trim($value, " \t\n\r\0\x0B\"'");
// Sla op in array en zet in globale PHP variabelen
$envVars[$name] = $value;
$_ENV[$name] = $value;
$_SERVER[$name] = $value;
@putenv("{$name}={$value}");
}
}
}
break; // Stop zodra we het eerste geldige bestand hebben ingeladen
}
}
/**
* Veilige helper om een omgevingsvariabele op te vragen
*/
if (!function_exists('fociz_env')) {
function fociz_env(string $key, $default = null) {
global $envVars;
if (isset($envVars[$key]) && $envVars[$key] !== '') {
return $envVars[$key];
}
if (isset($_ENV[$key]) && $_ENV[$key] !== '') {
return $_ENV[$key];
}
if (isset($_SERVER[$key]) && $_SERVER[$key] !== '') {
return $_SERVER[$key];
}
$val = @getenv($key);
if ($val !== false && $val !== '') {
return $val;
}
return $default;
}
}
// MariaDB Verbindingsgegevens (uit .env of .env.example)
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', 'focizdev'));
define('DB_USER', fociz_env('DB_USER', 'focizdev_user'));
define('DB_PASS', fociz_env('DB_PASS', 'F0c1z_Dev_Secure_2026!'));
define('DB_CHARSET', 'utf8mb4');
// Bepaal de dynamische of geconfigureerde applicatie URL
if (!function_exists('fociz_detect_app_url')) {
function fociz_detect_app_url(): string {
$envUrl = fociz_env('APP_URL');
if (!empty($envUrl) && !str_contains($envUrl, 'uw-domein.nl') && !str_contains($envUrl, 'www.fociz.nl')) {
return rtrim($envUrl, '/');
}
// Dynamische detectie op basis van het huidige domein (werkt direct op dev.fociz.nl én fociz.nl)
if (!empty($_SERVER['HTTP_HOST'])) {
$isHttps = (
(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
(!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https') ||
(!empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'on') ||
(isset($_SERVER['SERVER_PORT']) && (int)$_SERVER['SERVER_PORT'] === 443)
);
$scheme = $isHttps ? 'https://' : 'http://';
return $scheme . $_SERVER['HTTP_HOST'];
}
// Standaard fallback per omgeving
return (defined('APP_ENV') && APP_ENV === 'live') ? 'https://fociz.nl' : 'https://dev.fociz.nl';
}
}
// Applicatie instellingen
define('APP_NAME', 'Fociz');
define('APP_ENV', fociz_env('APP_ENV', 'development')); // 'development' of 'live'
define('APP_URL', fociz_detect_app_url());
define('APP_SECRET', fociz_env('APP_SECRET', 'fociz-maria-db-super-secret-key-998877'));
// Tijdzone
date_default_timezone_set('Europe/Amsterdam');
// Foutrapportage: in development tonen we fouten direct op het scherm
if (APP_ENV !== 'live') {
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
}
+58 -61
View File
@@ -30,17 +30,15 @@ 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) {
// Dagsessie: verloopt iedere nacht om 23:59:59 (blijft niet meerdere dagen staan) // Zorg voor een ruime sessieduur (30 dagen)
$secondsUntilMidnight = max(60, strtotime('today 23:59:59') - time()); ini_set('session.gc_maxlifetime', '2592000');
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' => $secondsUntilMidnight, // Verloopt vannacht om 23:59:59 'lifetime' => 30 * 24 * 60 * 60, // 30 dagen
'path' => '/', 'path' => '/',
'domain' => '', 'domain' => '',
'secure' => $isSecure, 'secure' => $isSecure,
@@ -76,9 +74,6 @@ function ensure_remember_token_columns(PDO $db): void {
$result = $db->query("SHOW COLUMNS FROM `users` LIKE 'remember_token'"); $result = $db->query("SHOW COLUMNS FROM `users` LIKE 'remember_token'");
if (!$result || $result->rowCount() === 0) { if (!$result || $result->rowCount() === 0) {
$db->exec("ALTER TABLE `users` ADD COLUMN `remember_token` VARCHAR(64) NULL AFTER `backup_codes`, ADD COLUMN `remember_token_expires_at` DATETIME NULL AFTER `remember_token`"); $db->exec("ALTER TABLE `users` ADD COLUMN `remember_token` VARCHAR(64) NULL AFTER `backup_codes`, ADD COLUMN `remember_token_expires_at` DATETIME NULL AFTER `remember_token`");
} else {
// Maak alle bestaande actieve tokens direct leeg zodat geen enkele oude persistente browser-sessie blijft bestaan
$db->exec("UPDATE `users` SET `remember_token` = NULL, `remember_token_expires_at` = NULL WHERE `remember_token` IS NOT NULL");
} }
} catch (Throwable $e) { } catch (Throwable $e) {
// Stil negeren indien al aanwezig of tijdens migraties // Stil negeren indien al aanwezig of tijdens migraties
@@ -122,23 +117,33 @@ function ensure_theme_column(PDO $db): void {
} }
/** /**
* Verouderde functie voor persistent login. * Genereert en bewaart een persistente 'Onthoud mij' token in MariaDB en plaatst een veilige cookie
* Bewust geneutraliseerd: cookies worden direct gewist en geen tokens meer aangemaakt,
* zodat gebruikers iedere dag om 23:59:59 worden uitgelogd en daadwerkelijk opnieuw moeten inloggen.
*/ */
function issue_remember_token(int $userId): string { function issue_remember_token(int $userId): string {
clear_remember_cookie(); $rawToken = bin2hex(random_bytes(32));
try { $tokenHash = hash('sha256', $rawToken);
$expiresAt = date('Y-m-d H:i:s', time() + (30 * 86400)); // 30 dagen geldig
$db = get_db_connection(); $db = get_db_connection();
ensure_remember_token_columns($db); ensure_remember_token_columns($db);
$stmt = $db->prepare("UPDATE users SET remember_token = NULL, remember_token_expires_at = NULL WHERE id = ?");
$stmt->execute([$userId]); $stmt = $db->prepare("UPDATE users SET remember_token = ?, remember_token_expires_at = ? WHERE id = ?");
} catch (Throwable $e) {} $stmt->execute([$tokenHash, $expiresAt, $userId]);
return '';
$isSecure = is_https_request();
setcookie('fociz_remember', $rawToken, [
'expires' => time() + (30 * 86400),
'path' => '/',
'secure' => $isSecure,
'httponly' => true,
'samesite' => 'Lax'
]);
return $rawToken;
} }
/** /**
* Verwijdert de persistente remember cookie uit de browser * Verwijdert de persistente remember cookie
*/ */
function clear_remember_cookie(): void { function clear_remember_cookie(): void {
$isSecure = is_https_request(); $isSecure = is_https_request();
@@ -149,61 +154,59 @@ function clear_remember_cookie(): void {
'httponly' => true, 'httponly' => true,
'samesite' => 'Lax' 'samesite' => 'Lax'
]); ]);
if (isset($_COOKIE['fociz_remember'])) {
unset($_COOKIE['fociz_remember']);
}
} }
/** /**
* Haalt de huidige ingelogde gebruiker op uit de database. * Haalt de huidige ingelogde gebruiker op uit de database.
* Garandeert dat de sessie strikt om 23:59:59 gereset wordt en nooit meerdere dagen blijft staan. * Herstelt automatisch de sessie als een geldige 'fociz_remember' cookie aanwezig is.
* Bevat GEEN persistente cookies of auto-login bypass: de gebruiker moet iedere dag daadwerkelijk opnieuw inloggen.
*/ */
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();
// Verwijder altijd eventuele oude of achtergebleven fociz_remember cookies
if (isset($_COOKIE['fociz_remember'])) {
clear_remember_cookie();
}
// Controleer of de sessie van een eerdere dag is of voorbij 23:59:59
$isExpired = false;
if (!empty($_SESSION['auth_date']) && $_SESSION['auth_date'] !== $today) {
$isExpired = true;
}
if (!empty($_SESSION['session_expires_at']) && $now > (int)$_SESSION['session_expires_at']) {
$isExpired = true;
}
if ($isExpired) {
$_SESSION = ['session_was_expired' => true];
clear_remember_cookie();
if (session_status() === PHP_SESSION_ACTIVE) {
@session_regenerate_id(true);
}
return null;
}
// Controleer actieve PHP sessie (uitsluitend de sessie van vandaag is geldig)
if (!empty($_SESSION['user_id']) && !empty($_SESSION['is_2fa_verified'])) {
$db = get_db_connection(); $db = get_db_connection();
ensure_remember_token_columns($db); ensure_remember_token_columns($db);
// 1. Controleer actieve PHP sessie
if (!empty($_SESSION['user_id']) && !empty($_SESSION['is_2fa_verified'])) {
$stmt = $db->prepare("SELECT id, name, email, role, two_factor_enabled, created_at FROM users WHERE id = ?"); $stmt = $db->prepare("SELECT id, name, email, role, two_factor_enabled, created_at FROM users WHERE id = ?");
$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 = [];
}
// 2. Controleer persistente 'remember me' cookie (voorkomt ongewenst uitloggen bij refresh of herstart)
if (!empty($_COOKIE['fociz_remember'])) {
$rawToken = trim($_COOKIE['fociz_remember']);
$tokenHash = hash('sha256', $rawToken);
$stmt = $db->prepare("
SELECT id, name, email, role, two_factor_enabled, created_at
FROM users
WHERE remember_token = ? AND remember_token_expires_at > NOW()
");
$stmt->execute([$tokenHash]);
$user = $stmt->fetch();
if ($user) {
// Herstel volledige PHP sessie
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_name'] = $user['name'];
$_SESSION['user_email'] = $user['email'];
$_SESSION['user_role'] = $user['role'];
$_SESSION['is_2fa_verified'] = true;
// Verleng direct de geldigheid van de remember token voor nog eens 30 dagen
issue_remember_token((int)$user['id']);
return $user;
} else {
clear_remember_cookie(); clear_remember_cookie();
} }
}
return null; return null;
} }
@@ -230,7 +233,7 @@ function require_auth(bool $json = false): array {
exit; exit;
} }
// 2. Controleer of gebruiker ingelogd én 2FA geverifieerd is voor vandaag // 2. Controleer of gebruiker ingelogd én 2FA geverifieerd is
$user = get_logged_in_user(); $user = get_logged_in_user();
if (!$user) { if (!$user) {
if ($isAjax) { if ($isAjax) {
@@ -239,13 +242,7 @@ function require_auth(bool $json = false): array {
echo json_encode(['success' => false, 'error' => 'Niet geauthenticeerd of sessie verlopen']); echo json_encode(['success' => false, 'error' => 'Niet geauthenticeerd of sessie verlopen']);
exit; exit;
} }
$wasExpired = !empty($_SESSION['session_was_expired']);
unset($_SESSION['session_was_expired']);
if ($wasExpired) {
header('Location: /auth/login.php?expired=1');
} else {
header('Location: /auth/login.php'); header('Location: /auth/login.php');
}
exit; exit;
} }
-61
View File
@@ -57,40 +57,6 @@ $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 en dwingt dagelijks opnieuw inloggen af -->
<script>
(function() {
try {
const sessionDate = "<?= date('Y-m-d') ?>";
const checkMidnight = function() {
const now = new Date();
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
const todayStr = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0');
if (todayStr !== sessionDate || now.getTime() > midnight.getTime()) {
window.location.href = '/auth/login.php?expired=1';
}
};
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);
}
// Controleer direct zodra de gebruiker de browser weer activeert (bij bijv. standby / slaapstand overnacht)
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'visible') {
checkMidnight();
}
});
window.addEventListener('focus', checkMidnight);
setInterval(checkMidnight, 30000);
} catch(e) {}
})();
</script>
<style> <style>
html.dark body { html.dark body {
background-color: #0c0f17; background-color: #0c0f17;
@@ -111,33 +77,6 @@ $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, .fociz-card-interactive {
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, html.dark .fociz-card-interactive {
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">
+8
View File
@@ -563,6 +563,7 @@ function microsoft_delete_event(int $userId, string $eventId): bool {
} }
/** /**
<<<<<<< HEAD
* Werkt een bestaande afspraak bij in Microsoft Outlook via Graph API (PATCH) * Werkt een bestaande afspraak bij in Microsoft Outlook via Graph API (PATCH)
*/ */
function microsoft_update_event(int $userId, string $eventId, array $eventData): bool { function microsoft_update_event(int $userId, string $eventId, array $eventData): bool {
@@ -632,6 +633,8 @@ function microsoft_update_event(int $userId, string $eventId, array $eventData):
} }
/** /**
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
* Ontkoppelt Microsoft integratie voor een gebruiker * Ontkoppelt Microsoft integratie voor een gebruiker
* Wist uitsluitend de persoonlijke tokens; behoudt de centrale Azure App gegevens indien aanwezig. * Wist uitsluitend de persoonlijke tokens; behoudt de centrale Azure App gegevens indien aanwezig.
*/ */
@@ -663,6 +666,7 @@ function microsoft_disconnect(int $userId): bool {
} }
} }
<<<<<<< HEAD
/** /**
* Haalt één specifieke afspraak op uit Microsoft Outlook via Graph API. * Haalt één specifieke afspraak op uit Microsoft Outlook via Graph API.
* Retourneert: * Retourneert:
@@ -881,3 +885,7 @@ function microsoft_reconcile_tasks_with_outlook(int $userId, string $startDate,
'updated' => $updatedCount, 'updated' => $updatedCount,
]; ];
} }
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
+256 -121
View File
@@ -42,7 +42,53 @@ $dutchShortMonths = ['', 'jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug',
$formattedSelectedDate = $dutchFullDays[(int)date('N', $selectedTs)] . ' ' . date('j', $selectedTs) . ' ' . $dutchMonths[(int)date('n', $selectedTs)] . ' ' . date('Y', $selectedTs); $formattedSelectedDate = $dutchFullDays[(int)date('N', $selectedTs)] . ' ' . date('j', $selectedTs) . ' ' . $dutchMonths[(int)date('n', $selectedTs)] . ' ' . date('Y', $selectedTs);
$formattedWeekRange = date('j', $mondayTs) . ' ' . $dutchShortMonths[(int)date('n', $mondayTs)] . ' – ' . date('j', $sundayTs) . ' ' . $dutchShortMonths[(int)date('n', $sundayTs)] . ' ' . date('Y', $sundayTs); $formattedWeekRange = date('j', $mondayTs) . ' ' . $dutchShortMonths[(int)date('n', $mondayTs)] . ' – ' . date('j', $sundayTs) . ' ' . $dutchShortMonths[(int)date('n', $sundayTs)] . ' ' . date('Y', $sundayTs);
<<<<<<< HEAD
// 1. Haal integratiestatussen op // 1. Haal integratiestatussen op
=======
// 1. Haal dagplanning op of maak aan voor $selectedDate
$stmtPlan = $db->prepare("SELECT * FROM daily_plans WHERE user_id = ? AND plan_date = ?");
$stmtPlan->execute([$userId, $selectedDate]);
$dailyPlan = $stmtPlan->fetch();
if (!$dailyPlan) {
$defaultGoal = ($selectedDate === $today) ? 'Mijn belangrijkste doel van vandaag behalen' : 'Focusdoel voor deze dag bepalen';
$stmtCreatePlan = $db->prepare("
INSERT INTO daily_plans (user_id, plan_date, focus_goal)
VALUES (?, ?, ?)
");
$stmtCreatePlan->execute([$userId, $selectedDate, $defaultGoal]);
$planId = (int)$db->lastInsertId();
$dailyPlan = ['id' => $planId, 'plan_date' => $selectedDate, 'focus_goal' => $defaultGoal, 'notes' => ''];
}
// 2. Haal taken op voor de geselecteerde dag
$stmtTasks = $db->prepare("
SELECT * FROM tasks
WHERE user_id = ? AND (daily_plan_id = ? " . ($selectedDate === $today ? "OR daily_plan_id IS NULL" : "") . ")
ORDER BY is_completed ASC, priority ASC, time_block_start ASC, created_at DESC
");
$stmtTasks->execute([$userId, $dailyPlan['id']]);
$tasks = $stmtTasks->fetchAll();
// 3. Haal weekstatistieken voor taken op (aantal per dag)
$stmtWeekTasks = $db->prepare("
SELECT dp.plan_date, COUNT(t.id) as total_tasks, SUM(CASE WHEN t.is_completed = 1 THEN 1 ELSE 0 END) as completed_tasks
FROM daily_plans dp
LEFT JOIN tasks t ON t.daily_plan_id = dp.id AND t.user_id = ?
WHERE dp.user_id = ? AND dp.plan_date BETWEEN ? AND ?
GROUP BY dp.plan_date
");
$stmtWeekTasks->execute([$userId, $userId, $weekStart, $weekEnd]);
$weekTaskStats = [];
foreach ($stmtWeekTasks->fetchAll() as $row) {
$weekTaskStats[$row['plan_date']] = [
'total' => (int)$row['total_tasks'],
'completed' => (int)$row['completed_tasks'],
];
}
// 4. Haal integratiestatussen op
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
$stmtInt = $db->prepare("SELECT * FROM integrations WHERE user_id = ?"); $stmtInt = $db->prepare("SELECT * FROM integrations WHERE user_id = ?");
$stmtInt->execute([$userId]); $stmtInt->execute([$userId]);
$userIntegrations = []; $userIntegrations = [];
@@ -51,9 +97,12 @@ foreach ($stmtInt->fetchAll() as $row) {
} }
$isOutlookConnected = !empty($userIntegrations['OUTLOOK']['access_token']) && empty($userIntegrations['OUTLOOK']['is_demo_mode']); $isOutlookConnected = !empty($userIntegrations['OUTLOOK']['access_token']) && empty($userIntegrations['OUTLOOK']['is_demo_mode']);
<<<<<<< HEAD
$outlookIntegrationSettings = json_decode($userIntegrations['OUTLOOK']['settings'] ?? '{}', true) ?: []; $outlookIntegrationSettings = json_decode($userIntegrations['OUTLOOK']['settings'] ?? '{}', true) ?: [];
$syncIntervalSeconds = isset($outlookIntegrationSettings['sync_interval_seconds']) ? (int)$outlookIntegrationSettings['sync_interval_seconds'] : 30; $syncIntervalSeconds = isset($outlookIntegrationSettings['sync_interval_seconds']) ? (int)$outlookIntegrationSettings['sync_interval_seconds'] : 30;
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
$weekOutlookEvents = []; $weekOutlookEvents = [];
$isLiveOutlook = false; $isLiveOutlook = false;
@@ -61,9 +110,12 @@ if ($isOutlookConnected) {
// Haal afspraken op voor het volledige datumbereik van de week // Haal afspraken op voor het volledige datumbereik van de week
$weekOutlookEvents = microsoft_fetch_events_range($userId, $weekStart, $weekEnd); $weekOutlookEvents = microsoft_fetch_events_range($userId, $weekStart, $weekEnd);
$isLiveOutlook = true; $isLiveOutlook = true;
<<<<<<< HEAD
// Synchroniseer / reconcilieer Fociz taken direct met actuele Outlook data // Synchroniseer / reconcilieer Fociz taken direct met actuele Outlook data
microsoft_reconcile_tasks_with_outlook($userId, $weekStart, $weekEnd, $weekOutlookEvents); microsoft_reconcile_tasks_with_outlook($userId, $weekStart, $weekEnd, $weekOutlookEvents);
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
} else { } else {
// Demo data indien Microsoft Outlook nog niet gekoppeld is // Demo data indien Microsoft Outlook nog niet gekoppeld is
$weekOutlookEvents = [ $weekOutlookEvents = [
@@ -100,6 +152,7 @@ if ($isOutlookConnected) {
]; ];
} }
<<<<<<< HEAD
// 2. Haal dagplanning op of maak aan voor $selectedDate // 2. Haal dagplanning op of maak aan voor $selectedDate
$stmtPlan = $db->prepare("SELECT * FROM daily_plans WHERE user_id = ? AND plan_date = ?"); $stmtPlan = $db->prepare("SELECT * FROM daily_plans WHERE user_id = ? AND plan_date = ?");
$stmtPlan->execute([$userId, $selectedDate]); $stmtPlan->execute([$userId, $selectedDate]);
@@ -142,6 +195,8 @@ foreach ($stmtWeekTasks->fetchAll() as $row) {
]; ];
} }
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
// Groepeer Outlook afspraken per datum // Groepeer Outlook afspraken per datum
$outlookEventsByDate = []; $outlookEventsByDate = [];
foreach ($weekOutlookEvents as $evt) { foreach ($weekOutlookEvents as $evt) {
@@ -194,6 +249,7 @@ foreach ($dayOutlookEvents as $evt) {
$displayedOutlookEvents[] = $evt; $displayedOutlookEvents[] = $evt;
} }
<<<<<<< HEAD
// Bereken initiële status-hash voor achtergrondsynchronisatie // Bereken initiële status-hash voor achtergrondsynchronisatie
$dayEventsForHash = []; $dayEventsForHash = [];
foreach ($displayedOutlookEvents as $e) { foreach ($displayedOutlookEvents as $e) {
@@ -218,6 +274,8 @@ $initialSyncHash = md5(json_encode([
'tasks' => $tasksForHash 'tasks' => $tasksForHash
])); ]));
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
// 6. Tijdlijn uren & Werkdag Standaarden (Release v1.4) // 6. Tijdlijn uren & Werkdag Standaarden (Release v1.4)
$workdayStartStr = $workdaySettings['workday_start'] ?? '08:30'; $workdayStartStr = $workdaySettings['workday_start'] ?? '08:30';
$workdayEndStr = $workdaySettings['workday_end'] ?? '17:30'; $workdayEndStr = $workdaySettings['workday_end'] ?? '17:30';
@@ -260,19 +318,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="fociz-card p-6 sm:p-7 relative overflow-hidden"> <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="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-bold uppercase tracking-wider mb-1"> <div class="flex items-center space-x-2 text-indigo-600 dark:text-indigo-400 text-xs font-semibold 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.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> <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>
<?php else: ?> <?php else: ?>
<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> <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>
<?php endif; ?> <?php endif; ?>
</div> </div>
<h1 class="text-2xl sm:text-3xl font-black tracking-tight text-slate-900 dark:text-white"> <h1 class="text-2xl sm:text-3xl font-black text-slate-900 dark:text-white tracking-tight">
Dagplanning & Structuur Dagplanning & Structuur
</h1> </h1>
</div> </div>
@@ -280,28 +338,36 @@ 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.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"> <<<<<<< HEAD
<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">
<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/80 dark:text-sky-400/70 font-mono hidden sm:inline">(synced <span id="syncTimeDisplay"><?= date('H:i') ?></span>)</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>
<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>
=======
<div 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">
<span class="w-2 h-2 rounded-full bg-sky-500 animate-pulse"></span>
<span>Outlook 365 Live</span>
<button onclick="location.reload()" title="Agenda Verversen" class="p-0.5 text-sky-600 hover:text-sky-900 dark:text-sky-400 dark:hover:text-white rounded transition">
<i data-lucide="refresh-cw" class="w-3 h-3"></i>
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
</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-semibold 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-medium 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.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"> <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">
<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-semibold 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-medium 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,32 +375,26 @@ for ($h = $startHour; $h <= $endHour; $h++) {
</div> </div>
</div> </div>
<!-- Dagdoel Focus Spotlight Blok --> <!-- Dagdoel invoerveld -->
<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"> <div class="mt-5 pt-4 border-t border-slate-100 dark:border-slate-800/60">
<div class="flex items-center space-x-2 mb-2"> <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="w-6 h-6 rounded-lg bg-indigo-600 text-white flex items-center justify-center shadow-xs"> <i data-lucide="target" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
<i data-lucide="target" class="w-3.5 h-3.5"></i> <span>Mijn Belangrijkste Dagdoel voor <?= htmlspecialchars($dutchFullDays[(int)date('N', $selectedTs)]) ?></span>
</div>
<label for="focusGoalInput" class="text-xs font-bold text-indigo-950 dark:text-indigo-200 uppercase tracking-wider">
Focus van de Dag &bull; <?= htmlspecialchars($dutchFullDays[(int)date('N', $selectedTs)]) ?>
</label> </label>
</div> <div class="flex items-center space-x-2">
<div class="flex items-center gap-2">
<div class="relative flex-1">
<input <input
type="text" type="text"
id="focusGoalInput" id="focusGoalInput"
value="<?= htmlspecialchars($dailyPlan['focus_goal'] ?? '') ?>" value="<?= htmlspecialchars($dailyPlan['focus_goal'] ?? '') ?>"
placeholder="Wat moet er deze dag absoluut gebeuren voor succes?" 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" 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"
> >
</div>
<button <button
onclick="saveGoal()" onclick="saveGoal()"
id="saveGoalBtn" id="saveGoalBtn"
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" 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"
> >
<i data-lucide="check" class="w-4 h-4 stroke-[2.5]"></i> <i data-lucide="check-circle-2" class="w-4 h-4"></i>
<span>Opslaan</span> <span>Opslaan</span>
</button> </button>
</div> </div>
@@ -342,20 +402,20 @@ for ($h = $startHour; $h <= $endHour; $h++) {
</div> </div>
<!-- Week Navigatie & Dagselector --> <!-- Week Navigatie & Dagselector -->
<div class="fociz-card p-5 sm:p-6"> <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="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.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)) ?>)"> <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)) ?>)">
<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.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"> <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">
Vandaag Vandaag
</a> </a>
<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)) ?>)"> <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)) ?>)">
<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>
@@ -363,7 +423,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-bold uppercase tracking-wider text-indigo-600 dark:text-indigo-400"> <div class="text-xs font-semibold 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">
@@ -379,58 +439,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 shadow-2xs" 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"
> >
</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-3"> <div class="grid grid-cols-2 sm:grid-cols-4 md:grid-cols-7 gap-2.5">
<?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="fociz-card-interactive group relative flex flex-col p-3.5 rounded-2xl border transition-all text-left <?= $wd['is_selected'] class="group relative flex flex-col p-3 rounded-xl border transition text-left <?= $wd['is_selected']
? '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-indigo-50/80 dark:bg-indigo-500/10 border-indigo-500/40 ring-1 ring-indigo-500/30 shadow-xs'
: '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' ?>" : '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' ?>"
> >
<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-bold uppercase tracking-wider <?= $wd['is_selected'] ? 'text-indigo-600 dark:text-indigo-400' : 'text-slate-500 dark:text-slate-400' ?>"> <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' ?>">
<?= $wd['short_name'] ?> <?= $wd['short_name'] ?>
</span> </span>
<?php if ($wd['is_today']): ?> <?php if ($wd['is_today']): ?>
<span class="px-2 py-0.5 rounded-full text-[9px] font-extrabold uppercase bg-indigo-600 text-white shadow-xs"> <span class="px-1.5 py-0.5 rounded-full text-[9px] font-bold uppercase bg-indigo-600 text-white">
Nu Nu
</span> </span>
<?php endif; ?> <?php endif; ?>
</div> </div>
<div class="flex items-baseline space-x-1.5 mb-3"> <div class="flex items-baseline space-x-1 mb-2">
<span class="text-2xl font-black <?= $wd['is_selected'] ? 'text-indigo-600 dark:text-indigo-400' : 'text-slate-900 dark:text-white' ?>"> <span class="text-xl 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-[11px] font-semibold text-slate-400 dark:text-slate-500 uppercase"> <span class="text-[10px] font-medium text-slate-400 dark:text-slate-500">
<?= $wd['month_short'] ?> <?= $wd['month_short'] ?>
</span> </span>
</div> </div>
<!-- Mini chips voor taken en meetings op deze dag --> <!-- Indicatoren voor taken en meetings op deze dag -->
<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 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 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"> <div class="flex items-center justify-between 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-indigo-500"></i> <i data-lucide="check-square" class="w-3 h-3 text-slate-400 dark:text-slate-500"></i>
<span>Taken</span> <span>Taken</span>
</span> </span>
<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' ?>"> <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' ?>">
<?= $wd['completed_count'] ?>/<?= $wd['task_count'] ?> <?= $wd['completed_count'] ?>/<?= $wd['task_count'] ?>
</span> </span>
</div> </div>
<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"> <div class="flex items-center justify-between 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="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-bold"> <span class="font-semibold <?= $wd['meeting_count'] > 0 ? 'text-sky-600 dark:text-sky-400' : 'text-slate-400' ?>">
<?= $wd['meeting_count'] ?> <?= $wd['meeting_count'] ?>
</span> </span>
</div> </div>
@@ -446,86 +506,93 @@ 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 Workstation --> <!-- Focus Modus Timer -->
<div class="fociz-card p-6 sm:p-7 relative overflow-hidden"> <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="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-4">
<div class="flex items-center space-x-3"> <div class="flex items-center space-x-2">
<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"> <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">
<i data-lucide="flame" class="w-5 h-5"></i> <i data-lucide="flame" class="w-4 h-4"></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 werkstation & concentratie</p> <p class="text-[11px] text-slate-500 dark:text-slate-400">Pomodoro & geconcentreerd werken</p>
</div> </div>
</div> </div>
<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"> <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">
<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_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_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_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_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> <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>
</div> </div>
</div> </div>
<div class="text-center my-6 relative"> <div class="text-center my-6">
<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 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 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"> <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">
<span class="w-2 h-2 rounded-full bg-emerald-500 animate-pulse"></span> <span class="text-indigo-600 dark:text-indigo-400 font-medium">Actieve focus:</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-semibold">Kies een taak hieronder</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 h-2 rounded-full overflow-hidden mt-5 border border-slate-200/80 dark:border-slate-800"> <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 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 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> </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-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"> <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">
<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-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"> <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">
<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 Blok --> <!-- Takenlijst -->
<div class="fociz-card p-6 sm:p-7"> <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="flex items-center justify-between mb-5 pb-3 border-b border-slate-100 dark:border-slate-800/60"> <div class="flex items-center justify-between mb-4 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="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> <span class="text-xs font-normal text-slate-500 dark:text-slate-400">(<?= count($tasks) ?>)</span>
</h3> </h3>
</div> </div>
<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"> <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">
<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-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 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> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Taaktitel</label> <label class="block text-[11px] font-medium text-slate-600 dark:text-slate-400 mb-1">Taaktitel</label>
<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"> <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">
</div> </div>
<<<<<<< HEAD
<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-[#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"> <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">
=======
<div class="grid grid-cols-1 sm:grid-cols-3 gap-3">
<div>
<label class="block text-[11px] font-medium text-slate-600 dark:text-slate-400 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">
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
<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>
</select> </select>
</div> </div>
<div> <div>
<<<<<<< HEAD
<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-[#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')"> <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')">
<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> <i data-lucide="clock" class="w-3.5 h-3.5 text-slate-400 absolute right-2.5 top-2 pointer-events-none"></i>
</div> </div>
</div> </div>
<div> <div>
@@ -534,8 +601,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-[#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')"> <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')">
<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> <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>
</div> </div>
</div> </div>
<div> <div>
@@ -547,7 +614,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-[#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')"> <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')">
<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>
@@ -560,16 +627,32 @@ 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-[#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')"> <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')">
</div> </div>
=======
<label class="block text-[11px] font-medium text-slate-600 dark:text-slate-400 mb-1">Tijdblok (Starttijd)</label>
<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 px-2.5 py-1.5 text-slate-900 dark:text-white text-xs font-mono focus:outline-none">
</div>
<div>
<label class="block text-[11px] font-medium text-slate-600 dark:text-slate-400 mb-1">Tijdsduur</label>
<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">
<?php
$defDuration = (int)($workdaySettings['default_task_duration'] ?? 30);
$durations = [15 => '15 minuten', 30 => '30 minuten', 45 => '45 minuten', 60 => '60 minuten (1 uur)', 90 => '90 minuten (1,5 uur)', 120 => '120 minuten (2 uur)'];
foreach ($durations as $mins => $label):
?>
<option value="<?= $mins ?>" <?= $defDuration === $mins ? 'selected' : '' ?>><?= $label ?></option>
<?php endforeach; ?>
</select>
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
</div> </div>
</div> </div>
<?php if ($isOutlookConnected): ?> <?php if ($isOutlookConnected): ?>
<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"> <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">
<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-semibold"> <span class="flex items-center space-x-1.5 font-medium">
<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>
@@ -578,22 +661,20 @@ 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-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="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="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> <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>
</div> </div>
</div> </div>
<!-- Taken weergave --> <!-- Taken weergave -->
<div class="space-y-2.5" id="tasksContainer"> <div class="space-y-2" id="tasksContainer">
<?php if (empty($tasks)): ?> <?php if (empty($tasks)): ?>
<div class="text-center py-10 text-slate-400 dark:text-slate-500 text-xs"> <div class="text-center py-8 text-slate-400 dark:text-slate-500 text-xs">
<i data-lucide="check-circle" class="w-8 h-8 text-slate-300 dark:text-slate-700 mx-auto mb-2"></i> Nog geen taken gepland voor <?= htmlspecialchars($formattedSelectedDate) ?>. Klik op 'Nieuwe Taak' of importeer een Jira ticket hieronder.
<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="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="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="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']): ?>
@@ -613,7 +694,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<span>OUTLOOK</span> <span>OUTLOOK</span>
</span> </span>
<?php endif; ?> <?php endif; ?>
<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' ?>"> <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' ?>">
<?= htmlspecialchars($task['title']) ?> <?= htmlspecialchars($task['title']) ?>
</span> </span>
</div> </div>
@@ -622,7 +703,11 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<?php if (!empty($task['time_block_start'])): ?> <?php if (!empty($task['time_block_start'])): ?>
<span class="text-[10px] text-slate-500 dark:text-slate-400 font-mono flex items-center space-x-1"> <span class="text-[10px] text-slate-500 dark:text-slate-400 font-mono flex items-center space-x-1">
<i data-lucide="clock" class="w-2.5 h-2.5"></i> <i data-lucide="clock" class="w-2.5 h-2.5"></i>
<<<<<<< HEAD
<span><?= htmlspecialchars($task['time_block_start']) ?><?= !empty($task['time_block_end']) ? ' - ' . htmlspecialchars($task['time_block_end']) : '' ?><?= !empty($task['duration_minutes']) ? ' (' . (int)$task['duration_minutes'] . 'm)' : '' ?></span> <span><?= htmlspecialchars($task['time_block_start']) ?><?= !empty($task['time_block_end']) ? ' - ' . htmlspecialchars($task['time_block_end']) : '' ?><?= !empty($task['duration_minutes']) ? ' (' . (int)$task['duration_minutes'] . 'm)' : '' ?></span>
=======
<span><?= htmlspecialchars($task['time_block_start']) ?><?= !empty($task['time_block_end']) ? ' - ' . htmlspecialchars($task['time_block_end']) : '' ?></span>
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
</span> </span>
<?php endif; ?> <?php endif; ?>
<?php if (!empty($task['external_url'])): ?> <?php if (!empty($task['external_url'])): ?>
@@ -648,11 +733,16 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<?php endif; ?> <?php endif; ?>
<?php if (!$task['is_completed']): ?> <?php if (!$task['is_completed']): ?>
<<<<<<< HEAD
<button onclick="selectFocusTask('<?= htmlspecialchars(addslashes($task['title'])) ?>')" title="Koppel aan Focus Timer" class="p-1.5 rounded-lg text-slate-400 hover:text-amber-500 hover:bg-amber-500/10 transition cursor-pointer"> <button onclick="selectFocusTask('<?= htmlspecialchars(addslashes($task['title'])) ?>')" title="Koppel aan Focus Timer" class="p-1.5 rounded-lg text-slate-400 hover:text-amber-500 hover:bg-amber-500/10 transition cursor-pointer">
=======
<button onclick="selectFocusTask('<?= htmlspecialchars(addslashes($task['title'])) ?>')" title="Koppel aan Focus Timer" class="p-1.5 rounded-lg text-slate-400 hover:text-amber-500 hover:bg-amber-500/10 transition">
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
<i data-lucide="flame" class="w-3.5 h-3.5"></i> <i data-lucide="flame" class="w-3.5 h-3.5"></i>
</button> </button>
<?php endif; ?> <?php endif; ?>
<<<<<<< HEAD
<button onclick="openEditTaskModal(<?= htmlspecialchars(json_encode([ <button onclick="openEditTaskModal(<?= htmlspecialchars(json_encode([
'id' => (int)$task['id'], 'id' => (int)$task['id'],
'title' => $task['title'], 'title' => $task['title'],
@@ -667,6 +757,9 @@ for ($h = $startHour; $h <= $endHour; $h++) {
</button> </button>
<button onclick="deleteTask(<?= $task['id'] ?>)" title="Verwijderen" class="p-1.5 rounded-lg text-slate-400 hover:text-red-600 dark:hover:text-red-400 hover:bg-red-500/10 opacity-0 group-hover:opacity-100 transition cursor-pointer"> <button onclick="deleteTask(<?= $task['id'] ?>)" title="Verwijderen" class="p-1.5 rounded-lg text-slate-400 hover:text-red-600 dark:hover:text-red-400 hover:bg-red-500/10 opacity-0 group-hover:opacity-100 transition cursor-pointer">
=======
<button onclick="deleteTask(<?= $task['id'] ?>)" title="Verwijderen" class="p-1.5 rounded-lg text-slate-400 hover:text-red-600 dark:hover:text-red-400 hover:bg-red-500/10 opacity-0 group-hover:opacity-100 transition">
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
<i data-lucide="trash-2" class="w-3.5 h-3.5"></i> <i data-lucide="trash-2" class="w-3.5 h-3.5"></i>
</button> </button>
</div> </div>
@@ -677,19 +770,19 @@ for ($h = $startHour; $h <= $endHour; $h++) {
</div> </div>
<!-- Jira Snelle Import Widget --> <!-- Jira Snelle Import Widget -->
<div id="jiraPanel" class="fociz-card p-6"> <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 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-bold text-slate-900 dark:text-white uppercase tracking-wider"> <h3 class="text-xs font-semibold 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-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' ?>"> <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' ?>">
<?= 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 font-medium"> <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">
<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>
@@ -702,7 +795,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="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="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="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">
@@ -732,28 +825,28 @@ for ($h = $startHour; $h <= $endHour; $h++) {
</div> </div>
<!-- Dagnotities & Reflectie --> <!-- Dagnotities & Reflectie -->
<div class="fociz-card p-6"> <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="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-bold text-slate-900 dark:text-white uppercase tracking-wider">Dagnotities & Kladblok</h3> <h3 class="text-xs font-semibold 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-[#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" 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"
><?= 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="fociz-card p-5 sm:p-6 overflow-hidden"> <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="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-bold text-slate-900 dark:text-white uppercase tracking-wider">Tijdlijn & Time-blocking</h3> <h3 class="text-xs font-semibold 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']): ?>
@@ -763,7 +856,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-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> <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>
<?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>
@@ -786,16 +879,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-semibold text-slate-500 dark:text-slate-400 pt-1.5 flex-shrink-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">
<?= $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-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="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="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/20 text-amber-900 dark:text-amber-200 font-mono text-[10px] font-bold flex-shrink-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">
<?= 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">
@@ -809,7 +902,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<!-- Outlook meetings --> <!-- Outlook meetings -->
<?php foreach ($slotEvents as $evt): ?> <?php foreach ($slotEvents as $evt): ?>
<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="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="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">
@@ -838,7 +931,7 @@ for ($h = $startHour; $h <= $endHour; $h++) {
<!-- Geplande taken --> <!-- Geplande taken -->
<?php foreach ($slotTasks as $t): ?> <?php foreach ($slotTasks as $t): ?>
<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="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="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">
@@ -869,9 +962,8 @@ 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-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"> <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">
<span>+ Plan taak om <?= $hour ?></span> + Plan taak om <?= $hour ?>
<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>
@@ -883,9 +975,10 @@ for ($h = $startHour; $h <= $endHour; $h++) {
</div> </div>
</div> </div>
<<<<<<< HEAD
<!-- 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-950/70 backdrop-blur-sm hidden items-center justify-center p-4"> <div id="editTaskModal" class="fixed inset-0 z-50 bg-slate-900/60 backdrop-blur-xs hidden items-center justify-center p-4">
<div class="fociz-card p-6 w-full max-w-lg shadow-2xl space-y-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="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">
@@ -905,13 +998,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-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"> <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">
</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-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"> <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">
<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>
@@ -923,7 +1016,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-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')"> <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')">
<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>
@@ -936,7 +1029,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-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')"> <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')">
</div> </div>
</div> </div>
</div> </div>
@@ -945,7 +1038,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-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')"> <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')">
<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>
@@ -955,13 +1048,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-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')"> <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')">
<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-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"> <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">
<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>
@@ -977,6 +1070,8 @@ for ($h = $startHour; $h <= $endHour; $h++) {
</div> </div>
</div> </div>
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
<script> <script>
// --- Focus Timer Logica (Release v1.4) --- // --- Focus Timer Logica (Release v1.4) ---
const pomodoroFocusTime = <?= (int)$workdaySettings['pomodoro_focus'] ?>; const pomodoroFocusTime = <?= (int)$workdaySettings['pomodoro_focus'] ?>;
@@ -1018,7 +1113,10 @@ function toggleTimer() {
clearInterval(timerInterval); clearInterval(timerInterval);
isRunning = false; isRunning = false;
document.getElementById('timerToggleText').innerText = 'Hervatten'; document.getElementById('timerToggleText').innerText = 'Hervatten';
<<<<<<< HEAD
saveTimerStateBeforeReload(); saveTimerStateBeforeReload();
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
} else { } else {
isRunning = true; isRunning = true;
document.getElementById('timerToggleText').innerText = 'Pauzeren'; document.getElementById('timerToggleText').innerText = 'Pauzeren';
@@ -1029,7 +1127,10 @@ function toggleTimer() {
} else { } else {
clearInterval(timerInterval); clearInterval(timerInterval);
isRunning = false; isRunning = false;
<<<<<<< HEAD
sessionStorage.removeItem('fociz_timer_state'); sessionStorage.removeItem('fociz_timer_state');
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
document.getElementById('timerToggleText').innerText = 'Start Focus'; document.getElementById('timerToggleText').innerText = 'Start Focus';
alert('Focus sessie voltooid! Neem even een korte pauze.'); alert('Focus sessie voltooid! Neem even een korte pauze.');
} }
@@ -1041,11 +1142,15 @@ function resetTimer() {
clearInterval(timerInterval); clearInterval(timerInterval);
isRunning = false; isRunning = false;
timerSeconds = totalDuration; timerSeconds = totalDuration;
<<<<<<< HEAD
sessionStorage.removeItem('fociz_timer_state'); sessionStorage.removeItem('fociz_timer_state');
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
document.getElementById('timerToggleText').innerText = 'Start Focus'; document.getElementById('timerToggleText').innerText = 'Start Focus';
updateTimerDisplay(); updateTimerDisplay();
} }
<<<<<<< HEAD
function saveTimerStateBeforeReload() { function saveTimerStateBeforeReload() {
try { try {
if (isRunning || timerSeconds < totalDuration) { if (isRunning || timerSeconds < totalDuration) {
@@ -1094,6 +1199,8 @@ window.addEventListener('beforeunload', () => {
saveTimerStateBeforeReload(); saveTimerStateBeforeReload();
}); });
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
function selectFocusTask(title) { function selectFocusTask(title) {
document.getElementById('activeTaskDisplay').innerText = title; document.getElementById('activeTaskDisplay').innerText = title;
} }
@@ -1124,6 +1231,7 @@ async function saveGoal() {
} }
} }
<<<<<<< HEAD
// --- Tijdblok Hulpfuncties & Vrije Duur Berekening --- // --- Tijdblok Hulpfuncties & Vrije Duur Berekening ---
function parseTimeToMinutes(str) { function parseTimeToMinutes(str) {
if (!str || typeof str !== 'string') return null; if (!str || typeof str !== 'string') return null;
@@ -1257,6 +1365,8 @@ function setSelectedNewTaskDuration(mins) {
if (durationDisplay) durationDisplay.innerText = `${mins}m`; if (durationDisplay) durationDisplay.innerText = `${mins}m`;
} }
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
function toggleAddTaskForm() { function toggleAddTaskForm() {
const form = document.getElementById('addTaskForm'); const form = document.getElementById('addTaskForm');
form.classList.toggle('hidden'); form.classList.toggle('hidden');
@@ -1266,6 +1376,7 @@ function toggleAddTaskForm() {
} }
function quickSchedule(hour) { function quickSchedule(hour) {
<<<<<<< HEAD
const form = document.getElementById('addTaskForm'); const form = document.getElementById('addTaskForm');
if (form && form.classList.contains('hidden')) { if (form && form.classList.contains('hidden')) {
form.classList.remove('hidden'); form.classList.remove('hidden');
@@ -1278,12 +1389,20 @@ function quickSchedule(hour) {
const outlookCheckbox = document.getElementById('newTaskSyncOutlook'); const outlookCheckbox = document.getElementById('newTaskSyncOutlook');
if (outlookCheckbox) outlookCheckbox.checked = true; if (outlookCheckbox) outlookCheckbox.checked = true;
document.getElementById('newTaskTitle')?.focus(); document.getElementById('newTaskTitle')?.focus();
=======
toggleAddTaskForm();
const timeInput = document.getElementById('newTaskTime');
if (timeInput) timeInput.value = hour;
const outlookCheckbox = document.getElementById('newTaskSyncOutlook');
if (outlookCheckbox) outlookCheckbox.checked = true;
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
} }
async function submitNewTask() { async function submitNewTask() {
const title = document.getElementById('newTaskTitle').value.trim(); const title = document.getElementById('newTaskTitle').value.trim();
const priority = document.getElementById('newTaskPriority').value; const priority = document.getElementById('newTaskPriority').value;
const time = document.getElementById('newTaskTime').value.trim(); const time = document.getElementById('newTaskTime').value.trim();
<<<<<<< HEAD
const endTime = document.getElementById('newTaskEndTime') ? document.getElementById('newTaskEndTime').value.trim() : ''; const endTime = document.getElementById('newTaskEndTime') ? document.getElementById('newTaskEndTime').value.trim() : '';
const duration = getSelectedNewTaskDurationMinutes(); const duration = getSelectedNewTaskDurationMinutes();
const syncOutlook = document.getElementById('newTaskSyncOutlook') ? document.getElementById('newTaskSyncOutlook').checked : false; const syncOutlook = document.getElementById('newTaskSyncOutlook') ? document.getElementById('newTaskSyncOutlook').checked : false;
@@ -1292,6 +1411,12 @@ async function submitNewTask() {
alert('Vul een taaktitel in.'); alert('Vul een taaktitel in.');
return; return;
} }
=======
const duration = document.getElementById('newTaskDuration') ? parseInt(document.getElementById('newTaskDuration').value) : 30;
const syncOutlook = document.getElementById('newTaskSyncOutlook') ? document.getElementById('newTaskSyncOutlook').checked : false;
if (!title) return;
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
try { try {
const res = await fetch('/api/planner.php?action=add_task', { const res = await fetch('/api/planner.php?action=add_task', {
@@ -1300,8 +1425,12 @@ async function submitNewTask() {
body: JSON.stringify({ body: JSON.stringify({
title, title,
priority, priority,
<<<<<<< HEAD
time_block_start: time, time_block_start: time,
time_block_end: endTime, time_block_end: endTime,
=======
time_block_start: time,
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
duration_minutes: duration, duration_minutes: duration,
sync_to_outlook: syncOutlook, sync_to_outlook: syncOutlook,
date: activePlannerDate date: activePlannerDate
@@ -1321,6 +1450,7 @@ async function submitNewTask() {
} }
} }
<<<<<<< HEAD
// --- Taak & Tijdblok Bewerken Modal Logica --- // --- Taak & Tijdblok Bewerken Modal Logica ---
function openEditTaskModal(task) { function openEditTaskModal(task) {
if (!task) return; if (!task) return;
@@ -1509,6 +1639,8 @@ async function submitEditTask() {
} }
} }
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
async function syncTaskToOutlook(taskId, btn) { async function syncTaskToOutlook(taskId, btn) {
if (!btn) return; if (!btn) return;
const originalHtml = btn.innerHTML; const originalHtml = btn.innerHTML;
@@ -1634,6 +1766,7 @@ async function aiSmartSchedule(btn) {
} }
} }
} }
<<<<<<< HEAD
// --- Outlook 365 Auto-Sync & Achtergrond Controle --- // --- Outlook 365 Auto-Sync & Achtergrond Controle ---
const isOutlookConnected = <?= $isOutlookConnected ? 'true' : 'false' ?>; const isOutlookConnected = <?= $isOutlookConnected ? 'true' : 'false' ?>;
let currentSyncHash = '<?= $initialSyncHash ?? '' ?>'; let currentSyncHash = '<?= $initialSyncHash ?? '' ?>';
@@ -1722,6 +1855,8 @@ document.addEventListener('DOMContentLoaded', () => {
}); });
} }
}); });
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
</script> </script>
<?php require_once __DIR__ . '/includes/footer.php'; ?> <?php require_once __DIR__ . '/includes/footer.php'; ?>
+18 -10
View File
@@ -48,6 +48,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
exit; exit;
} }
<<<<<<< HEAD
// 2b. Outlook synchronisatievoorkeuren opslaan // 2b. Outlook synchronisatievoorkeuren opslaan
elseif ($action === 'save_outlook_settings') { elseif ($action === 'save_outlook_settings') {
$syncInterval = (int)($_POST['sync_interval_seconds'] ?? 30); $syncInterval = (int)($_POST['sync_interval_seconds'] ?? 30);
@@ -64,6 +65,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$message = "Uw Microsoft Outlook synchronisatievoorkeur is succesvol opgeslagen."; $message = "Uw Microsoft Outlook synchronisatievoorkeur is succesvol opgeslagen.";
$messageType = 'success'; $messageType = 'success';
} }
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
// 3. Jira Opslaan & Testen // 3. Jira Opslaan & Testen
elseif ($action === 'save_jira') { elseif ($action === 'save_jira') {
$companyDomain = jira_get_company_domain(); $companyDomain = jira_get_company_domain();
@@ -223,7 +227,7 @@ require_once __DIR__ . '/includes/header.php';
<div class="space-y-8 max-w-5xl mx-auto pb-12"> <div class="space-y-8 max-w-5xl mx-auto pb-12">
<!-- Profiel Header Card --> <!-- Profiel Header Card -->
<div class="relative overflow-hidden fociz-card p-6 sm:p-8"> <div class="relative overflow-hidden bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-6 sm:p-8 shadow-xs transition">
<div class="absolute -top-20 -right-20 w-72 h-72 bg-indigo-500/10 rounded-full blur-3xl pointer-events-none"></div> <div class="absolute -top-20 -right-20 w-72 h-72 bg-indigo-500/10 rounded-full blur-3xl pointer-events-none"></div>
<div class="relative z-10 flex flex-col sm:flex-row sm:items-center justify-between gap-6"> <div class="relative z-10 flex flex-col sm:flex-row sm:items-center justify-between gap-6">
@@ -236,7 +240,7 @@ require_once __DIR__ . '/includes/header.php';
<div class="space-y-1"> <div class="space-y-1">
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<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-bold text-slate-900 dark:text-white tracking-tight">
<?= htmlspecialchars($userProfile['name']) ?> <?= htmlspecialchars($userProfile['name']) ?>
</h1> </h1>
<?php if ($userProfile['role'] === 'ADMIN'): ?> <?php if ($userProfile['role'] === 'ADMIN'): ?>
@@ -285,7 +289,7 @@ require_once __DIR__ . '/includes/header.php';
<?php endif; ?> <?php endif; ?>
<!-- Sectie 0: Weergave & Thema Instellingen (Dark & Light mode) --> <!-- Sectie 0: Weergave & Thema Instellingen (Dark & Light mode) -->
<div class="fociz-card p-6 sm:p-7"> <div class="bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-6 sm:p-7 shadow-xs transition">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 pb-6 border-b border-slate-100 dark:border-slate-800/80"> <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 pb-6 border-b border-slate-100 dark:border-slate-800/80">
<div class="flex items-center space-x-3.5"> <div class="flex items-center space-x-3.5">
<div class="w-12 h-12 rounded-2xl bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 flex items-center justify-center text-indigo-600 dark:text-indigo-400 font-bold shadow-xs"> <div class="w-12 h-12 rounded-2xl bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 flex items-center justify-center text-indigo-600 dark:text-indigo-400 font-bold shadow-xs">
@@ -420,7 +424,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
<!-- Sectie 1: Mijn Microsoft 365 Outlook Agenda --> <!-- Sectie 1: Mijn Microsoft 365 Outlook Agenda -->
<div class="fociz-card p-6 sm:p-7"> <div class="bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-6 sm:p-7 shadow-xs transition">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-6 border-b border-slate-100 dark:border-slate-800/80"> <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-6 border-b border-slate-100 dark:border-slate-800/80">
<div class="flex items-center space-x-3.5"> <div class="flex items-center space-x-3.5">
<div class="w-12 h-12 rounded-2xl bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 flex items-center justify-center text-sky-600 dark:text-sky-400 font-bold shadow-xs"> <div class="w-12 h-12 rounded-2xl bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 flex items-center justify-center text-sky-600 dark:text-sky-400 font-bold shadow-xs">
@@ -478,6 +482,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
</div> </div>
<<<<<<< HEAD
<form method="POST" class="mt-4 p-4 rounded-xl bg-slate-50/70 dark:bg-slate-900/60 border border-slate-200/80 dark:border-slate-800 flex flex-col sm:flex-row sm:items-center justify-between gap-4"> <form method="POST" class="mt-4 p-4 rounded-xl bg-slate-50/70 dark:bg-slate-900/60 border border-slate-200/80 dark:border-slate-800 flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<input type="hidden" name="action" value="save_outlook_settings"> <input type="hidden" name="action" value="save_outlook_settings">
<div class="space-y-1"> <div class="space-y-1">
@@ -503,6 +508,9 @@ require_once __DIR__ . '/includes/header.php';
</button> </button>
</div> </div>
</form> </form>
=======
>>>>>>> dd738e670b78819c11e329da93db1b472808f195
<div class="mt-4 p-3.5 rounded-xl bg-teal-50 dark:bg-teal-500/10 border border-teal-200 dark:border-teal-500/20 text-teal-800 dark:text-teal-300 text-xs flex items-center justify-between"> <div class="mt-4 p-3.5 rounded-xl bg-teal-50 dark:bg-teal-500/10 border border-teal-200 dark:border-teal-500/20 text-teal-800 dark:text-teal-300 text-xs flex items-center justify-between">
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<i data-lucide="check-circle" class="w-4 h-4 text-teal-600 dark:text-teal-400 flex-shrink-0"></i> <i data-lucide="check-circle" class="w-4 h-4 text-teal-600 dark:text-teal-400 flex-shrink-0"></i>
@@ -553,7 +561,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
<!-- Sectie 2: Mijn Atlassian Jira Koppeling --> <!-- Sectie 2: Mijn Atlassian Jira Koppeling -->
<div class="fociz-card p-6 sm:p-7"> <div class="bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-6 sm:p-7 shadow-xs transition">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-6 border-b border-slate-100 dark:border-slate-800/80"> <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-6 border-b border-slate-100 dark:border-slate-800/80">
<div class="flex items-center space-x-3.5"> <div class="flex items-center space-x-3.5">
<div class="w-12 h-12 rounded-2xl bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 flex items-center justify-center text-indigo-600 dark:text-indigo-400 font-bold shadow-xs"> <div class="w-12 h-12 rounded-2xl bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 flex items-center justify-center text-indigo-600 dark:text-indigo-400 font-bold shadow-xs">
@@ -642,7 +650,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
<!-- Sectie 3: Mijn Meldingen & Agenda Push Notificaties --> <!-- Sectie 3: Mijn Meldingen & Agenda Push Notificaties -->
<div class="fociz-card p-6 sm:p-7"> <div class="bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-6 sm:p-7 shadow-xs transition">
<div class="flex items-center space-x-3.5 pb-6 border-b border-slate-100 dark:border-slate-800/80"> <div class="flex items-center space-x-3.5 pb-6 border-b border-slate-100 dark:border-slate-800/80">
<div class="w-12 h-12 rounded-2xl bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 flex items-center justify-center text-indigo-600 dark:text-indigo-400 font-bold shadow-xs"> <div class="w-12 h-12 rounded-2xl bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 flex items-center justify-center text-indigo-600 dark:text-indigo-400 font-bold shadow-xs">
<i data-lucide="bell" class="w-6 h-6"></i> <i data-lucide="bell" class="w-6 h-6"></i>
@@ -790,7 +798,7 @@ require_once __DIR__ . '/includes/header.php';
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Profielnaam formulier --> <!-- Profielnaam formulier -->
<div class="fociz-card p-6 sm:p-7 space-y-4"> <div class="bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-6 sm:p-7 shadow-xs space-y-4 transition">
<div class="flex items-center space-x-3 pb-4 border-b border-slate-100 dark:border-slate-800/80"> <div class="flex items-center space-x-3 pb-4 border-b border-slate-100 dark:border-slate-800/80">
<i data-lucide="user" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i> <i data-lucide="user" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
<h3 class="text-sm font-bold text-slate-900 dark:text-white">Persoonlijke Gegevens</h3> <h3 class="text-sm font-bold text-slate-900 dark:text-white">Persoonlijke Gegevens</h3>
@@ -803,14 +811,14 @@ require_once __DIR__ . '/includes/header.php';
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5"> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5">
Weergavenaam Weergavenaam
</label> </label>
<input type="text" name="name" required value="<?= htmlspecialchars($userProfile['name']) ?>" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs"> <input type="text" name="name" required value="<?= htmlspecialchars($userProfile['name']) ?>" class="w-full bg-white dark:bg-slate-900/60 border border-slate-200 dark:border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-1 focus:ring-indigo-500">
</div> </div>
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5"> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5">
E-mailadres E-mailadres
</label> </label>
<input type="email" readonly disabled value="<?= htmlspecialchars($userProfile['email']) ?>" class="w-full bg-slate-100/70 dark:bg-slate-900/40 border border-slate-200 dark:border-slate-800/60 rounded-xl px-3.5 py-2.5 text-xs text-slate-500 cursor-not-allowed shadow-2xs"> <input type="email" readonly disabled value="<?= htmlspecialchars($userProfile['email']) ?>" class="w-full bg-slate-100/70 dark:bg-slate-900/40 border border-slate-200 dark:border-slate-800/60 rounded-xl px-3.5 py-2.5 text-xs text-slate-500 cursor-not-allowed">
<span class="text-[10px] text-slate-500 mt-1 block">E-mailadres is gekoppeld aan uw account en 2FA.</span> <span class="text-[10px] text-slate-500 mt-1 block">E-mailadres is gekoppeld aan uw account en 2FA.</span>
</div> </div>
@@ -823,7 +831,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
<!-- Wachtwoord Wijzigen Formulier --> <!-- Wachtwoord Wijzigen Formulier -->
<div class="fociz-card p-6 sm:p-7 space-y-4"> <div class="bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-6 sm:p-7 shadow-xs space-y-4 transition">
<div class="flex items-center space-x-3 pb-4 border-b border-slate-100 dark:border-slate-800/80"> <div class="flex items-center space-x-3 pb-4 border-b border-slate-100 dark:border-slate-800/80">
<i data-lucide="key" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i> <i data-lucide="key" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
<h3 class="text-sm font-bold text-slate-900 dark:text-white">Wachtwoord Wijzigen</h3> <h3 class="text-sm font-bold text-slate-900 dark:text-white">Wachtwoord Wijzigen</h3>
+43 -50
View File
@@ -37,35 +37,35 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
<div class="space-y-6 max-w-7xl mx-auto"> <div class="space-y-6 max-w-7xl mx-auto">
<!-- Header --> <!-- Header -->
<div class="fociz-card p-6 sm:p-7 flex flex-col sm:flex-row sm:items-center justify-between gap-4"> <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-6 sm:p-7 shadow-xs transition">
<div> <div>
<div class="flex items-center space-x-2 text-indigo-600 dark:text-indigo-400 text-xs font-bold uppercase tracking-wider mb-1"> <div class="flex items-center space-x-2 text-indigo-600 dark:text-indigo-400 text-xs font-semibold uppercase tracking-wider mb-1">
<i data-lucide="map" class="w-4 h-4"></i> <i data-lucide="map" class="w-4 h-4"></i>
<span>Planning & Strategie</span> <span>Planning & Strategie</span>
</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-bold text-slate-900 dark:text-white tracking-tight">
Roadmap & Tijdlijn Roadmap & Tijdlijn
</h1> </h1>
<p class="text-slate-500 dark:text-slate-400 text-xs sm:text-sm mt-1 max-w-2xl"> <p class="text-slate-500 dark:text-slate-400 text-xs sm:text-sm mt-1">
Centraal overzicht van alle mijlpalen, features en doelen, direct voortgekomen uit brainstorms en gesynchroniseerd met Jira. Centraal overzicht van alle mijlpalen, features en doelen, direct voortgekomen uit brainstorms en gesynchroniseerd met Jira.
</p> </p>
</div> </div>
<button onclick="document.getElementById('newItemModal').classList.remove('hidden')" class="flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-bold transition shadow-xs flex-shrink-0 cursor-pointer"> <button onclick="document.getElementById('newItemModal').classList.remove('hidden')" class="flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-semibold transition shadow-xs flex-shrink-0 cursor-pointer">
<i data-lucide="plus" class="w-4 h-4"></i> <i data-lucide="plus" class="w-4 h-4"></i>
<span>Nieuw Item</span> <span>Nieuw Item</span>
</button> </button>
</div> </div>
<!-- Filters: Quarters & Status --> <!-- Filters: Quarters & Status -->
<div class="fociz-card p-4 flex flex-wrap items-center justify-between gap-3"> <div class="flex flex-wrap items-center justify-between gap-3 bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-4 shadow-xs transition">
<!-- Quarter Tabs --> <!-- Quarter Tabs -->
<div class="flex items-center space-x-1 text-xs"> <div class="flex items-center space-x-1 text-xs">
<a href="/roadmap.php?quarter=ALL&status=<?= htmlspecialchars($selectedStatus) ?>" class="px-3 py-1.5 rounded-lg transition font-semibold <?= $selectedQuarter === 'ALL' ? 'bg-indigo-600 text-white shadow-xs' : 'text-slate-600 hover:text-slate-900 dark:text-slate-400 dark:hover:text-slate-200 hover:bg-slate-100 dark:hover:bg-slate-800/80' ?>"> <a href="/roadmap.php?quarter=ALL&status=<?= htmlspecialchars($selectedStatus) ?>" class="px-3 py-1.5 rounded-lg transition font-medium <?= $selectedQuarter === 'ALL' ? 'bg-indigo-600 text-white shadow-xs' : 'text-slate-600 hover:text-slate-900 dark:text-slate-400 dark:hover:text-slate-200 hover:bg-slate-100 dark:hover:bg-slate-800' ?>">
Alle Quarters Alle Quarters
</a> </a>
<?php foreach ($quarters as $q): ?> <?php foreach ($quarters as $q): ?>
<a href="/roadmap.php?quarter=<?= $q ?>&status=<?= htmlspecialchars($selectedStatus) ?>" class="px-3 py-1.5 rounded-lg transition font-semibold <?= $selectedQuarter === $q ? 'bg-indigo-600 text-white shadow-xs' : 'text-slate-600 hover:text-slate-900 dark:text-slate-400 dark:hover:text-slate-200 hover:bg-slate-100 dark:hover:bg-slate-800/80' ?>"> <a href="/roadmap.php?quarter=<?= $q ?>&status=<?= htmlspecialchars($selectedStatus) ?>" class="px-3 py-1.5 rounded-lg transition font-medium <?= $selectedQuarter === $q ? 'bg-indigo-600 text-white shadow-xs' : 'text-slate-600 hover:text-slate-900 dark:text-slate-400 dark:hover:text-slate-200 hover:bg-slate-100 dark:hover:bg-slate-800' ?>">
<?= $q ?> <?= $q ?>
</a> </a>
<?php endforeach; ?> <?php endforeach; ?>
@@ -73,8 +73,8 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
<!-- Status Filter --> <!-- Status Filter -->
<div class="flex items-center space-x-2 text-xs"> <div class="flex items-center space-x-2 text-xs">
<span class="text-slate-500 dark:text-slate-400 font-semibold">Status:</span> <span class="text-slate-500 dark:text-slate-400 font-medium">Status:</span>
<select onchange="window.location.href='/roadmap.php?quarter=<?= htmlspecialchars($selectedQuarter) ?>&status='+this.value" class="bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-1.5 text-slate-900 dark:text-white text-xs font-semibold focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs"> <select onchange="window.location.href='/roadmap.php?quarter=<?= htmlspecialchars($selectedQuarter) ?>&status='+this.value" class="bg-slate-50 dark:bg-slate-900/60 border border-slate-200 dark:border-slate-800 rounded-xl px-2.5 py-1 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500">
<option value="ALL" <?= $selectedStatus === 'ALL' ? 'selected' : '' ?>>Alle Statussen</option> <option value="ALL" <?= $selectedStatus === 'ALL' ? 'selected' : '' ?>>Alle Statussen</option>
<option value="PLANNED" <?= $selectedStatus === 'PLANNED' ? 'selected' : '' ?>>Gepland</option> <option value="PLANNED" <?= $selectedStatus === 'PLANNED' ? 'selected' : '' ?>>Gepland</option>
<option value="IN_PROGRESS" <?= $selectedStatus === 'IN_PROGRESS' ? 'selected' : '' ?>>In Uitvoering</option> <option value="IN_PROGRESS" <?= $selectedStatus === 'IN_PROGRESS' ? 'selected' : '' ?>>In Uitvoering</option>
@@ -87,34 +87,27 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
<!-- Roadmap Items Lijst --> <!-- Roadmap Items Lijst -->
<div class="space-y-4"> <div class="space-y-4">
<?php if (empty($roadmapItems)): ?> <?php if (empty($roadmapItems)): ?>
<div class="fociz-card p-12 text-center"> <div class="bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 rounded-2xl p-12 text-center shadow-xs">
<i data-lucide="map-pin" class="w-12 h-12 text-slate-300 dark:text-slate-700 mx-auto mb-3"></i> <i data-lucide="map-pin" class="w-12 h-12 text-slate-300 dark:text-slate-700 mx-auto mb-3"></i>
<h3 class="text-base font-bold text-slate-900 dark:text-white">Geen items gevonden op de roadmap</h3> <h3 class="text-base font-semibold text-slate-900 dark:text-white">Geen items gevonden op de roadmap</h3>
<p class="text-xs text-slate-500 dark:text-slate-400 mt-1 max-w-sm mx-auto"> <p class="text-xs text-slate-500 dark:text-slate-400 mt-1 max-w-sm mx-auto">
Ga naar een <a href="/brainstorm.php" class="text-indigo-600 dark:text-indigo-400 underline font-medium">Brainstorm sessie</a> en zet ideeën met één klik om naar de roadmap, of voeg handmatig een item toe. Ga naar een <a href="/brainstorm.php" class="text-indigo-600 dark:text-indigo-400 underline font-medium">Brainstorm sessie</a> en zet ideeën met één klik om naar de roadmap, of voeg handmatig een item toe.
</p> </p>
</div> </div>
<?php else: ?> <?php else: ?>
<?php foreach ($roadmapItems as $item): <?php foreach ($roadmapItems as $item): ?>
$statusBorder = match($item['status']) { <div class="bg-white dark:bg-[#111622] border border-slate-200/80 dark:border-slate-800 hover:border-indigo-300 dark:hover:border-indigo-700/60 rounded-2xl p-5 shadow-xs transition space-y-3" id="roadmap-item-<?= $item['id'] ?>">
'COMPLETED' => 'border-l-4 border-l-emerald-500',
'IN_PROGRESS' => 'border-l-4 border-l-indigo-500',
'REVIEW' => 'border-l-4 border-l-amber-500',
default => 'border-l-4 border-l-slate-300 dark:border-l-slate-700',
};
?>
<div class="fociz-card-interactive p-5 space-y-3.5 <?= $statusBorder ?>" id="roadmap-item-<?= $item['id'] ?>">
<!-- Top header van item --> <!-- Top header van item -->
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-2"> <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-2">
<div class="flex items-center space-x-2.5 flex-wrap"> <div class="flex items-center space-x-2.5 flex-wrap">
<!-- Quarter badge --> <!-- Quarter badge -->
<span class="px-2.5 py-0.5 rounded-lg bg-indigo-50 dark:bg-indigo-500/10 text-indigo-700 dark:text-indigo-300 font-mono text-xs font-bold border border-indigo-200 dark:border-indigo-500/20"> <span class="px-2.5 py-0.5 rounded-md bg-indigo-50 dark:bg-indigo-500/10 text-indigo-700 dark:text-indigo-300 font-mono text-xs font-semibold border border-indigo-200 dark:border-indigo-500/20">
<?= htmlspecialchars($item['quarter']) ?> <?= htmlspecialchars($item['quarter']) ?>
</span> </span>
<!-- Type badge --> <!-- Type badge -->
<span class="px-2 py-0.5 rounded-lg bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300 text-[10px] font-semibold border border-slate-200 dark:border-slate-700"> <span class="px-2 py-0.5 rounded-md bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300 text-[10px] font-semibold">
<?= htmlspecialchars($item['type']) ?> <?= htmlspecialchars($item['type']) ?>
</span> </span>
@@ -125,7 +118,7 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
<!-- Jira Issue Key link --> <!-- Jira Issue Key link -->
<?php if (!empty($item['jira_issue_key'])): ?> <?php if (!empty($item['jira_issue_key'])): ?>
<a href="/profile.php" class="flex items-center space-x-1 px-2.5 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-mono hover:underline"> <a href="/profile.php" class="flex items-center space-x-1 px-2 py-0.5 rounded-md 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-mono hover:underline">
<i data-lucide="layers" class="w-3 h-3"></i> <i data-lucide="layers" class="w-3 h-3"></i>
<span><?= htmlspecialchars($item['jira_issue_key']) ?></span> <span><?= htmlspecialchars($item['jira_issue_key']) ?></span>
</a> </a>
@@ -134,7 +127,7 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
<!-- Status Selector --> <!-- Status Selector -->
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<select onchange="updateRoadmapStatus(<?= $item['id'] ?>, this.value)" class="bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-200 dark:border-slate-800 rounded-xl px-2.5 py-1 text-xs text-slate-800 dark:text-slate-200 font-bold focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs"> <select onchange="updateRoadmapStatus(<?= $item['id'] ?>, this.value)" class="bg-slate-50 dark:bg-slate-900/60 border border-slate-200 dark:border-slate-800 rounded-xl px-2.5 py-1 text-xs text-slate-800 dark:text-slate-200 font-semibold focus:outline-none focus:ring-1 focus:ring-indigo-500">
<option value="PLANNED" <?= $item['status'] === 'PLANNED' ? 'selected' : '' ?>>⏳ Gepland</option> <option value="PLANNED" <?= $item['status'] === 'PLANNED' ? 'selected' : '' ?>>⏳ Gepland</option>
<option value="IN_PROGRESS" <?= $item['status'] === 'IN_PROGRESS' ? 'selected' : '' ?>>⚡ In Uitvoering</option> <option value="IN_PROGRESS" <?= $item['status'] === 'IN_PROGRESS' ? 'selected' : '' ?>>⚡ In Uitvoering</option>
<option value="REVIEW" <?= $item['status'] === 'REVIEW' ? 'selected' : '' ?>>🔍 In Review</option> <option value="REVIEW" <?= $item['status'] === 'REVIEW' ? 'selected' : '' ?>>🔍 In Review</option>
@@ -161,32 +154,32 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
<!-- Origin Brainstorm snippet --> <!-- Origin Brainstorm snippet -->
<?php if (!empty($item['origin_brainstorm_card_id'])): ?> <?php if (!empty($item['origin_brainstorm_card_id'])): ?>
<div class="bg-slate-50/70 dark:bg-[#0c0f17]/60 rounded-xl p-2.5 text-[11px] text-slate-600 dark:text-slate-400 flex items-center space-x-2 border border-slate-200/80 dark:border-slate-800"> <div class="bg-slate-50 dark:bg-slate-900/60 rounded-xl p-2.5 text-[11px] text-slate-500 dark:text-slate-400 flex items-center space-x-2 border border-slate-200/80 dark:border-slate-800">
<i data-lucide="lightbulb" class="w-3.5 h-3.5 text-amber-500 flex-shrink-0"></i> <i data-lucide="lightbulb" class="w-3.5 h-3.5 text-amber-500 flex-shrink-0"></i>
<span class="truncate">Ontstaan uit brainstormsessie</span> <span class="truncate">Ontstaan uit brainstormsessie</span>
</div> </div>
<?php endif; ?> <?php endif; ?>
<!-- Voortgangsbalk & Deadline --> <!-- Voortgangsbalk & Deadline -->
<div class="pt-2.5 border-t border-slate-100 dark:border-slate-800/60 flex flex-col sm:flex-row sm:items-center justify-between gap-3 text-xs"> <div class="pt-2 border-t border-slate-100 dark:border-slate-800/60 flex flex-col sm:flex-row sm:items-center justify-between gap-3 text-xs">
<!-- Progress Slider --> <!-- Progress Slider -->
<div class="flex items-center space-x-3 flex-1 max-w-md"> <div class="flex items-center space-x-3 flex-1 max-w-md">
<span class="text-slate-500 dark:text-slate-400 text-[11px] font-semibold w-16">Voortgang:</span> <span class="text-slate-500 dark:text-slate-400 text-[11px] font-medium w-16">Voortgang:</span>
<div class="flex-1 bg-slate-100 dark:bg-slate-900 h-2.5 rounded-full overflow-hidden border border-slate-200 dark:border-slate-800"> <div class="flex-1 bg-slate-100 dark:bg-slate-900 h-2 rounded-full overflow-hidden border border-slate-200 dark:border-slate-800">
<div class="bg-gradient-to-r from-indigo-600 to-sky-500 h-full transition-all" style="width: <?= $item['progress'] ?>%"></div> <div class="bg-gradient-to-r from-indigo-600 to-sky-500 h-full transition-all" style="width: <?= $item['progress'] ?>%"></div>
</div> </div>
<span class="font-mono text-slate-800 dark:text-slate-200 font-bold w-10 text-right"><?= $item['progress'] ?>%</span> <span class="font-mono text-slate-800 dark:text-slate-200 font-semibold w-10 text-right"><?= $item['progress'] ?>%</span>
<div class="flex space-x-1"> <div class="flex space-x-1">
<button onclick="updateRoadmapProgress(<?= $item['id'] ?>, 25)" class="px-2 py-0.5 rounded-lg bg-slate-100 dark:bg-slate-800 text-[10px] text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white cursor-pointer font-semibold transition">25%</button> <button onclick="updateRoadmapProgress(<?= $item['id'] ?>, 25)" class="px-1.5 py-0.5 rounded bg-slate-100 dark:bg-slate-800 text-[10px] text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white cursor-pointer">25%</button>
<button onclick="updateRoadmapProgress(<?= $item['id'] ?>, 50)" class="px-2 py-0.5 rounded-lg bg-slate-100 dark:bg-slate-800 text-[10px] text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white cursor-pointer font-semibold transition">50%</button> <button onclick="updateRoadmapProgress(<?= $item['id'] ?>, 50)" class="px-1.5 py-0.5 rounded bg-slate-100 dark:bg-slate-800 text-[10px] text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white cursor-pointer">50%</button>
<button onclick="updateRoadmapProgress(<?= $item['id'] ?>, 100)" class="px-2 py-0.5 rounded-lg bg-indigo-50 dark:bg-indigo-500/15 text-[10px] text-indigo-700 dark:text-indigo-400 hover:text-indigo-800 dark:hover:text-indigo-300 font-bold cursor-pointer transition">100%</button> <button onclick="updateRoadmapProgress(<?= $item['id'] ?>, 100)" class="px-1.5 py-0.5 rounded bg-indigo-50 dark:bg-indigo-500/15 text-[10px] text-indigo-700 dark:text-indigo-400 hover:text-indigo-800 dark:hover:text-indigo-300 font-semibold cursor-pointer">100%</button>
</div> </div>
</div> </div>
<!-- Deadline & Creator --> <!-- Deadline & Creator -->
<div class="flex items-center space-x-3 text-slate-500 text-[11px]"> <div class="flex items-center space-x-3 text-slate-500 text-[11px]">
<?php if (!empty($item['due_date'])): ?> <?php if (!empty($item['due_date'])): ?>
<span class="flex items-center space-x-1 text-slate-700 dark:text-slate-300 font-semibold"> <span class="flex items-center space-x-1 text-slate-700 dark:text-slate-300 font-medium">
<i data-lucide="calendar" class="w-3.5 h-3.5 text-indigo-600 dark:text-indigo-400"></i> <i data-lucide="calendar" class="w-3.5 h-3.5 text-indigo-600 dark:text-indigo-400"></i>
<span>Deadline: <?= date('d-m-Y', strtotime($item['due_date'])) ?></span> <span>Deadline: <?= date('d-m-Y', strtotime($item['due_date'])) ?></span>
</span> </span>
@@ -201,33 +194,33 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
</div> </div>
<!-- Modal: Nieuw Roadmap Item Handmatig Toevoegen --> <!-- Modal: Nieuw Roadmap Item Handmatig Toevoegen -->
<div id="newItemModal" class="hidden fixed inset-0 z-50 bg-slate-950/70 backdrop-blur-sm flex items-center justify-center p-4"> <div id="newItemModal" class="hidden fixed inset-0 z-50 bg-slate-950/60 backdrop-blur-xs flex items-center justify-center p-4">
<div class="fociz-card p-6 sm:p-7 shadow-2xl max-w-lg w-full space-y-4"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800 rounded-2xl p-6 shadow-xl max-w-lg w-full transition">
<div class="flex items-center justify-between 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">
<h3 class="text-sm font-bold text-slate-900 dark:text-white flex items-center space-x-2"> <h3 class="text-sm font-semibold text-slate-900 dark:text-white flex items-center space-x-2">
<i data-lucide="map" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i> <i data-lucide="map" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
<span>Nieuw Roadmap Item Toevoegen</span> <span>Nieuw Roadmap Item Toevoegen</span>
</h3> </h3>
<button onclick="document.getElementById('newItemModal').classList.add('hidden')" class="p-1.5 text-slate-400 hover:text-slate-600 dark:hover:text-white rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition cursor-pointer"> <button onclick="document.getElementById('newItemModal').classList.add('hidden')" class="text-slate-400 hover:text-slate-600 dark:hover:text-white cursor-pointer">
<i data-lucide="x" class="w-4 h-4"></i> <i data-lucide="x" class="w-5 h-5"></i>
</button> </button>
</div> </div>
<div class="space-y-4"> <div class="space-y-4">
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Titel / Doel</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Titel / Doel</label>
<input type="text" id="manualTitle" placeholder="Bijv. 2FA Authenticatie afronden" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 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 shadow-2xs"> <input type="text" id="manualTitle" placeholder="Bijv. 2FA Authenticatie afronden" class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 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> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Beschrijving / Specificatie</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Beschrijving / Specificatie</label>
<textarea id="manualDescription" rows="3" placeholder="Wat houdt deze milestone of feature in?" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 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 shadow-2xs"></textarea> <textarea id="manualDescription" rows="3" placeholder="Wat houdt deze milestone of feature in?" class="w-full bg-slate-50 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"></textarea>
</div> </div>
<div class="grid grid-cols-2 gap-3"> <div class="grid grid-cols-2 gap-3">
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Kwartaal</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Kwartaal</label>
<select id="manualQuarter" 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"> <select id="manualQuarter" class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 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">
<option value="Q1">Q1</option> <option value="Q1">Q1</option>
<option value="Q2">Q2</option> <option value="Q2">Q2</option>
<option value="Q3" selected>Q3</option> <option value="Q3" selected>Q3</option>
@@ -236,7 +229,7 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
</div> </div>
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Type</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Type</label>
<select id="manualType" 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"> <select id="manualType" class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 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">
<option value="FEATURE" selected>Feature</option> <option value="FEATURE" selected>Feature</option>
<option value="EPIC">Epic</option> <option value="EPIC">Epic</option>
<option value="MILESTONE">Mijlpaal</option> <option value="MILESTONE">Mijlpaal</option>
@@ -248,7 +241,7 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
<div class="grid grid-cols-2 gap-3"> <div class="grid 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="manualPriority" 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"> <select id="manualPriority" class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 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">
<option value="CRITICAL">Kritiek</option> <option value="CRITICAL">Kritiek</option>
<option value="HIGH" selected>Hoog</option> <option value="HIGH" selected>Hoog</option>
<option value="MEDIUM">Normaal</option> <option value="MEDIUM">Normaal</option>
@@ -257,20 +250,20 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
</div> </div>
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Jira Issue Key (optioneel)</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Jira Issue Key (optioneel)</label>
<input type="text" id="manualJiraKey" placeholder="Bijv. FOC-101" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-1.5 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs"> <input type="text" id="manualJiraKey" placeholder="Bijv. FOC-101" class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-1.5 text-slate-900 dark:text-white text-xs font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500">
</div> </div>
</div> </div>
<div> <div>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Streefdatum</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Streefdatum</label>
<input type="date" id="manualDueDate" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-1.5 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs"> <input type="date" id="manualDueDate" class="w-full bg-slate-50 dark:bg-slate-900/60 border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-1.5 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500">
</div> </div>
<div class="flex space-x-2 pt-2 border-t border-slate-100 dark:border-slate-800/80"> <div class="flex space-x-2 pt-2">
<button onclick="submitManualItem()" class="flex-1 bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-2.5 px-4 rounded-xl text-xs transition cursor-pointer shadow-xs"> <button onclick="submitManualItem()" class="flex-1 bg-indigo-600 hover:bg-indigo-500 text-white font-semibold py-2.5 px-4 rounded-xl text-xs transition cursor-pointer shadow-xs">
Toevoegen aan Roadmap Toevoegen aan Roadmap
</button> </button>
<button onclick="document.getElementById('newItemModal').classList.add('hidden')" class="px-4 py-2.5 bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-xl text-xs font-semibold transition cursor-pointer"> <button onclick="document.getElementById('newItemModal').classList.add('hidden')" class="px-4 py-2.5 bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-xl text-xs transition cursor-pointer">
Annuleren Annuleren
</button> </button>
</div> </div>
+7 -7
View File
@@ -71,7 +71,7 @@ require_once __DIR__ . '/includes/header.php';
<div class="space-y-6 max-w-7xl mx-auto pb-12"> <div class="space-y-6 max-w-7xl mx-auto pb-12">
<!-- Header --> <!-- Header -->
<div class="fociz-card p-6 sm:p-7"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-6 sm:p-7 shadow-xs transition">
<div class="flex items-center space-x-2 text-indigo-600 dark:text-indigo-400 text-xs font-bold 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="shield" class="w-4 h-4"></i> <i data-lucide="shield" class="w-4 h-4"></i>
<span>Beheerderspaneel</span> <span>Beheerderspaneel</span>
@@ -79,7 +79,7 @@ require_once __DIR__ . '/includes/header.php';
<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 text-slate-900 dark:text-white tracking-tight">
Team & Uitnodigingen Team & Uitnodigingen
</h1> </h1>
<p class="text-slate-500 dark:text-slate-400 text-xs sm:text-sm mt-1 max-w-2xl"> <p class="text-slate-500 dark:text-slate-400 text-xs sm:text-sm mt-1">
Fociz is strikt afgesloten: nieuwe collega's kunnen enkel toegang krijgen na het ontvangen van een uitnodigingslink en verplichte 2FA-activatie. Fociz is strikt afgesloten: nieuwe collega's kunnen enkel toegang krijgen na het ontvangen van een uitnodigingslink en verplichte 2FA-activatie.
</p> </p>
</div> </div>
@@ -111,7 +111,7 @@ require_once __DIR__ . '/includes/header.php';
<?php endif; ?> <?php endif; ?>
<!-- Uitnodiging Genereren Kaart --> <!-- Uitnodiging Genereren Kaart -->
<div class="fociz-card p-6 sm:p-7"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-6 sm:p-7 shadow-xs transition">
<h3 class="text-base font-bold text-slate-900 dark:text-white mb-4 flex items-center space-x-2"> <h3 class="text-base font-bold text-slate-900 dark:text-white mb-4 flex items-center space-x-2">
<i data-lucide="user-plus" class="w-5 h-5 text-indigo-600 dark:text-indigo-400"></i> <i data-lucide="user-plus" class="w-5 h-5 text-indigo-600 dark:text-indigo-400"></i>
<span>Nieuwe Collega Uitnodigen</span> <span>Nieuwe Collega Uitnodigen</span>
@@ -122,12 +122,12 @@ require_once __DIR__ . '/includes/header.php';
<div class="md:col-span-6"> <div class="md:col-span-6">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">E-mailadres van collega</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">E-mailadres van collega</label>
<input type="email" name="email" required placeholder="collega@bedrijf.nl" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-4 py-2.5 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 text-xs shadow-2xs"> <input type="email" name="email" required placeholder="collega@bedrijf.nl" class="w-full bg-slate-50 dark:bg-[#0c0f17] border border-slate-300 dark:border-slate-800 rounded-xl px-4 py-2.5 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 text-xs">
</div> </div>
<div class="md:col-span-3"> <div class="md:col-span-3">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Rol</label> <label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Rol</label>
<select name="role" 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.5 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs"> <select name="role" class="w-full bg-slate-50 dark:bg-[#0c0f17] border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-2.5 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500">
<option value="MEMBER">Collega (Standaard)</option> <option value="MEMBER">Collega (Standaard)</option>
<option value="ADMIN">Mede-beheerder</option> <option value="ADMIN">Mede-beheerder</option>
</select> </select>
@@ -143,7 +143,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
<!-- Actieve Gebruikers Tabel --> <!-- Actieve Gebruikers Tabel -->
<div class="fociz-card p-6 sm:p-7 space-y-4"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-6 sm:p-7 shadow-xs space-y-4 transition">
<div class="flex items-center justify-between pb-3 border-b border-slate-100 dark:border-slate-800"> <div class="flex items-center justify-between pb-3 border-b border-slate-100 dark:border-slate-800">
<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">
<i data-lucide="users" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i> <i data-lucide="users" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
@@ -200,7 +200,7 @@ require_once __DIR__ . '/includes/header.php';
</div> </div>
<!-- Uitstaande Uitnodigingen Tabel --> <!-- Uitstaande Uitnodigingen Tabel -->
<div class="fociz-card p-6 sm:p-7 space-y-4"> <div class="bg-white dark:bg-[#111622] border border-slate-200 dark:border-slate-800/80 rounded-2xl p-6 sm:p-7 shadow-xs space-y-4 transition">
<div class="flex items-center justify-between pb-3 border-b border-slate-100 dark:border-slate-800"> <div class="flex items-center justify-between pb-3 border-b border-slate-100 dark:border-slate-800">
<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">
<i data-lucide="mail" class="w-4 h-4 text-amber-500"></i> <i data-lucide="mail" class="w-4 h-4 text-amber-500"></i>