Dev #15

Merged
NiekRabelink merged 2 commits from dev into main 2026-09-09 10:05:03 +00:00
12 changed files with 1059 additions and 632 deletions
Showing only changes of commit 62af7b0017 - Show all commits
+120 -121
View File
@@ -129,30 +129,30 @@ require_once __DIR__ . '/includes/header.php';
<div class="space-y-8 max-w-7xl mx-auto pb-12">
<!-- Top Header Banner -->
<div class="relative overflow-hidden bg-slate-900/90 border border-slate-800 rounded-3xl p-6 sm:p-8 shadow-2xl backdrop-blur-xl">
<div class="relative overflow-hidden bg-white dark:bg-slate-900/90 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-8 shadow-sm dark:shadow-2xl backdrop-blur-xl transition">
<div class="absolute -top-24 -right-24 w-80 h-80 bg-emerald-500/10 rounded-full blur-3xl pointer-events-none"></div>
<div class="absolute -bottom-24 -left-24 w-80 h-80 bg-blue-500/10 rounded-full blur-3xl pointer-events-none"></div>
<div class="relative z-10 flex flex-col md:flex-row md:items-center md:justify-between gap-6">
<div class="space-y-2">
<div class="inline-flex items-center space-x-2 px-3 py-1 rounded-full bg-emerald-500/10 border border-emerald-500/30 text-emerald-400 text-xs font-semibold tracking-wide">
<div class="inline-flex items-center space-x-2 px-3 py-1 rounded-full bg-emerald-500/10 border border-emerald-500/30 text-emerald-700 dark:text-emerald-400 text-xs font-semibold tracking-wide">
<i data-lucide="shield-alert" class="w-3.5 h-3.5"></i>
<span>Beheerderspaneel • Alleen toegankelijk voor Beheer</span>
</div>
<h1 class="text-3xl sm:text-4xl font-black text-white tracking-tight">
<h1 class="text-3xl sm:text-4xl font-black text-slate-900 dark:text-white tracking-tight">
Systeembeheer & Integraties
</h1>
<p class="text-sm text-slate-400 max-w-2xl leading-relaxed">
<p class="text-sm text-slate-600 dark:text-slate-400 max-w-2xl leading-relaxed">
Beheer hier de centrale organisatiekoppelingen zoals Microsoft 365 Azure App Registratie en Jira, inspecteer de teamstatus en configureer toekomstige modules.
</p>
</div>
<div class="flex flex-wrap items-center gap-3">
<a href="/users.php" class="inline-flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-slate-800/90 hover:bg-slate-700 text-slate-200 border border-slate-700 text-xs font-semibold transition shadow-md">
<i data-lucide="users" class="w-4 h-4 text-emerald-400"></i>
<a href="/users.php" class="inline-flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800/90 dark:hover:bg-slate-700 text-slate-800 dark:text-slate-200 border border-slate-200 dark:border-slate-700 text-xs font-semibold transition shadow-sm">
<i data-lucide="users" class="w-4 h-4 text-emerald-600 dark:text-emerald-400"></i>
<span>Team & Invites (<?= $totalUsers ?>)</span>
</a>
<a href="/profile.php" class="inline-flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-emerald-600 hover:bg-emerald-500 text-slate-950 text-xs font-bold transition shadow-lg shadow-emerald-600/20">
<a href="/profile.php" class="inline-flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-emerald-600 hover:bg-emerald-500 text-white dark:text-slate-950 text-xs font-bold transition shadow-lg shadow-emerald-600/20">
<i data-lucide="user" class="w-4 h-4"></i>
<span>Mijn Persoonlijk Profiel</span>
</a>
@@ -162,55 +162,55 @@ require_once __DIR__ . '/includes/header.php';
<!-- Meldingen Banner -->
<?php if ($message): ?>
<div class="p-4 rounded-2xl flex items-start space-x-3 text-sm animate-in fade-in duration-200 <?= $messageType === 'success' ? 'bg-emerald-500/10 border border-emerald-500/30 text-emerald-200' : 'bg-red-500/10 border border-red-500/30 text-red-200' ?>">
<i data-lucide="<?= $messageType === 'success' ? 'check-circle-2' : 'alert-triangle' ?>" class="w-5 h-5 flex-shrink-0 mt-0.5 <?= $messageType === 'success' ? 'text-emerald-400' : 'text-red-400' ?>"></i>
<div class="p-4 rounded-2xl flex items-start space-x-3 text-sm animate-in fade-in duration-200 <?= $messageType === 'success' ? 'bg-emerald-500/10 border border-emerald-500/30 text-emerald-800 dark:text-emerald-200' : 'bg-red-500/10 border border-red-500/30 text-red-800 dark:text-red-200' ?>">
<i data-lucide="<?= $messageType === 'success' ? 'check-circle-2' : 'alert-triangle' ?>" class="w-5 h-5 flex-shrink-0 mt-0.5 <?= $messageType === 'success' ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400' ?>"></i>
<div class="flex-1 font-medium"><?= htmlspecialchars($message) ?></div>
</div>
<?php endif; ?>
<!-- Stat kaarten rij -->
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4">
<div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-4 flex items-center space-x-4">
<div class="w-12 h-12 rounded-xl bg-emerald-500/10 border border-emerald-500/20 flex items-center justify-center text-emerald-400 flex-shrink-0">
<div class="bg-white dark:bg-slate-900/70 border border-slate-200 dark:border-slate-800 rounded-3xl p-5 flex items-center space-x-4 shadow-sm transition">
<div class="w-12 h-12 rounded-2xl bg-emerald-500/10 border border-emerald-500/20 flex items-center justify-center text-emerald-600 dark:text-emerald-400 flex-shrink-0">
<i data-lucide="users" class="w-6 h-6"></i>
</div>
<div>
<span class="text-xs text-slate-400 font-medium block">Totaal Teamleden</span>
<span class="text-2xl font-black text-white"><?= $totalUsers ?></span>
<span class="text-[10px] text-slate-500 block"><?= $totalAdmins ?> Beheerders • <?= $totalMembers ?> Collega's</span>
<span class="text-xs text-slate-500 dark:text-slate-400 font-medium block">Totaal Teamleden</span>
<span class="text-2xl font-black text-slate-900 dark:text-white"><?= $totalUsers ?></span>
<span class="text-[10px] text-slate-500 dark:text-slate-500 block"><?= $totalAdmins ?> Beheerders • <?= $totalMembers ?> Collega's</span>
</div>
</div>
<div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-4 flex items-center space-x-4">
<div class="w-12 h-12 rounded-xl bg-blue-500/10 border border-blue-500/20 flex items-center justify-center text-blue-400 flex-shrink-0">
<div class="bg-white dark:bg-slate-900/70 border border-slate-200 dark:border-slate-800 rounded-3xl p-5 flex items-center space-x-4 shadow-sm transition">
<div class="w-12 h-12 rounded-2xl bg-blue-500/10 border border-blue-500/20 flex items-center justify-center text-blue-600 dark:text-blue-400 flex-shrink-0">
<i data-lucide="calendar" class="w-6 h-6"></i>
</div>
<div>
<span class="text-xs text-slate-400 font-medium block">Outlook Live Gekoppeld</span>
<span class="text-2xl font-black text-white"><?= $outlookConnectedCount ?></span>
<span class="text-[10px] text-emerald-400 block"><?= $appConfig['is_configured'] ? 'Azure App Actief' : 'Configuratie nodig' ?></span>
<span class="text-xs text-slate-500 dark:text-slate-400 font-medium block">Outlook Live Gekoppeld</span>
<span class="text-2xl font-black text-slate-900 dark:text-white"><?= $outlookConnectedCount ?></span>
<span class="text-[10px] text-emerald-600 dark:text-emerald-400 block"><?= $appConfig['is_configured'] ? 'Azure App Actief' : 'Configuratie nodig' ?></span>
</div>
</div>
<div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-4 flex items-center space-x-4">
<div class="w-12 h-12 rounded-xl bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center text-indigo-400 flex-shrink-0">
<div class="bg-white dark:bg-slate-900/70 border border-slate-200 dark:border-slate-800 rounded-3xl p-5 flex items-center space-x-4 shadow-sm transition">
<div class="w-12 h-12 rounded-2xl bg-indigo-500/10 border border-indigo-500/20 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>
</div>
<div>
<span class="text-xs text-slate-400 font-medium block">Jira Gekoppeld</span>
<span class="text-2xl font-black text-white"><?= $jiraConnectedCount ?></span>
<span class="text-[10px] text-slate-500 block"><?= !empty($companyJiraDomain) ? 'Domein ingesteld' : 'Geen domein' ?></span>
<span class="text-xs text-slate-500 dark:text-slate-400 font-medium block">Jira Gekoppeld</span>
<span class="text-2xl font-black text-slate-900 dark:text-white"><?= $jiraConnectedCount ?></span>
<span class="text-[10px] text-slate-500 dark:text-slate-500 block"><?= !empty($companyJiraDomain) ? 'Domein ingesteld' : 'Geen domein' ?></span>
</div>
</div>
<div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-4 flex items-center space-x-4">
<div class="w-12 h-12 rounded-xl bg-amber-500/10 border border-amber-500/20 flex items-center justify-center text-amber-400 flex-shrink-0">
<div class="bg-white dark:bg-slate-900/70 border border-slate-200 dark:border-slate-800 rounded-3xl p-5 flex items-center space-x-4 shadow-sm transition">
<div class="w-12 h-12 rounded-2xl bg-amber-500/10 border border-amber-500/20 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>
</div>
<div>
<span class="text-xs text-slate-400 font-medium block">Openstaande Invites</span>
<span class="text-2xl font-black text-white"><?= $pendingInvites ?></span>
<a href="/users.php" class="text-[10px] text-amber-400 hover:underline block">Beheer uitnodigingen &rarr;</a>
<span class="text-xs text-slate-500 dark:text-slate-400 font-medium block">Openstaande Invites</span>
<span class="text-2xl font-black text-slate-900 dark:text-white"><?= $pendingInvites ?></span>
<a href="/users.php" class="text-[10px] text-amber-600 dark:text-amber-400 hover:underline block font-medium">Beheer uitnodigingen &rarr;</a>
</div>
</div>
</div>
@@ -222,34 +222,34 @@ require_once __DIR__ . '/includes/header.php';
<div class="lg:col-span-8 space-y-8">
<!-- 1. Microsoft 365 Azure App Registratie -->
<div class="bg-slate-900/80 border border-slate-800 rounded-3xl p-6 sm:p-7 shadow-xl">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-6 border-b border-slate-800/80">
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl 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 items-center space-x-3.5">
<div class="w-12 h-12 rounded-2xl bg-blue-500/10 border border-blue-500/20 flex items-center justify-center text-blue-400 font-bold shadow-md">
<div class="w-12 h-12 rounded-2xl bg-blue-500/10 border border-blue-500/20 flex items-center justify-center text-blue-600 dark:text-blue-400 font-bold shadow-sm">
<i data-lucide="cloud" class="w-6 h-6"></i>
</div>
<div>
<div class="flex items-center space-x-2">
<h2 class="text-lg font-bold text-white tracking-tight">Microsoft 365 & Azure App Registratie</h2>
<h2 class="text-lg font-bold text-slate-900 dark:text-white tracking-tight">Microsoft 365 & Azure App Registratie</h2>
<?php if ($appConfig['is_configured']): ?>
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/15 border border-emerald-500/30 text-emerald-400 text-[10px] font-bold">
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/15 border border-emerald-500/30 text-emerald-700 dark:text-emerald-400 text-[10px] font-bold">
Geconfigureerd
</span>
<?php else: ?>
<span class="px-2.5 py-0.5 rounded-full bg-amber-500/15 border border-amber-500/30 text-amber-400 text-[10px] font-bold">
<span class="px-2.5 py-0.5 rounded-full bg-amber-500/15 border border-amber-500/30 text-amber-700 dark:text-amber-400 text-[10px] font-bold">
Configuratie Vereist
</span>
<?php endif; ?>
</div>
<p class="text-xs text-slate-400">Centrale OAuth 2.0 instellingen voor de hele organisatie</p>
<p class="text-xs text-slate-500 dark:text-slate-400">Centrale OAuth 2.0 instellingen voor de hele organisatie</p>
</div>
</div>
<?php if ($appConfig['is_configured']): ?>
<a href="<?= htmlspecialchars($adminConsentUrl) ?>" target="_blank" rel="noopener noreferrer" class="inline-flex items-center space-x-2 px-3.5 py-2 rounded-xl bg-blue-600/20 hover:bg-blue-600/30 text-blue-300 border border-blue-500/30 text-xs font-semibold transition" title="Verleen namens alle gebruikers beheerdersgoedkeuring in Azure">
<i data-lucide="shield-check" class="w-4 h-4 text-blue-400"></i>
<a href="<?= htmlspecialchars($adminConsentUrl) ?>" target="_blank" rel="noopener noreferrer" class="inline-flex items-center space-x-2 px-3.5 py-2 rounded-xl bg-blue-50 hover:bg-blue-100 dark:bg-blue-600/20 dark:hover:bg-blue-600/30 text-blue-700 dark:text-blue-300 border border-blue-200 dark:border-blue-500/30 text-xs font-semibold transition" title="Verleen namens alle gebruikers beheerdersgoedkeuring in Azure">
<i data-lucide="shield-check" class="w-4 h-4 text-blue-600 dark:text-blue-400"></i>
<span>Admin Consent Verlenen</span>
<i data-lucide="external-link" class="w-3.5 h-3.5 text-blue-400"></i>
<i data-lucide="external-link" class="w-3.5 h-3.5 text-blue-600 dark:text-blue-400"></i>
</a>
<?php endif; ?>
</div>
@@ -258,17 +258,17 @@ require_once __DIR__ . '/includes/header.php';
<input type="hidden" name="action" value="save_azure">
<!-- Redirect URI Kopieerbox -->
<div class="p-4 rounded-2xl bg-slate-950/70 border border-slate-800 space-y-2">
<div class="p-4 rounded-2xl bg-slate-50 dark:bg-slate-950/70 border border-slate-200 dark:border-slate-800 space-y-2">
<div class="flex items-center justify-between">
<label class="text-xs font-semibold text-slate-300 flex items-center space-x-1.5">
<i data-lucide="link" class="w-3.5 h-3.5 text-blue-400"></i>
<label class="text-xs font-semibold text-slate-700 dark:text-slate-300 flex items-center space-x-1.5">
<i data-lucide="link" class="w-3.5 h-3.5 text-blue-500"></i>
<span>Redirect URI (Terugbel-URL voor Azure Portal)</span>
</label>
<span class="text-[10px] text-slate-500">Kopieer dit exact naar de Azure Web Redirect URIs</span>
</div>
<div class="flex items-center space-x-2">
<input type="text" readonly id="adminRedirectUri" value="<?= htmlspecialchars($redirectUri) ?>" class="flex-1 bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-xs font-mono text-emerald-400 select-all focus:outline-none">
<button type="button" onclick="copyAdminRedirectUri()" class="px-3 py-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-white text-xs font-semibold flex items-center space-x-1.5 transition">
<input type="text" readonly id="adminRedirectUri" value="<?= htmlspecialchars($redirectUri) ?>" class="flex-1 bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-2 text-xs font-mono text-emerald-600 dark:text-emerald-400 select-all focus:outline-none">
<button type="button" onclick="copyAdminRedirectUri()" class="px-3 py-2 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-800 dark:text-white text-xs font-semibold flex items-center space-x-1.5 transition border border-slate-200 dark:border-transparent cursor-pointer">
<i data-lucide="copy" class="w-3.5 h-3.5" id="copyIcon"></i>
<span id="copyText">Kopiëren</span>
</button>
@@ -278,83 +278,83 @@ require_once __DIR__ . '/includes/header.php';
<!-- Client ID & Tenant ID Grid -->
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label class="block text-xs font-semibold text-slate-300 mb-1.5">
Application (Client) ID <span class="text-red-400">*</span>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5">
Application (Client) ID <span class="text-red-500">*</span>
</label>
<input type="text" name="client_id" required value="<?= htmlspecialchars($appConfig['client_id']) ?>" placeholder="bijv. 38314451-1d05-4205-88ec-..." class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-white placeholder-slate-600 focus:outline-none focus:border-blue-500">
<input type="text" name="client_id" required value="<?= htmlspecialchars($appConfig['client_id']) ?>" placeholder="bijv. 38314451-1d05-4205-88ec-..." class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-600 focus:outline-none focus:border-blue-500">
</div>
<div>
<label class="block text-xs font-semibold text-slate-300 mb-1.5">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5">
Directory (Tenant) ID / Domeinnaam
</label>
<input type="text" name="tenant_id" value="<?= htmlspecialchars((!empty($appConfig['tenant_id']) && $appConfig['tenant_id'] !== 'common') ? $appConfig['tenant_id'] : 'planningsagenda.nl') ?>" placeholder="bijv. planningsagenda.nl of Azure Tenant GUID" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-white placeholder-slate-600 focus:outline-none focus:border-blue-500 font-mono">
<span class="text-[10px] text-slate-400 mt-1 block">Vul uw domeinnaam in (<code class="text-emerald-400 font-mono">planningsagenda.nl</code>) of de Directory (tenant) ID uit Azure. <em>Let op: Gebruik géén 'common' voor single-tenant apps.</em></span>
<input type="text" name="tenant_id" value="<?= htmlspecialchars((!empty($appConfig['tenant_id']) && $appConfig['tenant_id'] !== 'common') ? $appConfig['tenant_id'] : 'planningsagenda.nl') ?>" placeholder="bijv. planningsagenda.nl of Azure Tenant GUID" class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-600 focus:outline-none focus:border-blue-500 font-mono">
<span class="text-[10px] text-slate-500 dark:text-slate-400 mt-1 block">Vul uw domeinnaam in (<code class="text-emerald-600 dark:text-emerald-400 font-mono">planningsagenda.nl</code>) of de Directory (tenant) ID uit Azure. <em>Let op: Gebruik géén 'common' voor single-tenant apps.</em></span>
</div>
</div>
<!-- Client Secret met toggle -->
<div>
<div class="flex items-center justify-between mb-1.5">
<label class="text-xs font-semibold text-slate-300">
Client Secret (Value) <span class="text-red-400">*</span>
<label class="text-xs font-semibold text-slate-700 dark:text-slate-300">
Client Secret (Value) <span class="text-red-500">*</span>
</label>
<span class="text-[10px] text-slate-500">Wordt veilig en versleuteld opgeslagen</span>
</div>
<div class="relative">
<input type="password" id="adminClientSecret" name="client_secret" value="<?= !empty($appConfig['client_secret']) ? '••••••••••••••••' : '' ?>" placeholder="Voer de Secret Value in uit Azure..." class="w-full bg-slate-950 border border-slate-800 rounded-xl pl-3.5 pr-10 py-2.5 text-xs text-white placeholder-slate-600 focus:outline-none focus:border-blue-500">
<button type="button" onclick="toggleAdminSecret()" class="absolute inset-y-0 right-0 pr-3 flex items-center text-slate-500 hover:text-slate-300">
<input type="password" id="adminClientSecret" name="client_secret" value="<?= !empty($appConfig['client_secret']) ? '••••••••••••••••' : '' ?>" placeholder="Voer de Secret Value in uit Azure..." class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl pl-3.5 pr-10 py-2.5 text-xs text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-600 focus:outline-none focus:border-blue-500">
<button type="button" onclick="toggleAdminSecret()" class="absolute inset-y-0 right-0 pr-3 flex items-center text-slate-400 hover:text-slate-600 dark:hover:text-slate-300">
<i data-lucide="eye" class="w-4 h-4" id="eyeSecretIcon"></i>
</button>
</div>
</div>
<div class="pt-2 flex items-center justify-between">
<div class="text-[11px] text-slate-400">
<div class="text-[11px] text-slate-500 dark:text-slate-400">
Zodra opgeslagen kunnen al uw collega's met 1 klik hun Outlook agenda koppelen.
</div>
<button type="submit" class="px-5 py-2.5 rounded-xl bg-blue-600 hover:bg-blue-500 text-white text-xs font-bold transition shadow-lg shadow-blue-500/20">
<button type="submit" class="px-5 py-2.5 rounded-xl bg-blue-600 hover:bg-blue-500 text-white text-xs font-bold transition shadow-lg shadow-blue-500/20 cursor-pointer">
Azure Gegevens Opslaan
</button>
</div>
</form>
<!-- Azure Setup Documentatie Accordion -->
<div class="mt-6 pt-6 border-t border-slate-800/80">
<button type="button" onclick="toggleAdminGuide()" class="w-full flex items-center justify-between text-xs font-semibold text-slate-300 hover:text-white transition">
<div class="mt-6 pt-6 border-t border-slate-100 dark:border-slate-800/80">
<button type="button" onclick="toggleAdminGuide()" class="w-full flex items-center justify-between text-xs font-semibold text-slate-700 dark:text-slate-300 hover:text-slate-900 dark:hover:text-white transition cursor-pointer">
<span class="flex items-center space-x-2">
<i data-lucide="help-circle" class="w-4 h-4 text-blue-400"></i>
<i data-lucide="help-circle" class="w-4 h-4 text-blue-500"></i>
<span>Hoe configureer ik de Azure App Registratie in 4 stappen?</span>
</span>
<i data-lucide="chevron-down" class="w-4 h-4 transition-transform duration-200" id="guideArrow"></i>
</button>
<div id="adminGuideContent" class="hidden mt-4 p-4 rounded-2xl bg-slate-950/60 border border-slate-800 text-xs text-slate-300 space-y-3 leading-relaxed">
<div id="adminGuideContent" class="hidden mt-4 p-4 rounded-2xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800 text-xs text-slate-600 dark:text-slate-300 space-y-3 leading-relaxed">
<div class="flex items-start space-x-2.5">
<span class="w-5 h-5 rounded-full bg-blue-500/20 text-blue-400 flex items-center justify-center font-bold text-[10px] flex-shrink-0 mt-0.5">1</span>
<span class="w-5 h-5 rounded-full bg-blue-500/20 text-blue-600 dark:text-blue-400 flex items-center justify-center font-bold text-[10px] flex-shrink-0 mt-0.5">1</span>
<div>
<strong class="text-white">Azure Portal:</strong> Ga naar <a href="https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps" target="_blank" class="text-blue-400 underline">portal.azure.com</a> &rarr; <em>Microsoft Entra ID</em> &rarr; <em>App registrations</em> &rarr; <em>New registration</em>. Kies "Accounts in any organizational directory and personal Microsoft accounts" (of alleen uw organisatie).
<strong class="text-slate-900 dark:text-white">Azure Portal:</strong> Ga naar <a href="https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps" target="_blank" class="text-blue-600 dark:text-blue-400 underline">portal.azure.com</a> &rarr; <em>Microsoft Entra ID</em> &rarr; <em>App registrations</em> &rarr; <em>New registration</em>. Kies "Accounts in this organizational directory only" (single-tenant).
</div>
</div>
<div class="flex items-start space-x-2.5">
<span class="w-5 h-5 rounded-full bg-blue-500/20 text-blue-400 flex items-center justify-center font-bold text-[10px] flex-shrink-0 mt-0.5">2</span>
<span class="w-5 h-5 rounded-full bg-blue-500/20 text-blue-600 dark:text-blue-400 flex items-center justify-center font-bold text-[10px] flex-shrink-0 mt-0.5">2</span>
<div>
<strong class="text-white">Redirect URI:</strong> Kies platform <strong>Web</strong> en vul exact in: <code class="text-emerald-400 font-mono"><?= htmlspecialchars($redirectUri) ?></code>.
<strong class="text-slate-900 dark:text-white">Redirect URI:</strong> Kies platform <strong>Web</strong> en vul exact in: <code class="text-emerald-600 dark:text-emerald-400 font-mono"><?= htmlspecialchars($redirectUri) ?></code>.
</div>
</div>
<div class="flex items-start space-x-2.5">
<span class="w-5 h-5 rounded-full bg-blue-500/20 text-blue-400 flex items-center justify-center font-bold text-[10px] flex-shrink-0 mt-0.5">3</span>
<span class="w-5 h-5 rounded-full bg-blue-500/20 text-blue-600 dark:text-blue-400 flex items-center justify-center font-bold text-[10px] flex-shrink-0 mt-0.5">3</span>
<div>
<strong class="text-white">API Permissions:</strong> Ga naar <em>API permissions</em> &rarr; <em>Add a permission</em> &rarr; <em>Microsoft Graph</em> &rarr; <strong>Delegated permissions</strong> &rarr; Vink aan: <code class="text-blue-400">User.Read</code> en <code class="text-blue-400">Calendars.ReadWrite</code>.
<strong class="text-slate-900 dark:text-white">API Permissions:</strong> Ga naar <em>API permissions</em> &rarr; <em>Add a permission</em> &rarr; <em>Microsoft Graph</em> &rarr; <strong>Delegated permissions</strong> &rarr; Vink aan: <code class="text-blue-600 dark:text-blue-400">User.Read</code> en <code class="text-blue-600 dark:text-blue-400">Calendars.ReadWrite</code>.
</div>
</div>
<div class="flex items-start space-x-2.5">
<span class="w-5 h-5 rounded-full bg-blue-500/20 text-blue-400 flex items-center justify-center font-bold text-[10px] flex-shrink-0 mt-0.5">4</span>
<span class="w-5 h-5 rounded-full bg-blue-500/20 text-blue-600 dark:text-blue-400 flex items-center justify-center font-bold text-[10px] flex-shrink-0 mt-0.5">4</span>
<div>
<strong class="text-white">Beheerdersgoedkeuring (Admin Consent):</strong> Klik op <em>"Grant admin consent for [Uw Organisatie]"</em>. Er verschijnt direct een groen vinkje bij alle regels. Hiermee hoeven individuele collega's geen beheerder meer te vragen!
<strong class="text-slate-900 dark:text-white">Beheerdersgoedkeuring (Admin Consent):</strong> Klik op <em>"Grant admin consent for [Uw Organisatie]"</em>. Er verschijnt direct een groen vinkje bij alle regels. Hiermee hoeven individuele collega's geen beheerder meer te vragen!
</div>
</div>
</div>
@@ -362,25 +362,25 @@ require_once __DIR__ . '/includes/header.php';
</div>
<!-- 2. Atlassian Jira Bedrijfsinstellingen -->
<div class="bg-slate-900/80 border border-slate-800 rounded-3xl p-6 sm:p-7 shadow-xl">
<div class="flex items-center space-x-3.5 pb-6 border-b border-slate-800/80">
<div class="w-12 h-12 rounded-2xl bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center text-indigo-400 font-bold shadow-md">
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl transition">
<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-500/10 border border-indigo-500/20 flex items-center justify-center text-indigo-600 dark:text-indigo-400 font-bold shadow-sm">
<i data-lucide="trello" class="w-6 h-6"></i>
</div>
<div>
<div class="flex items-center space-x-2">
<h2 class="text-lg font-bold text-white tracking-tight">Atlassian Jira Organisatie-instellingen</h2>
<h2 class="text-lg font-bold text-slate-900 dark:text-white tracking-tight">Atlassian Jira Organisatie-instellingen</h2>
<?php if (!empty($companyJiraDomain)): ?>
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/15 border border-emerald-500/30 text-emerald-400 text-[10px] font-bold">
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/15 border border-emerald-500/30 text-emerald-700 dark:text-emerald-400 text-[10px] font-bold">
Actief
</span>
<?php else: ?>
<span class="px-2.5 py-0.5 rounded-full bg-slate-800 text-slate-400 text-[10px] font-bold">
<span class="px-2.5 py-0.5 rounded-full bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400 text-[10px] font-bold">
Optioneel
</span>
<?php endif; ?>
</div>
<p class="text-xs text-slate-400">Standaard Jira Cloud domein voor het hele team</p>
<p class="text-xs text-slate-500 dark:text-slate-400">Standaard Jira Cloud domein voor het hele team</p>
</div>
</div>
@@ -388,17 +388,17 @@ require_once __DIR__ . '/includes/header.php';
<input type="hidden" name="action" value="save_jira_domain">
<div>
<label class="block text-xs font-semibold text-slate-300 mb-1.5">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5">
Standaard Jira Bedrijfsdomein
</label>
<input type="text" name="jira_domain" value="<?= htmlspecialchars($companyJiraDomain) ?>" placeholder="https://uwbedrijf.atlassian.net" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-white placeholder-slate-600 focus:outline-none focus:border-indigo-500 font-mono">
<p class="text-[11px] text-slate-400 mt-1.5 leading-relaxed">
<input type="text" name="jira_domain" value="<?= htmlspecialchars($companyJiraDomain) ?>" placeholder="https://uwbedrijf.atlassian.net" class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-600 focus:outline-none focus:border-indigo-500 font-mono">
<p class="text-[11px] text-slate-500 dark:text-slate-400 mt-1.5 leading-relaxed">
Wanneer u dit instelt, wordt dit domein automatisch vooraf ingevuld op de profielpagina van alle collega's. Zij hoeven dan enkel nog hun eigen persoonlijke e-mailadres en Atlassian API-token in te voeren.
</p>
</div>
<div class="flex justify-end pt-2">
<button type="submit" class="px-5 py-2.5 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-bold transition shadow-lg shadow-indigo-500/20">
<button type="submit" class="px-5 py-2.5 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-bold transition shadow-lg shadow-indigo-500/20 cursor-pointer">
Jira Domein Opslaan
</button>
</div>
@@ -406,56 +406,56 @@ require_once __DIR__ . '/includes/header.php';
</div>
<!-- 3. Toekomstige Systeemmodules Hub -->
<div class="bg-slate-900/80 border border-slate-800 rounded-3xl p-6 sm:p-7 shadow-xl space-y-6">
<div class="flex items-center space-x-3.5 pb-4 border-b border-slate-800/80">
<div class="w-12 h-12 rounded-2xl bg-teal-500/10 border border-teal-500/20 flex items-center justify-center text-teal-400 font-bold shadow-md">
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl space-y-6 transition">
<div class="flex items-center space-x-3.5 pb-4 border-b border-slate-100 dark:border-slate-800/80">
<div class="w-12 h-12 rounded-2xl bg-teal-500/10 border border-teal-500/20 flex items-center justify-center text-teal-600 dark:text-teal-400 font-bold shadow-sm">
<i data-lucide="cpu" class="w-6 h-6"></i>
</div>
<div>
<h2 class="text-lg font-bold text-white tracking-tight">Toekomstige Modules & Extensies</h2>
<p class="text-xs text-slate-400">Voorbereid architectuurkader voor nieuwe bedrijfssystemen</p>
<h2 class="text-lg font-bold text-slate-900 dark:text-white tracking-tight">Toekomstige Modules & Extensies</h2>
<p class="text-xs text-slate-500 dark:text-slate-400">Voorbereid architectuurkader voor nieuwe bedrijfssystemen</p>
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<!-- Module 1: AI Brainstorm -->
<div class="p-4 rounded-2xl bg-slate-950/60 border border-slate-800/80 flex flex-col justify-between space-y-3">
<div class="p-4 rounded-2xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800/80 flex flex-col justify-between space-y-3">
<div>
<div class="flex items-center justify-between mb-2">
<span class="text-xs font-bold text-white flex items-center space-x-1.5">
<i data-lucide="sparkles" class="w-4 h-4 text-amber-400"></i>
<span class="text-xs font-bold text-slate-900 dark:text-white flex items-center space-x-1.5">
<i data-lucide="sparkles" class="w-4 h-4 text-amber-500"></i>
<span>AI & Brainstorm Co-Pilot</span>
</span>
<span class="px-2 py-0.5 rounded-full bg-amber-500/10 text-amber-400 text-[10px] font-semibold border border-amber-500/20">
<span class="px-2 py-0.5 rounded-full bg-amber-500/10 text-amber-700 dark:text-amber-400 text-[10px] font-semibold border border-amber-500/20">
Voorbereid
</span>
</div>
<p class="text-[11px] text-slate-400 leading-relaxed">
<p class="text-[11px] text-slate-600 dark:text-slate-400 leading-relaxed">
Centrale OpenAI of Anthropic Claude API-sleutels instellen voor automatische categorisatie van sticky notes en taakschattingen.
</p>
</div>
<div class="pt-2 border-t border-slate-900 text-[10px] text-slate-500">
<div class="pt-2 border-t border-slate-200 dark:border-slate-900 text-[10px] text-slate-500">
Gepland voor release v1.5
</div>
</div>
<!-- Module 2: Dagplanning Standaarden -->
<div class="p-4 rounded-2xl bg-slate-950/60 border border-slate-800/80 flex flex-col justify-between space-y-3">
<div class="p-4 rounded-2xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800/80 flex flex-col justify-between space-y-3">
<div>
<div class="flex items-center justify-between mb-2">
<span class="text-xs font-bold text-white flex items-center space-x-1.5">
<i data-lucide="clock" class="w-4 h-4 text-emerald-400"></i>
<span class="text-xs font-bold text-slate-900 dark:text-white flex items-center space-x-1.5">
<i data-lucide="clock" class="w-4 h-4 text-emerald-600 dark:text-emerald-400"></i>
<span>Organisatie Werkdag Standaarden</span>
</span>
<span class="px-2 py-0.5 rounded-full bg-emerald-500/10 text-emerald-400 text-[10px] font-semibold border border-emerald-500/20">
<span class="px-2 py-0.5 rounded-full bg-emerald-500/10 text-emerald-700 dark:text-emerald-400 text-[10px] font-semibold border border-emerald-500/20">
Binnenkort
</span>
</div>
<p class="text-[11px] text-slate-400 leading-relaxed">
<p class="text-[11px] text-slate-600 dark:text-slate-400 leading-relaxed">
Standaard kantoortijden instellen (bijv. 08:30 - 17:00), standaard Pomodoro tijden (25m / 50m) en lunchpauze blokken.
</p>
</div>
<div class="pt-2 border-t border-slate-900 text-[10px] text-slate-500">
<div class="pt-2 border-t border-slate-200 dark:border-slate-900 text-[10px] text-slate-500">
Gepland voor release v1.4
</div>
</div>
@@ -467,35 +467,35 @@ require_once __DIR__ . '/includes/header.php';
<div class="lg:col-span-4 space-y-6">
<!-- Team Status Overzicht -->
<div class="bg-slate-900/80 border border-slate-800 rounded-3xl p-6 shadow-xl space-y-5">
<div class="flex items-center justify-between pb-4 border-b border-slate-800/80">
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 shadow-sm dark:shadow-xl 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 space-x-2.5">
<i data-lucide="activity" class="w-4 h-4 text-emerald-400"></i>
<h3 class="text-sm font-bold text-white">Team & Integratiestatus</h3>
<i data-lucide="activity" class="w-4 h-4 text-emerald-600 dark:text-emerald-400"></i>
<h3 class="text-sm font-bold text-slate-900 dark:text-white">Team & Integratiestatus</h3>
</div>
<a href="/users.php" class="text-[11px] text-emerald-400 hover:underline font-semibold">
<a href="/users.php" class="text-[11px] text-emerald-600 dark:text-emerald-400 hover:underline font-semibold">
Alle gebruikers &rarr;
</a>
</div>
<div class="space-y-3">
<?php foreach ($recentUsers as $u): ?>
<div class="p-3 rounded-2xl bg-slate-950/60 border border-slate-800/70 flex items-center justify-between">
<div class="p-3 rounded-2xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800/70 flex items-center justify-between">
<div class="flex items-center space-x-3 overflow-hidden">
<div class="w-8 h-8 rounded-full bg-emerald-600/20 border border-emerald-500/30 text-emerald-400 font-bold flex items-center justify-center text-xs flex-shrink-0">
<div class="w-8 h-8 rounded-full bg-emerald-600/15 border border-emerald-500/30 text-emerald-700 dark:text-emerald-400 font-bold flex items-center justify-center text-xs flex-shrink-0">
<?= strtoupper(substr($u['name'], 0, 1)) ?>
</div>
<div class="truncate">
<span class="text-xs font-semibold text-white block truncate"><?= htmlspecialchars($u['name']) ?></span>
<span class="text-[10px] text-slate-400 block truncate"><?= htmlspecialchars($u['email']) ?></span>
<span class="text-xs font-semibold text-slate-900 dark:text-white block truncate"><?= htmlspecialchars($u['name']) ?></span>
<span class="text-[10px] text-slate-500 dark:text-slate-400 block truncate"><?= htmlspecialchars($u['email']) ?></span>
</div>
</div>
<div class="flex items-center space-x-1.5 flex-shrink-0">
<span title="Outlook: <?= $u['has_outlook'] ? 'Live Gekoppeld' : 'Niet gekoppeld' ?>" class="w-5 h-5 rounded-md flex items-center justify-center text-[10px] <?= $u['has_outlook'] ? 'bg-blue-500/20 text-blue-300 border border-blue-500/30' : 'bg-slate-800 text-slate-600' ?>">
<span title="Outlook: <?= $u['has_outlook'] ? 'Live Gekoppeld' : 'Niet gekoppeld' ?>" class="w-5 h-5 rounded-md flex items-center justify-center text-[10px] <?= $u['has_outlook'] ? 'bg-blue-500/20 text-blue-700 dark:text-blue-300 border border-blue-500/30' : 'bg-slate-200 dark:bg-slate-800 text-slate-400 dark:text-slate-600' ?>">
<i data-lucide="calendar" class="w-3 h-3"></i>
</span>
<span title="Jira: <?= $u['has_jira'] ? 'Gekoppeld' : 'Niet gekoppeld' ?>" class="w-5 h-5 rounded-md flex items-center justify-center text-[10px] <?= $u['has_jira'] ? 'bg-indigo-500/20 text-indigo-300 border border-indigo-500/30' : 'bg-slate-800 text-slate-600' ?>">
<span title="Jira: <?= $u['has_jira'] ? 'Gekoppeld' : 'Niet gekoppeld' ?>" class="w-5 h-5 rounded-md flex items-center justify-center text-[10px] <?= $u['has_jira'] ? 'bg-indigo-500/20 text-indigo-700 dark:text-indigo-300 border border-indigo-500/30' : 'bg-slate-200 dark:bg-slate-800 text-slate-400 dark:text-slate-600' ?>">
<i data-lucide="check-square" class="w-3 h-3"></i>
</span>
</div>
@@ -504,41 +504,41 @@ require_once __DIR__ . '/includes/header.php';
</div>
<div class="pt-2">
<a href="/users.php" class="w-full flex items-center justify-center space-x-2 py-2.5 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-200 text-xs font-semibold transition border border-slate-700">
<i data-lucide="user-plus" class="w-3.5 h-3.5 text-emerald-400"></i>
<a href="/users.php" class="w-full flex items-center justify-center space-x-2 py-2.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-800 dark:text-slate-200 text-xs font-semibold transition border border-slate-200 dark:border-slate-700 shadow-sm">
<i data-lucide="user-plus" class="w-3.5 h-3.5 text-emerald-600 dark:text-emerald-400"></i>
<span>Nieuwe Collega Uitnodigen</span>
</a>
</div>
</div>
<!-- Systeem Gezondheid & Beveiliging -->
<div class="bg-slate-900/80 border border-slate-800 rounded-3xl p-6 shadow-xl space-y-4">
<div class="flex items-center space-x-2 text-emerald-400 text-xs font-semibold">
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 shadow-sm dark:shadow-xl space-y-4 transition">
<div class="flex items-center space-x-2 text-emerald-600 dark:text-emerald-400 text-xs font-semibold">
<i data-lucide="shield-check" class="w-4 h-4"></i>
<span>Systeem & Beveiliging</span>
</div>
<div class="space-y-2.5 text-xs text-slate-300">
<div class="flex items-center justify-between p-2.5 rounded-xl bg-slate-950/60 border border-slate-800">
<div class="space-y-2.5 text-xs text-slate-700 dark:text-slate-300">
<div class="flex items-center justify-between p-2.5 rounded-xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800">
<span>Tweestapsverificatie (2FA)</span>
<span class="text-emerald-400 font-bold flex items-center space-x-1">
<span class="text-emerald-600 dark:text-emerald-400 font-bold flex items-center space-x-1">
<i data-lucide="check" class="w-3 h-3"></i>
<span>Verplicht</span>
</span>
</div>
<div class="flex items-center justify-between p-2.5 rounded-xl bg-slate-950/60 border border-slate-800">
<div class="flex items-center justify-between p-2.5 rounded-xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800">
<span>Database Versie</span>
<span class="text-slate-400 font-mono text-[11px]">MariaDB 10.x</span>
<span class="text-slate-500 dark:text-slate-400 font-mono text-[11px]">MariaDB 10.x</span>
</div>
<div class="flex items-center justify-between p-2.5 rounded-xl bg-slate-950/60 border border-slate-800">
<div class="flex items-center justify-between p-2.5 rounded-xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800">
<span>Push Notificaties</span>
<span class="text-emerald-400 font-bold">Actief</span>
<span class="text-emerald-600 dark:text-emerald-400 font-bold">Actief</span>
</div>
<div class="flex items-center justify-between p-2.5 rounded-xl bg-slate-950/60 border border-slate-800">
<div class="flex items-center justify-between p-2.5 rounded-xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800">
<span>Graph API Sync</span>
<span class="text-blue-400 font-bold">Live v1.0</span>
<span class="text-blue-600 dark:text-blue-400 font-bold">Live v1.0</span>
</div>
</div>
</div>
@@ -592,4 +592,3 @@ function toggleAdminGuide() {
</script>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
+47
View File
@@ -0,0 +1,47 @@
<?php
/**
* Fociz Thema API Endpoint (Dark / Light / System)
*/
header('Content-Type: application/json; charset=utf-8');
require_once __DIR__ . '/../includes/auth.php';
$user = require_auth(true);
$userId = (int)$user['id'];
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$currentTheme = get_user_theme($userId);
echo json_encode([
'success' => true,
'theme' => $currentTheme,
]);
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
$theme = $data['theme'] ?? ($_POST['theme'] ?? 'dark');
if (!in_array($theme, ['dark', 'light', 'system'])) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Ongeldig thema. Kies dark, light of system.']);
exit;
}
$ok = update_user_theme($userId, $theme);
if ($ok) {
echo json_encode([
'success' => true,
'theme' => $theme,
'message' => 'Themavoorkeur succesvol opgeslagen.',
]);
} else {
http_response_code(500);
echo json_encode(['success' => false, 'error' => 'Kon thema niet opslaan in database.']);
}
exit;
}
http_response_code(405);
echo json_encode(['success' => false, 'error' => 'Method not allowed']);
+68 -30
View File
@@ -59,23 +59,28 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// STAP 2: 2FA TOTP Code verificatie
elseif ($step === 2) {
$userId = $_SESSION['pending_2fa_user_id'] ?? null;
$totpCode = trim(str_replace(' ', '', $_POST['totp_code'] ?? ''));
$totpCode = trim($_POST['totp_code'] ?? '');
if (!$userId || empty($totpCode)) {
$error = "Vul de 6-cijferige 2FA verificatiecode in.";
if (!$userId) {
header('Location: /auth/login.php');
exit;
}
if (empty($totpCode)) {
$error = "Vul de 6-cijferige 2FA code in uit uw authenticator app.";
} else {
$stmt = $db->prepare("SELECT id, name, email, role, two_factor_secret, backup_codes FROM users WHERE id = ?");
$stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$userId]);
$user = $stmt->fetch();
$isValid = false;
// 1. Controleer TOTP code
if (!empty($user['two_factor_secret']) && TOTP::verifyCode($user['two_factor_secret'], $totpCode)) {
$isValid = true;
// Controleer reguliere TOTP code
if (!empty($user['two_factor_secret'])) {
$isValid = verify_totp($user['two_factor_secret'], $totpCode);
}
// 2. Controleer optioneel backup codes
// Fallback: controleer 8-karakter backup codes
if (!$isValid && !empty($user['backup_codes'])) {
$backupCodes = json_decode($user['backup_codes'], true) ?: [];
$codeUpper = strtoupper($totpCode);
@@ -119,28 +124,62 @@ $pageTitle = "Fociz — Inloggen";
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= htmlspecialchars($pageTitle) ?></title>
<!-- Anti-flicker script: Laad direct het gekozen thema uit localStorage vóór DOM render -->
<script>
(function() {
var activeTheme = localStorage.getItem('fociz_theme') || 'dark';
var isDark = true;
if (activeTheme === 'dark') isDark = true;
else if (activeTheme === 'light') isDark = false;
else if (activeTheme === 'system') {
isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
}
if (isDark) document.documentElement.classList.add('dark');
else document.documentElement.classList.remove('dark');
})();
</script>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
slate: {
850: '#151f32',
950: '#070b12',
}
}
}
}
}
</script>
<script src="https://unpkg.com/lucide@latest"></script>
<style>body { background-color: #090d16; color: #f1f5f9; }</style>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<style>
body { font-family: 'Plus Jakarta Sans', sans-serif; }
</style>
</head>
<body class="min-h-screen flex items-center justify-center p-4 bg-gradient-to-br from-[#090d16] via-[#0f172a] to-[#090d16]">
<body class="min-h-screen flex items-center justify-center p-4 bg-slate-50 dark:bg-gradient-to-br dark:from-[#090d16] dark:via-[#0f172a] dark:to-[#090d16] text-slate-900 dark:text-slate-100 transition-colors">
<?php require_once __DIR__ . '/../includes/env_badge.php'; ?>
<div class="w-full max-w-md bg-slate-900/90 border border-slate-800 rounded-2xl shadow-2xl backdrop-blur-xl p-8">
<div class="w-full max-w-md bg-white dark:bg-slate-900/90 border border-slate-200 dark:border-slate-800 rounded-3xl shadow-xl dark:shadow-2xl backdrop-blur-xl p-8 transition">
<!-- Header -->
<div class="text-center mb-8">
<div class="inline-flex items-center justify-center w-14 h-14 rounded-2xl bg-emerald-500/10 border border-emerald-500/30 text-emerald-400 mb-3 shadow-lg shadow-emerald-500/10">
<div class="inline-flex items-center justify-center w-14 h-14 rounded-2xl bg-emerald-500/10 border border-emerald-500/30 text-emerald-600 dark:text-emerald-400 mb-3 shadow-lg shadow-emerald-500/10">
<i data-lucide="shield-check" class="w-8 h-8"></i>
</div>
<h1 class="text-3xl font-extrabold tracking-tight text-white">Fociz</h1>
<p class="text-slate-400 text-sm mt-1">
<h1 class="text-3xl font-extrabold tracking-tight text-slate-900 dark:text-white">Fociz</h1>
<p class="text-slate-500 dark:text-slate-400 text-sm mt-1">
Veilig inloggen met tweestapsverificatie (2FA)
</p>
</div>
<?php if ($error): ?>
<div class="mb-6 p-4 rounded-xl bg-red-500/10 border border-red-500/30 flex items-start space-x-3 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>
<span><?= htmlspecialchars($error) ?></span>
</div>
@@ -150,20 +189,20 @@ $pageTitle = "Fociz — Inloggen";
<!-- STAP 1: E-mail & Wachtwoord -->
<form method="POST" action="/auth/login.php" class="space-y-4">
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">E-mailadres</label>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">E-mailadres</label>
<div class="relative">
<input type="email" name="email" required autofocus placeholder="uw.naam@bedrijf.nl" value="<?= htmlspecialchars($_POST['email'] ?? '') ?>" class="w-full bg-slate-800/80 border border-slate-700 rounded-xl px-4 py-2.5 text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-emerald-500/50 text-sm transition">
<input type="email" name="email" required autofocus placeholder="uw.naam@bedrijf.nl" value="<?= htmlspecialchars($_POST['email'] ?? '') ?>" class="w-full bg-slate-50 dark:bg-slate-800/80 border border-slate-300 dark:border-slate-700 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-2 focus:ring-emerald-500/50 text-sm transition">
</div>
</div>
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Wachtwoord</label>
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Wachtwoord</label>
<div class="relative">
<input type="password" name="password" required placeholder="••••••••" class="w-full bg-slate-800/80 border border-slate-700 rounded-xl px-4 py-2.5 text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-emerald-500/50 text-sm transition">
<input type="password" name="password" required placeholder="••••••••" class="w-full bg-slate-50 dark:bg-slate-800/80 border border-slate-300 dark:border-slate-700 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-2 focus:ring-emerald-500/50 text-sm transition">
</div>
</div>
<button type="submit" class="w-full mt-4 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold py-3 px-4 rounded-xl transition shadow-lg shadow-emerald-500/20 flex items-center justify-center space-x-2">
<button type="submit" class="w-full mt-4 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold py-3 px-4 rounded-xl transition shadow-lg shadow-emerald-500/20 flex items-center justify-center space-x-2 cursor-pointer">
<span>Verder naar 2FA</span>
<i data-lucide="arrow-right" class="w-4 h-4"></i>
</button>
@@ -174,29 +213,29 @@ $pageTitle = "Fociz — Inloggen";
<!-- STAP 2: 2FA TOTP Code -->
<form method="POST" action="/auth/login.php" class="space-y-5">
<div class="text-center">
<div class="inline-flex items-center justify-center w-12 h-12 rounded-xl bg-emerald-500/10 text-emerald-400 mb-2">
<div class="inline-flex items-center justify-center w-12 h-12 rounded-2xl bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 mb-2">
<i data-lucide="key" class="w-6 h-6"></i>
</div>
<p className="text-sm text-slate-300 font-medium">
<p class="text-sm text-slate-800 dark:text-slate-300 font-semibold">
Voer uw 6-cijferige verificatiecode in
</p>
<p class="text-xs text-slate-400 mt-1">
Gekoppeld aan <strong class="text-slate-200"><?= htmlspecialchars($_SESSION['pending_2fa_user_email'] ?? '') ?></strong>
<p class="text-xs text-slate-500 dark:text-slate-400 mt-1">
Gekoppeld aan <strong class="text-slate-900 dark:text-slate-200"><?= htmlspecialchars($_SESSION['pending_2fa_user_email'] ?? '') ?></strong>
</p>
</div>
<div>
<input type="text" name="totp_code" required autofocus maxlength="9" placeholder="000 000" class="w-full text-center tracking-[0.4em] font-mono text-2xl bg-slate-800/80 border border-slate-700 rounded-xl py-3 text-white placeholder-slate-600 focus:outline-none focus:ring-2 focus:ring-emerald-500/50 transition">
<span class="text-[11px] text-slate-500 text-center block mt-1">
<input type="text" name="totp_code" required autofocus maxlength="9" placeholder="000 000" class="w-full text-center tracking-[0.4em] font-mono text-2xl bg-slate-50 dark:bg-slate-800/80 border border-slate-300 dark:border-slate-700 rounded-xl py-3 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-600 focus:outline-none focus:ring-2 focus:ring-emerald-500/50 transition">
<span class="text-[11px] text-slate-500 dark:text-slate-500 text-center block mt-1">
Tip: U kunt ook een 8-cijferige herstelcode invoeren.
</span>
</div>
<div class="flex space-x-3">
<a href="/auth/login.php?action=restart" class="w-1/3 text-center bg-slate-800 hover:bg-slate-700 text-slate-300 font-medium py-2.5 px-3 rounded-xl transition text-sm flex items-center justify-center">
<a href="/auth/login.php?action=restart" class="w-1/3 text-center bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 font-medium py-2.5 px-3 rounded-xl transition text-sm flex items-center justify-center cursor-pointer">
Terug
</a>
<button type="submit" class="w-2/3 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold py-2.5 px-4 rounded-xl transition shadow-lg shadow-emerald-500/20 flex items-center justify-center space-x-2">
<button type="submit" class="w-2/3 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold py-2.5 px-4 rounded-xl transition shadow-lg shadow-emerald-500/20 flex items-center justify-center space-x-2 cursor-pointer">
<span>Inloggen</span>
<i data-lucide="check-circle-2" class="w-4 h-4"></i>
</button>
@@ -205,7 +244,7 @@ $pageTitle = "Fociz — Inloggen";
<?php endif; ?>
<div class="mt-8 pt-6 border-t border-slate-800/80 text-center text-xs text-slate-500">
<div class="mt-8 pt-6 border-t border-slate-100 dark:border-slate-800/80 text-center text-xs text-slate-500">
Toegang tot Fociz is strikt op uitnodiging. Vraag uw beheerder om een uitnodigingslink.
</div>
</div>
@@ -215,4 +254,3 @@ $pageTitle = "Fociz — Inloggen";
</script>
</body>
</html>
+32 -33
View File
@@ -40,30 +40,30 @@ $sessions = $stmtSessions->fetchAll();
require_once __DIR__ . '/includes/header.php';
?>
<div class="space-y-6">
<div class="space-y-6 max-w-7xl mx-auto">
<!-- Header -->
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 bg-slate-900/80 border border-slate-800 rounded-2xl p-6 shadow-xl">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl transition">
<div>
<div class="flex items-center space-x-2 text-amber-400 text-xs font-semibold uppercase tracking-wider mb-1">
<div class="flex items-center space-x-2 text-amber-600 dark:text-amber-400 text-xs font-bold uppercase tracking-wider mb-1">
<i data-lucide="lightbulb" class="w-4 h-4"></i>
<span>Creatie & Innovatie</span>
</div>
<h1 class="text-2xl sm:text-3xl font-black text-white tracking-tight">
<h1 class="text-2xl sm:text-3xl font-black text-slate-900 dark:text-white tracking-tight">
Brainstorm Sessies
</h1>
<p class="text-slate-400 text-xs sm:text-sm mt-1">
<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.
</p>
</div>
<button onclick="document.getElementById('newSessionModal').classList.remove('hidden')" class="flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-amber-500 hover:bg-amber-600 text-slate-950 text-xs font-bold transition shadow-lg shadow-amber-500/20 flex-shrink-0">
<button onclick="document.getElementById('newSessionModal').classList.remove('hidden')" class="flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-amber-500 hover:bg-amber-600 text-slate-950 text-xs font-bold transition shadow-lg shadow-amber-500/20 flex-shrink-0 cursor-pointer">
<i data-lucide="plus" class="w-4 h-4"></i>
<span>Nieuwe Sessie Starten</span>
</button>
</div>
<?php if ($error): ?>
<div class="p-4 rounded-xl bg-red-500/10 border border-red-500/30 text-red-400 text-sm">
<div class="p-4 rounded-2xl bg-red-500/10 border border-red-500/30 text-red-700 dark:text-red-400 text-sm">
<?= htmlspecialchars($error) ?>
</div>
<?php endif; ?>
@@ -71,44 +71,44 @@ require_once __DIR__ . '/includes/header.php';
<!-- Grid met sessies -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
<?php if (empty($sessions)): ?>
<div class="col-span-full bg-slate-900/60 border border-slate-800/80 rounded-2xl p-12 text-center">
<div class="col-span-full bg-white dark:bg-slate-900/60 border border-slate-200 dark:border-slate-800/80 rounded-3xl p-12 text-center shadow-sm">
<i data-lucide="lightbulb" class="w-12 h-12 text-amber-500/40 mx-auto mb-3"></i>
<h3 class="text-base font-bold text-white">Nog geen brainstormsessies gestart</h3>
<p class="text-xs text-slate-400 mt-1 max-w-sm mx-auto">
<h3 class="text-base font-bold 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">
Start uw eerste brainstormsessie om ideeën te verzamelen en ze met één klik om te vormen naar planningsitems.
</p>
<button onclick="document.getElementById('newSessionModal').classList.remove('hidden')" class="mt-4 px-4 py-2 bg-amber-500 hover:bg-amber-600 text-slate-950 font-bold rounded-xl text-xs transition">
<button onclick="document.getElementById('newSessionModal').classList.remove('hidden')" class="mt-4 px-4 py-2 bg-amber-500 hover:bg-amber-600 text-slate-950 font-bold rounded-xl text-xs transition cursor-pointer">
Sessie Starten
</button>
</div>
<?php else: ?>
<?php foreach ($sessions as $sess): ?>
<a href="/brainstorm_canvas.php?id=<?= $sess['id'] ?>" class="group bg-slate-900/80 hover:bg-slate-850 border border-slate-800 hover:border-amber-500/40 rounded-2xl p-5 shadow-lg transition flex flex-col justify-between">
<a href="/brainstorm_canvas.php?id=<?= $sess['id'] ?>" class="group bg-white hover:bg-slate-50 dark:bg-slate-900/80 dark:hover:bg-slate-850 border border-slate-200 hover:border-amber-500/50 dark:border-slate-800 dark:hover:border-amber-500/40 rounded-3xl p-5 shadow-sm hover:shadow-md dark:shadow-lg transition flex flex-col justify-between">
<div>
<div class="flex items-center justify-between mb-3">
<span class="px-2.5 py-0.5 rounded-full bg-amber-500/10 border border-amber-500/20 text-amber-400 font-semibold text-[11px]">
<span class="px-2.5 py-0.5 rounded-full bg-amber-500/15 border border-amber-500/30 text-amber-700 dark:text-amber-400 font-bold text-[11px]">
<?= htmlspecialchars($sess['theme']) ?>
</span>
<span class="flex items-center space-x-1 text-slate-500 text-xs">
<span class="flex items-center space-x-1 text-slate-500 dark:text-slate-400 text-xs">
<i data-lucide="message-square" class="w-3.5 h-3.5"></i>
<span><?= $sess['cards_count'] ?> kaarten</span>
</span>
</div>
<h3 class="text-base font-bold text-white group-hover:text-amber-400 transition leading-snug">
<h3 class="text-base font-bold text-slate-900 dark:text-white group-hover:text-amber-600 dark:group-hover:text-amber-400 transition leading-snug">
<?= htmlspecialchars($sess['title']) ?>
</h3>
<?php if (!empty($sess['description'])): ?>
<p class="text-slate-400 text-xs mt-2 line-clamp-2">
<p class="text-slate-600 dark:text-slate-400 text-xs mt-2 line-clamp-2 leading-relaxed">
<?= htmlspecialchars($sess['description']) ?>
</p>
<?php endif; ?>
</div>
<div class="mt-5 pt-4 border-t border-slate-800/80 flex items-center justify-between text-xs text-slate-500">
<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>Door <?= htmlspecialchars($sess['creator_name']) ?></span>
<div class="flex items-center space-x-1 text-amber-400 group-hover:translate-x-1 transition font-medium">
<div class="flex items-center space-x-1 text-amber-600 dark:text-amber-400 group-hover:translate-x-1 transition font-semibold">
<span>Open canvas</span>
<i data-lucide="arrow-right" class="w-3.5 h-3.5"></i>
</div>
@@ -120,14 +120,14 @@ require_once __DIR__ . '/includes/header.php';
</div>
<!-- Modal: Nieuwe sessie -->
<div id="newSessionModal" class="hidden fixed inset-0 z-50 bg-black/70 backdrop-blur-sm flex items-center justify-center p-4">
<div class="bg-slate-900 border border-slate-800 rounded-2xl p-6 shadow-2xl max-w-lg w-full">
<div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-800">
<h3 class="text-base font-bold text-white flex items-center space-x-2">
<i data-lucide="sparkles" class="w-4 h-4 text-amber-400"></i>
<div id="newSessionModal" class="hidden fixed inset-0 z-50 bg-black/60 dark:bg-black/70 backdrop-blur-sm flex items-center justify-center p-4">
<div class="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-2xl max-w-lg w-full transition">
<div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-100 dark:border-slate-800">
<h3 class="text-base font-bold text-slate-900 dark:text-white flex items-center space-x-2">
<i data-lucide="sparkles" class="w-4 h-4 text-amber-500"></i>
<span>Nieuwe Brainstormsessie</span>
</h3>
<button onclick="document.getElementById('newSessionModal').classList.add('hidden')" class="text-slate-400 hover:text-white">
<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-5 h-5"></i>
</button>
</div>
@@ -136,14 +136,14 @@ require_once __DIR__ . '/includes/header.php';
<input type="hidden" name="action" value="create_session">
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Onderwerp / Titel</label>
<input type="text" name="title" required placeholder="Bijv. Q4 Automatisering & Klantreis" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2 text-white text-xs placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-amber-500/50">
<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 dark:bg-slate-950 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-2 focus:ring-amber-500/50">
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Thema / Categorie</label>
<select name="theme" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-2 text-white text-xs focus:outline-none">
<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 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">
<option value="Product & Strategie">Product & Strategie</option>
<option value="Procesverbetering">Procesverbetering</option>
<option value="Klant & Service">Klant & Service</option>
@@ -152,16 +152,16 @@ require_once __DIR__ . '/includes/header.php';
</select>
</div>
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Doel / Beschrijving</label>
<input type="text" name="description" placeholder="Doel van deze sessie..." class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2 text-white text-xs placeholder-slate-500 focus:outline-none">
<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 dark:bg-slate-950 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">
</div>
</div>
<div class="flex space-x-2 pt-2">
<button type="submit" class="flex-1 bg-amber-500 hover:bg-amber-600 text-slate-950 font-bold py-2.5 px-4 rounded-xl text-xs transition">
<button type="submit" class="flex-1 bg-amber-500 hover:bg-amber-600 text-slate-950 font-bold py-2.5 px-4 rounded-xl text-xs transition cursor-pointer">
Sessie Aanmaken & Canvas Openen
</button>
<button type="button" onclick="document.getElementById('newSessionModal').classList.add('hidden')" class="px-4 py-2.5 bg-slate-800 hover:bg-slate-700 text-slate-300 rounded-xl text-xs transition">
<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
</button>
</div>
@@ -170,4 +170,3 @@ require_once __DIR__ . '/includes/header.php';
</div>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
+86 -59
View File
@@ -17,7 +17,7 @@ $stmtSession->execute([$sessionId]);
$session = $stmtSession->fetch();
if (!$session) {
echo "<div class='p-8 text-center text-red-400'>Brainstormsessie niet gevonden. <a href='/brainstorm.php' class='underline'>Terug</a></div>";
echo "<div class='p-8 text-center text-red-500'>Brainstormsessie niet gevonden. <a href='/brainstorm.php' class='underline'>Terug</a></div>";
require_once __DIR__ . '/includes/footer.php';
exit;
}
@@ -32,41 +32,69 @@ $stmtCards->execute([$sessionId]);
$cards = $stmtCards->fetchAll();
$categories = [
'Ideeën' => ['title' => 'Ideeën & Concepten', 'icon' => 'lightbulb', 'color' => 'amber', 'border' => 'border-amber-500/40', 'bg' => 'bg-amber-950/20', 'badge' => 'bg-amber-500/20 text-amber-300'],
'Knelpunten' => ['title' => 'Knelpunten & Uitdagingen', 'icon' => 'alert-triangle', 'color' => 'rose', 'border' => 'border-rose-500/40', 'bg' => 'bg-rose-950/20', 'badge' => 'bg-rose-500/20 text-rose-300'],
'Oplossingen' => ['title' => 'Oplossingen & Features', 'icon' => 'rocket', 'color' => 'emerald', 'border' => 'border-emerald-500/40', 'bg' => 'bg-emerald-950/20', 'badge' => 'bg-emerald-500/20 text-emerald-300'],
'Quick Wins' => ['title' => 'Quick Wins (Direct te doen)', 'icon' => 'zap', 'color' => 'blue', 'border' => 'border-blue-500/40', 'bg' => 'bg-blue-950/20', 'badge' => 'bg-blue-500/20 text-blue-300'],
'Ideeën' => [
'title' => 'Ideeën & Concepten',
'icon' => 'lightbulb',
'color' => 'amber',
'border' => 'border-amber-200 dark:border-amber-500/40',
'bg' => 'bg-amber-50/60 dark:bg-amber-950/20',
'badge' => 'bg-amber-500/15 text-amber-800 dark:text-amber-300'
],
'Knelpunten' => [
'title' => 'Knelpunten & Uitdagingen',
'icon' => 'alert-triangle',
'color' => 'rose',
'border' => 'border-rose-200 dark:border-rose-500/40',
'bg' => 'bg-rose-50/60 dark:bg-rose-950/20',
'badge' => 'bg-rose-500/15 text-rose-800 dark:text-rose-300'
],
'Oplossingen' => [
'title' => 'Oplossingen & Features',
'icon' => 'rocket',
'color' => 'emerald',
'border' => 'border-emerald-200 dark:border-emerald-500/40',
'bg' => 'bg-emerald-50/60 dark:bg-emerald-950/20',
'badge' => 'bg-emerald-500/15 text-emerald-800 dark:text-emerald-300'
],
'Quick Wins' => [
'title' => 'Quick Wins (Direct te doen)',
'icon' => 'zap',
'color' => 'blue',
'border' => 'border-blue-200 dark:border-blue-500/40',
'bg' => 'bg-blue-50/60 dark:bg-blue-950/20',
'badge' => 'bg-blue-500/15 text-blue-800 dark:text-blue-300'
],
];
?>
<div class="space-y-6">
<div class="space-y-6 max-w-7xl mx-auto">
<!-- Top Bar -->
<div class="flex flex-col lg:flex-row lg:items-center justify-between gap-4 bg-slate-900/90 border border-slate-800 rounded-2xl p-5 shadow-xl">
<div class="flex flex-col lg:flex-row lg:items-center justify-between gap-4 bg-white dark:bg-slate-900/90 border border-slate-200 dark:border-slate-800 rounded-3xl p-5 shadow-sm dark:shadow-xl transition">
<div class="flex items-center space-x-4">
<a href="/brainstorm.php" class="p-2 rounded-xl bg-slate-800 text-slate-400 hover:text-white transition">
<a href="/brainstorm.php" class="p-2.5 rounded-2xl 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>
</a>
<div>
<div class="flex items-center space-x-2 text-xs">
<span class="px-2 py-0.5 rounded bg-amber-500/10 text-amber-400 font-semibold border border-amber-500/20">
<span class="px-2 py-0.5 rounded bg-amber-500/15 text-amber-700 dark:text-amber-400 font-bold border border-amber-500/20">
<?= htmlspecialchars($session['theme']) ?>
</span>
<span class="text-slate-500">Gestart door <?= htmlspecialchars($session['creator_name']) ?></span>
<span class="text-slate-500 dark:text-slate-500">Gestart door <?= htmlspecialchars($session['creator_name']) ?></span>
</div>
<h1 class="text-xl sm:text-2xl font-black text-white tracking-tight mt-0.5">
<h1 class="text-xl sm:text-2xl font-black text-slate-900 dark:text-white tracking-tight mt-0.5">
<?= htmlspecialchars($session['title']) ?>
</h1>
</div>
</div>
<div class="flex items-center space-x-3">
<button onclick="openAddCardModal()" class="flex items-center space-x-1.5 px-3.5 py-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-200 text-xs font-semibold border border-slate-700 transition">
<i data-lucide="plus" class="w-4 h-4 text-amber-400"></i>
<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-sm">
<i data-lucide="plus" class="w-4 h-4 text-amber-500"></i>
<span>Nieuwe Kaart</span>
</button>
<!-- De Kernfeature: Zet om naar Roadmap! -->
<button onclick="openConvertModal()" class="flex items-center space-x-2 px-4 py-2 rounded-xl bg-gradient-to-r from-emerald-500 to-teal-400 hover:from-emerald-600 hover:to-teal-500 text-slate-950 text-xs font-bold transition shadow-lg shadow-emerald-500/20">
<button onclick="openConvertModal()" class="flex items-center space-x-2 px-4 py-2 rounded-xl bg-gradient-to-r from-emerald-500 to-teal-400 hover:from-emerald-600 hover:to-teal-500 text-slate-950 text-xs font-bold transition shadow-lg shadow-emerald-500/20 cursor-pointer">
<i data-lucide="map" class="w-4 h-4"></i>
<span>Zet om naar Roadmap</span>
</button>
@@ -78,14 +106,14 @@ $categories = [
<?php foreach ($categories as $catKey => $catConfig):
$catCards = array_filter($cards, fn($c) => $c['category'] === $catKey);
?>
<div class="bg-slate-900/60 border border-slate-800/80 rounded-2xl p-4 flex flex-col min-h-[500px]">
<div class="bg-white dark:bg-slate-900/60 border border-slate-200 dark:border-slate-800/80 rounded-3xl p-4 flex flex-col min-h-[500px] shadow-sm transition">
<!-- Column Header -->
<div class="flex items-center justify-between pb-3 mb-3 border-b 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">
<i data-lucide="<?= $catConfig['icon'] ?>" class="w-4 h-4 text-<?= $catConfig['color'] ?>-400"></i>
<h3 class="text-xs font-bold text-white uppercase tracking-wider"><?= $catConfig['title'] ?></h3>
<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>
</div>
<span class="text-xs font-mono font-semibold px-2 py-0.5 rounded-full bg-slate-800 text-slate-400">
<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">
<?= count($catCards) ?>
</span>
</div>
@@ -93,22 +121,22 @@ $categories = [
<!-- Cards Container -->
<div class="flex-1 space-y-3">
<?php if (empty($catCards)): ?>
<div class="py-8 text-center text-slate-600 text-xs">
<div class="py-8 text-center text-slate-400 dark:text-slate-600 text-xs">
Nog geen kaarten in deze categorie.
</div>
<?php else: ?>
<?php foreach ($catCards as $card): ?>
<div class="group relative rounded-xl p-4 border <?= $catConfig['border'] ?> <?= $catConfig['bg'] ?> backdrop-blur-sm shadow-md transition hover:-translate-y-0.5" id="card-<?= $card['id'] ?>">
<div class="group relative rounded-2xl p-4 border <?= $catConfig['border'] ?> <?= $catConfig['bg'] ?> backdrop-blur-sm shadow-sm transition hover:-translate-y-0.5" id="card-<?= $card['id'] ?>">
<!-- Top: Checkbox voor selectie + Roadmap badge -->
<div class="flex items-center justify-between mb-2">
<label class="flex items-center space-x-2 cursor-pointer">
<input type="checkbox" value="<?= $card['id'] ?>" class="card-checkbox w-4 h-4 rounded bg-slate-900 border-slate-700 text-emerald-500 focus:ring-0">
<span class="text-[10px] text-slate-400">Selecteer</span>
<input type="checkbox" value="<?= $card['id'] ?>" class="card-checkbox w-4 h-4 rounded bg-white dark:bg-slate-900 border-slate-300 dark:border-slate-700 text-emerald-600 focus:ring-0">
<span class="text-[10px] text-slate-500 dark:text-slate-400">Selecteer</span>
</label>
<?php if (!empty($card['converted_to_roadmap_item_id'])): ?>
<span class="px-2 py-0.5 rounded-full bg-emerald-500/20 text-emerald-300 font-semibold text-[10px] flex items-center space-x-1 border border-emerald-500/30">
<span class="px-2 py-0.5 rounded-full bg-emerald-500/20 text-emerald-800 dark:text-emerald-300 font-bold text-[10px] flex items-center space-x-1 border border-emerald-500/30">
<i data-lucide="check" class="w-3 h-3"></i>
<span>Op Roadmap</span>
</span>
@@ -116,23 +144,23 @@ $categories = [
</div>
<!-- Inhoud -->
<p class="text-xs text-slate-200 leading-relaxed whitespace-pre-wrap">
<p class="text-xs text-slate-800 dark:text-slate-200 leading-relaxed whitespace-pre-wrap font-medium">
<?= htmlspecialchars($card['content']) ?>
</p>
<!-- Footer van kaart -->
<div class="mt-3 pt-2.5 border-t border-slate-800/60 flex items-center justify-between text-[10px] text-slate-400">
<div class="mt-3 pt-2.5 border-t border-slate-200/60 dark:border-slate-800/60 flex items-center justify-between text-[10px] text-slate-500 dark:text-slate-400">
<span><?= htmlspecialchars($card['author_name'] ?? 'Collega') ?></span>
<div class="flex items-center space-x-2">
<!-- Upvote button -->
<button onclick="voteCard(<?= $card['id'] ?>)" class="flex items-center space-x-1 px-2 py-1 rounded-lg bg-slate-800/80 hover:bg-slate-700 text-amber-300 transition">
<button onclick="voteCard(<?= $card['id'] ?>)" class="flex items-center space-x-1 px-2 py-1 rounded-lg bg-white hover:bg-slate-100 dark:bg-slate-800/80 dark:hover:bg-slate-700 text-amber-600 dark:text-amber-300 border border-slate-200 dark:border-transparent transition shadow-xs cursor-pointer">
<i data-lucide="thumbs-up" class="w-3 h-3"></i>
<span id="votes-<?= $card['id'] ?>" class="font-bold"><?= $card['votes'] ?></span>
</button>
<!-- Delete button -->
<button onclick="deleteCard(<?= $card['id'] ?>)" class="p-1 rounded text-slate-500 hover:text-red-400 transition opacity-0 group-hover:opacity-100">
<button onclick="deleteCard(<?= $card['id'] ?>)" class="p-1 rounded text-slate-400 hover:text-red-600 dark:text-slate-500 dark:hover:text-red-400 transition opacity-0 group-hover:opacity-100 cursor-pointer">
<i data-lucide="trash-2" class="w-3.5 h-3.5"></i>
</button>
</div>
@@ -143,7 +171,7 @@ $categories = [
</div>
<!-- Quick add button at column bottom -->
<button onclick="openAddCardModal('<?= $catKey ?>')" class="mt-3 w-full py-2 rounded-xl border border-dashed border-slate-800 hover:border-slate-700 text-slate-500 hover:text-slate-300 text-xs transition flex items-center justify-center space-x-1">
<button onclick="openAddCardModal('<?= $catKey ?>')" class="mt-3 w-full py-2 rounded-xl border border-dashed border-slate-300 dark:border-slate-800 hover:border-slate-400 dark:hover:border-slate-700 text-slate-500 hover:text-slate-800 dark:hover:text-slate-300 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>
<span>Kaart toevoegen</span>
</button>
@@ -153,22 +181,22 @@ $categories = [
</div>
<!-- Modal: Nieuwe Kaart Toevoegen -->
<div id="addCardModal" class="hidden fixed inset-0 z-50 bg-black/70 backdrop-blur-sm flex items-center justify-center p-4">
<div class="bg-slate-900 border border-slate-800 rounded-2xl p-6 shadow-2xl max-w-md w-full">
<div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-800">
<h3 class="text-base font-bold text-white flex items-center space-x-2">
<i data-lucide="sticky-note" class="w-4 h-4 text-amber-400"></i>
<div id="addCardModal" class="hidden fixed inset-0 z-50 bg-black/60 dark:bg-black/70 backdrop-blur-sm flex items-center justify-center p-4">
<div class="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 shadow-2xl max-w-md w-full transition">
<div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-100 dark:border-slate-800">
<h3 class="text-base font-bold text-slate-900 dark:text-white flex items-center space-x-2">
<i data-lucide="sticky-note" class="w-4 h-4 text-amber-500"></i>
<span>Brainstormkaart Toevoegen</span>
</h3>
<button onclick="closeAddCardModal()" class="text-slate-400 hover:text-white">
<button onclick="closeAddCardModal()" class="text-slate-400 hover:text-slate-600 dark:hover:text-white cursor-pointer">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<div class="space-y-4">
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Categorie</label>
<select id="modalCardCategory" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-2 text-white text-xs focus:outline-none">
<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 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">
<option value="Ideeën">💡 Ideeën & Concepten</option>
<option value="Knelpunten">⚠️ Knelpunten & Uitdagingen</option>
<option value="Oplossingen">🚀 Oplossingen & Features</option>
@@ -177,15 +205,15 @@ $categories = [
</div>
<div>
<label class="block text-xs font-medium 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-950 border border-slate-800 rounded-xl p-3 text-white text-xs placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-amber-500 resize-none"></textarea>
<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 dark:bg-slate-950 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-amber-500 resize-none"></textarea>
</div>
<div class="flex space-x-2 pt-2">
<button onclick="submitNewCard()" class="flex-1 bg-amber-500 hover:bg-amber-600 text-slate-950 font-bold py-2.5 px-4 rounded-xl text-xs transition">
<button onclick="submitNewCard()" class="flex-1 bg-amber-500 hover:bg-amber-600 text-slate-950 font-bold py-2.5 px-4 rounded-xl text-xs transition cursor-pointer">
Plaats op Canvas
</button>
<button onclick="closeAddCardModal()" class="px-4 py-2.5 bg-slate-800 hover:bg-slate-700 text-slate-300 rounded-xl text-xs transition">
<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
</button>
</div>
@@ -194,27 +222,27 @@ $categories = [
</div>
<!-- Modal: Zet om naar Roadmap -->
<div id="convertModal" class="hidden fixed inset-0 z-50 bg-black/70 backdrop-blur-sm flex items-center justify-center p-4">
<div class="bg-slate-900 border border-emerald-500/40 rounded-2xl p-6 shadow-2xl max-w-lg w-full">
<div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-800">
<h3 class="text-base font-bold text-white flex items-center space-x-2">
<i data-lucide="map" class="w-4 h-4 text-emerald-400"></i>
<div id="convertModal" class="hidden fixed inset-0 z-50 bg-black/60 dark:bg-black/70 backdrop-blur-sm flex items-center justify-center p-4">
<div class="bg-white dark:bg-slate-900 border border-emerald-500/40 rounded-3xl p-6 shadow-2xl max-w-lg w-full transition">
<div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-100 dark:border-slate-800">
<h3 class="text-base font-bold text-slate-900 dark:text-white flex items-center space-x-2">
<i data-lucide="map" class="w-4 h-4 text-emerald-600 dark:text-emerald-400"></i>
<span>Zet Brainstorm om naar Roadmap</span>
</h3>
<button onclick="closeConvertModal()" class="text-slate-400 hover:text-white">
<button onclick="closeConvertModal()" class="text-slate-400 hover:text-slate-600 dark:hover:text-white cursor-pointer">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<div class="space-y-4">
<div class="bg-emerald-950/30 border border-emerald-500/20 rounded-xl p-3 text-xs text-emerald-300">
<div class="bg-emerald-50 dark:bg-emerald-950/30 border border-emerald-200 dark:border-emerald-500/20 rounded-2xl p-3 text-xs text-emerald-800 dark:text-emerald-300">
<span id="selectedCountText" class="font-bold">0</span> kaarten geselecteerd om om te zetten naar planbare roadmap items.
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Doel Kwartaal</label>
<select id="roadmapQuarter" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-2 text-white text-xs focus:outline-none">
<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 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">
<option value="Q1">Q1 (Jan - Mrt)</option>
<option value="Q2">Q2 (Apr - Jun)</option>
<option value="Q3" selected>Q3 (Jul - Sep)</option>
@@ -223,8 +251,8 @@ $categories = [
</div>
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Item Type</label>
<select id="roadmapType" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-2 text-white text-xs focus:outline-none">
<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 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">
<option value="FEATURE" selected>Feature / Functionaliteit</option>
<option value="EPIC">Epic (Groot project)</option>
<option value="MILESTONE">Mijlpaal</option>
@@ -235,8 +263,8 @@ $categories = [
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Prioriteit</label>
<select id="roadmapPriority" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-2 text-white text-xs focus:outline-none">
<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 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">
<option value="HIGH" selected>Hoog (Belangrijke milestone)</option>
<option value="CRITICAL">Kritiek (Must-have)</option>
<option value="MEDIUM">Normaal</option>
@@ -245,17 +273,17 @@ $categories = [
</div>
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Streefdatum (Deadline)</label>
<input type="date" id="roadmapDueDate" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-1.5 text-white text-xs focus:outline-none">
<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 dark:bg-slate-950 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">
</div>
</div>
<div class="flex space-x-2 pt-2">
<button onclick="submitConvertToRoadmap()" class="flex-1 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold py-2.5 px-4 rounded-xl text-xs transition shadow-lg shadow-emerald-500/20 flex items-center justify-center space-x-2">
<button onclick="submitConvertToRoadmap()" class="flex-1 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold py-2.5 px-4 rounded-xl text-xs transition shadow-lg shadow-emerald-500/20 flex items-center justify-center space-x-2 cursor-pointer">
<i data-lucide="check-circle" class="w-4 h-4"></i>
<span>Definitief Toevoegen aan Roadmap</span>
</button>
<button onclick="closeConvertModal()" class="px-4 py-2.5 bg-slate-800 hover:bg-slate-700 text-slate-300 rounded-xl text-xs transition">
<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
</button>
</div>
@@ -368,4 +396,3 @@ async function submitConvertToRoadmap() {
</script>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
+57
View File
@@ -98,6 +98,24 @@ function ensure_notification_columns(PDO $db): void {
}
}
/**
* Garandeert dat de kolom voor weergavethema (dark, light, system) aanwezig is in MariaDB
*/
function ensure_theme_column(PDO $db): void {
static $themeChecked = false;
if ($themeChecked) return;
$themeChecked = true;
try {
$result = $db->query("SHOW COLUMNS FROM `users` LIKE 'theme'");
if (!$result || $result->rowCount() === 0) {
$db->exec("ALTER TABLE `users` ADD COLUMN `theme` VARCHAR(20) NOT NULL DEFAULT 'dark' AFTER `notification_settings`");
}
} catch (Throwable $e) {
// Stil negeren indien al aanwezig
}
}
/**
* Genereert en bewaart een persistente 'Onthoud mij' token in MariaDB en plaatst een veilige cookie
*/
@@ -399,4 +417,43 @@ function update_user_notification_settings(int $userId, array $settings): bool {
}
}
/**
* Haalt het voorkeursthema op voor een gebruiker ('dark', 'light' of 'system')
*/
function get_user_theme(int $userId): string {
$db = get_db_connection();
ensure_theme_column($db);
try {
$stmt = $db->prepare("SELECT theme FROM users WHERE id = ?");
$stmt->execute([$userId]);
$theme = $stmt->fetchColumn();
if ($theme && in_array($theme, ['dark', 'light', 'system'])) {
return $theme;
}
} catch (Throwable $e) {
error_log("get_user_theme error: " . $e->getMessage());
}
return 'dark';
}
/**
* Slaat het voorkeursthema van een gebruiker op ('dark', 'light' of 'system')
*/
function update_user_theme(int $userId, string $theme): bool {
$db = get_db_connection();
ensure_theme_column($db);
$theme = in_array($theme, ['dark', 'light', 'system']) ? $theme : 'dark';
try {
$stmt = $db->prepare("UPDATE users SET theme = ? WHERE id = ?");
return $stmt->execute([$theme, $userId]);
} catch (Throwable $e) {
error_log("update_user_theme error: " . $e->getMessage());
return false;
}
}
+4 -5
View File
@@ -1,14 +1,14 @@
</main>
<footer class="border-t border-slate-800/80 py-6 text-center text-xs text-slate-500">
<footer class="border-t border-slate-200 dark:border-slate-800/80 bg-white/50 dark:bg-transparent backdrop-blur-sm py-6 text-center text-xs text-slate-500 transition">
<div class="max-w-7xl mx-auto px-4 flex flex-col sm:flex-row items-center justify-between gap-2">
<div class="flex items-center space-x-2">
<span class="font-bold text-slate-400">Fociz</span>
<span class="font-bold text-slate-700 dark:text-slate-400">Fociz</span>
<span>&bull;</span>
<span>Focus & Structuur Systeem</span>
<span class="text-slate-600 dark:text-slate-500">Focus & Structuur Systeem</span>
</div>
<div>
<span>Beveiligd met MariaDB & Tweestapsverificatie (2FA)</span>
<span class="text-slate-500 dark:text-slate-500">Beveiligd met MariaDB & Tweestapsverificatie (2FA)</span>
</div>
</div>
</footer>
@@ -24,4 +24,3 @@
</script>
</body>
</html>
+156 -71
View File
@@ -1,11 +1,12 @@
<?php
/**
* Header & Navigatiebalk voor Fociz
* Header & Navigatiebalk voor Fociz (Dual-Mode: Dark & Light, Executive Styling)
*/
require_once __DIR__ . '/auth.php';
$currentUser = $currentUser ?? require_auth();
$currentPage = basename($_SERVER['PHP_SELF']);
$currentUserTheme = !empty($currentUser['id']) ? get_user_theme((int)$currentUser['id']) : 'dark';
?>
<!DOCTYPE html>
<html lang="nl" class="dark">
@@ -13,6 +14,26 @@ $currentPage = basename($_SERVER['PHP_SELF']);
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= htmlspecialchars($pageTitle ?? 'Fociz — Focus, Dagplanning & Roadmap') ?></title>
<!-- Anti-Flicker Theme Script: direct in head zodat er nooit een flits optreedt -->
<script>
(function() {
try {
const serverTheme = <?= json_encode($currentUserTheme ?? 'dark') ?>;
const savedTheme = localStorage.getItem('fociz_theme') || serverTheme || 'dark';
let effective = savedTheme;
if (savedTheme === 'system') {
effective = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
if (effective === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
} catch(e) {}
})();
</script>
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<script>
@@ -23,6 +44,8 @@ $currentPage = basename($_SERVER['PHP_SELF']);
colors: {
brand: {
50: '#f0fdf4',
100: '#dcfce7',
200: '#bbf7d0',
500: '#10b981',
600: '#059669',
700: '#047857',
@@ -35,17 +58,27 @@ $currentPage = basename($_SERVER['PHP_SELF']);
<!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
<style>
body {
html.dark body {
background-color: #090d16;
color: #f1f5f9;
}
html:not(.dark) body {
background-color: #f8fafc;
color: #0f172a;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
}
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: #0f172a; }
::-webkit-scrollbar-thumb { background: #334155; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: #475569; }
::-webkit-scrollbar { width: 7px; height: 7px; }
html.dark ::-webkit-scrollbar-track { background: #0b1120; }
html.dark ::-webkit-scrollbar-thumb { background: #223049; border-radius: 4px; }
html.dark ::-webkit-scrollbar-thumb:hover { background: #334668; }
html:not(.dark) ::-webkit-scrollbar-track { background: #f1f5f9; }
html:not(.dark) ::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }
html:not(.dark) ::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
</style>
<body class="min-h-screen flex flex-col antialiased selection:bg-emerald-500 selection:text-white">
</head>
<body class="min-h-screen flex flex-col antialiased selection:bg-emerald-500 selection:text-white transition-colors duration-150">
<?php
// Include flashy omgevingsindicator (Dev = Rood, Live = Groen)
@@ -53,104 +86,115 @@ require_once __DIR__ . '/env_badge.php';
?>
<?php if ($currentUser): ?>
<header class="sticky top-0 z-40 bg-[#0c121e]/90 backdrop-blur-md border-b border-slate-800/80">
<header class="sticky top-0 z-40 bg-white/85 dark:bg-[#0c121e]/90 backdrop-blur-md border-b border-slate-200/80 dark:border-slate-800/80 shadow-sm dark:shadow-none transition-colors duration-150">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-16">
<!-- Brand Logo (met linker padding zodat het badge vrij staat) -->
<!-- Brand Logo (met linker padding zodat het dev/live badge vrij staat) -->
<div class="flex items-center space-x-6 pl-28 sm:pl-36">
<a href="/planner.php" class="flex items-center space-x-2.5 group">
<div class="w-9 h-9 rounded-xl bg-gradient-to-tr from-emerald-600 to-teal-400 flex items-center justify-center text-slate-950 font-black text-lg shadow-md shadow-emerald-500/20 group-hover:scale-105 transition">
F
</div>
<div class="flex flex-col">
<span class="text-xl font-bold tracking-tight text-white leading-none">Fociz</span>
<span class="text-[10px] text-emerald-400 tracking-wider font-semibold uppercase">Focus & Structuur</span>
<span class="text-xl font-bold tracking-tight text-slate-900 dark:text-white leading-none">Fociz</span>
<span class="text-[10px] text-emerald-600 dark:text-emerald-400 tracking-wider font-semibold uppercase">Focus & Structuur</span>
</div>
</a>
<!-- Nav Tabs -->
<nav class="hidden md:flex items-center space-x-1">
<a href="/planner.php" class="flex items-center space-x-2 px-3.5 py-2 rounded-lg text-sm font-medium transition <?= $currentPage === 'planner.php' ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/60' ?>">
<a href="/planner.php" class="flex items-center space-x-2 px-3 py-1.5 rounded-xl text-xs font-semibold transition <?= $currentPage === 'planner.php' ? 'bg-emerald-50 text-emerald-700 border border-emerald-200 shadow-sm dark:bg-emerald-500/10 dark:text-emerald-400 dark:border-emerald-500/20' : 'text-slate-600 hover:text-slate-900 hover:bg-slate-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/60' ?>">
<i data-lucide="calendar" class="w-4 h-4"></i>
<span>Dagplanning</span>
</a>
<a href="/brainstorm.php" class="flex items-center space-x-2 px-3.5 py-2 rounded-lg text-sm font-medium transition <?= in_array($currentPage, ['brainstorm.php', 'brainstorm_canvas.php']) ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/60' ?>">
<a href="/brainstorm.php" class="flex items-center space-x-2 px-3 py-1.5 rounded-xl text-xs font-semibold transition <?= in_array($currentPage, ['brainstorm.php', 'brainstorm_canvas.php']) ? 'bg-emerald-50 text-emerald-700 border border-emerald-200 shadow-sm dark:bg-emerald-500/10 dark:text-emerald-400 dark:border-emerald-500/20' : 'text-slate-600 hover:text-slate-900 hover:bg-slate-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/60' ?>">
<i data-lucide="lightbulb" class="w-4 h-4"></i>
<span>Brainstorm</span>
</a>
<a href="/roadmap.php" class="flex items-center space-x-2 px-3.5 py-2 rounded-lg text-sm font-medium transition <?= $currentPage === 'roadmap.php' ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/60' ?>">
<a href="/roadmap.php" class="flex items-center space-x-2 px-3 py-1.5 rounded-xl text-xs font-semibold transition <?= $currentPage === 'roadmap.php' ? 'bg-emerald-50 text-emerald-700 border border-emerald-200 shadow-sm dark:bg-emerald-500/10 dark:text-emerald-400 dark:border-emerald-500/20' : 'text-slate-600 hover:text-slate-900 hover:bg-slate-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/60' ?>">
<i data-lucide="map" class="w-4 h-4"></i>
<span>Roadmap</span>
</a>
<a href="/profile.php" class="flex items-center space-x-2 px-3.5 py-2 rounded-lg text-sm font-medium transition <?= $currentPage === 'profile.php' ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/60' ?>">
<a href="/profile.php" class="flex items-center space-x-2 px-3 py-1.5 rounded-xl text-xs font-semibold transition <?= $currentPage === 'profile.php' ? 'bg-emerald-50 text-emerald-700 border border-emerald-200 shadow-sm dark:bg-emerald-500/10 dark:text-emerald-400 dark:border-emerald-500/20' : 'text-slate-600 hover:text-slate-900 hover:bg-slate-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/60' ?>">
<i data-lucide="user" class="w-4 h-4"></i>
<span>Mijn Profiel</span>
</a>
<?php if ($currentUser['role'] === 'ADMIN'): ?>
<a href="/users.php" class="flex items-center space-x-2 px-3.5 py-2 rounded-lg text-sm font-medium transition <?= $currentPage === 'users.php' ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/60' ?>">
<a href="/users.php" class="flex items-center space-x-2 px-3 py-1.5 rounded-xl text-xs font-semibold transition <?= $currentPage === 'users.php' ? 'bg-emerald-50 text-emerald-700 border border-emerald-200 shadow-sm dark:bg-emerald-500/10 dark:text-emerald-400 dark:border-emerald-500/20' : 'text-slate-600 hover:text-slate-900 hover:bg-slate-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/60' ?>">
<i data-lucide="users" class="w-4 h-4"></i>
<span>Team</span>
</a>
<a href="/admin.php" class="flex items-center space-x-2 px-3.5 py-2 rounded-lg text-sm font-medium transition <?= $currentPage === 'admin.php' ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800/60' ?>">
<i data-lucide="shield-check" class="w-4 h-4 text-emerald-400"></i>
<a href="/admin.php" class="flex items-center space-x-2 px-3 py-1.5 rounded-xl text-xs font-semibold transition <?= $currentPage === 'admin.php' ? 'bg-emerald-50 text-emerald-700 border border-emerald-200 shadow-sm dark:bg-emerald-500/10 dark:text-emerald-400 dark:border-emerald-500/20' : 'text-slate-600 hover:text-slate-900 hover:bg-slate-100 dark:text-slate-400 dark:hover:text-slate-200 dark:hover:bg-slate-800/60' ?>">
<i data-lucide="shield-check" class="w-4 h-4 text-emerald-600 dark:text-emerald-400"></i>
<span>Beheer</span>
</a>
<?php endif; ?>
</nav>
</div>
<!-- Right side: User, Notifications & 2FA Status -->
<div class="flex items-center space-x-2.5">
<button type="button" onclick="openNotificationModal()" class="relative p-2 rounded-lg text-slate-400 hover:text-white hover:bg-slate-800 transition" title="Meldingen & Agenda Herinneringen">
<!-- Right side: Theme Toggle, Notifications, 2FA Status & User -->
<div class="flex items-center space-x-2 sm:space-x-2.5">
<!-- 1-Click Snelle Thema Wisselaar (Zon / Maan) -->
<button type="button" onclick="focizQuickToggleTheme()" class="p-2 rounded-xl text-slate-500 hover:text-slate-900 hover:bg-slate-100 dark:text-slate-400 dark:hover:text-white dark:hover:bg-slate-800 transition" title="Thema wisselen (Donker / Licht)">
<i data-lucide="sun" class="w-4 h-4 hidden dark:block text-amber-400"></i>
<i data-lucide="moon" class="w-4 h-4 block dark:hidden text-slate-700"></i>
</button>
<!-- Notificatiebel -->
<button type="button" onclick="openNotificationModal()" class="relative p-2 rounded-xl text-slate-500 hover:text-slate-900 hover:bg-slate-100 dark:text-slate-400 dark:hover:text-white dark:hover:bg-slate-800 transition" title="Meldingen & Agenda Herinneringen">
<i data-lucide="bell" class="w-4 h-4"></i>
<span id="focizNotificationDot" class="hidden absolute top-1.5 right-1.5 w-2 h-2 rounded-full bg-blue-500 animate-pulse"></span>
</button>
<div class="hidden sm:flex items-center space-x-1.5 px-2.5 py-1 rounded-full bg-emerald-500/10 border border-emerald-500/25 text-emerald-400 text-xs font-medium">
<!-- 2FA Badge -->
<div class="hidden sm:flex items-center space-x-1.5 px-2.5 py-1 rounded-full bg-emerald-50 dark:bg-emerald-500/10 border border-emerald-200 dark:border-emerald-500/25 text-emerald-700 dark:text-emerald-400 text-xs font-semibold">
<i data-lucide="shield-check" class="w-3.5 h-3.5"></i>
<span>2FA Actief</span>
</div>
<a href="/profile.php" class="text-right hidden sm:block group hover:opacity-90 transition" title="Mijn Profiel & Instellingen">
<div class="text-xs font-semibold text-slate-200 group-hover:text-emerald-400 transition flex items-center justify-end space-x-1">
<!-- Profiel link rechtsboven -->
<a href="/profile.php" class="text-right hidden sm:block group hover:opacity-90 transition pl-1" title="Mijn Profiel & Instellingen">
<div class="text-xs font-semibold text-slate-800 dark:text-slate-200 group-hover:text-emerald-600 dark:group-hover:text-emerald-400 transition flex items-center justify-end space-x-1">
<span><?= htmlspecialchars($currentUser['name']) ?></span>
<i data-lucide="chevron-right" class="w-3 h-3 text-slate-500 group-hover:text-emerald-400 transition"></i>
<i data-lucide="chevron-right" class="w-3 h-3 text-slate-400 dark:text-slate-500 group-hover:text-emerald-600 dark:group-hover:text-emerald-400 transition"></i>
</div>
<div class="text-[10px] text-slate-500">
<div class="text-[10px] text-slate-500 dark:text-slate-400">
<?= $currentUser['role'] === 'ADMIN' ? 'Beheerder' : 'Collega' ?> • <?= htmlspecialchars($currentUser['email']) ?>
</div>
</a>
<a href="/auth/logout.php" title="Veilig uitloggen" class="p-2 rounded-lg text-slate-400 hover:text-red-400 hover:bg-red-500/10 border border-transparent hover:border-red-500/20 transition">
<!-- Uitloggen -->
<a href="/auth/logout.php" title="Veilig uitloggen" class="p-2 rounded-xl text-slate-500 hover:text-red-600 hover:bg-red-50 dark:text-slate-400 dark:hover:text-red-400 dark:hover:bg-red-500/10 transition">
<i data-lucide="log-out" class="w-4 h-4"></i>
</a>
</div>
</div>
<!-- Mobile Navigation -->
<div class="flex md:hidden items-center justify-around py-2 border-t border-slate-800/60 text-xs">
<a href="/planner.php" class="flex flex-col items-center py-1 <?= $currentPage === 'planner.php' ? 'text-emerald-400 font-bold' : 'text-slate-400' ?>">
<div class="flex md:hidden items-center justify-around py-2 border-t border-slate-200/80 dark:border-slate-800/60 text-xs">
<a href="/planner.php" class="flex flex-col items-center py-1 <?= $currentPage === 'planner.php' ? 'text-emerald-600 dark:text-emerald-400 font-bold' : 'text-slate-500 dark:text-slate-400' ?>">
<i data-lucide="calendar" class="w-4 h-4 mb-0.5"></i>
<span>Planning</span>
</a>
<a href="/brainstorm.php" class="flex flex-col items-center py-1 <?= in_array($currentPage, ['brainstorm.php', 'brainstorm_canvas.php']) ? 'text-emerald-400 font-bold' : 'text-slate-400' ?>">
<a href="/brainstorm.php" class="flex flex-col items-center py-1 <?= in_array($currentPage, ['brainstorm.php', 'brainstorm_canvas.php']) ? 'text-emerald-600 dark:text-emerald-400 font-bold' : 'text-slate-500 dark:text-slate-400' ?>">
<i data-lucide="lightbulb" class="w-4 h-4 mb-0.5"></i>
<span>Brainstorm</span>
</a>
<a href="/roadmap.php" class="flex flex-col items-center py-1 <?= $currentPage === 'roadmap.php' ? 'text-emerald-400 font-bold' : 'text-slate-400' ?>">
<a href="/roadmap.php" class="flex flex-col items-center py-1 <?= $currentPage === 'roadmap.php' ? 'text-emerald-600 dark:text-emerald-400 font-bold' : 'text-slate-500 dark:text-slate-400' ?>">
<i data-lucide="map" class="w-4 h-4 mb-0.5"></i>
<span>Roadmap</span>
</a>
<a href="/profile.php" class="flex flex-col items-center py-1 <?= $currentPage === 'profile.php' ? 'text-emerald-400 font-bold' : 'text-slate-400' ?>">
<a href="/profile.php" class="flex flex-col items-center py-1 <?= $currentPage === 'profile.php' ? 'text-emerald-600 dark:text-emerald-400 font-bold' : 'text-slate-500 dark:text-slate-400' ?>">
<i data-lucide="user" class="w-4 h-4 mb-0.5"></i>
<span>Profiel</span>
</a>
<button type="button" onclick="openNotificationModal()" class="flex flex-col items-center py-1 text-slate-400 hover:text-white">
<i data-lucide="bell" class="w-4 h-4 mb-0.5"></i>
<span>Meldingen</span>
<button type="button" onclick="focizQuickToggleTheme()" class="flex flex-col items-center py-1 text-slate-500 dark:text-slate-400">
<i data-lucide="sun" class="w-4 h-4 mb-0.5 hidden dark:block text-amber-400"></i>
<i data-lucide="moon" class="w-4 h-4 mb-0.5 block dark:hidden"></i>
<span>Thema</span>
</button>
<?php if ($currentUser['role'] === 'ADMIN'): ?>
<a href="/admin.php" class="flex flex-col items-center py-1 <?= $currentPage === 'admin.php' ? 'text-emerald-400 font-bold' : 'text-slate-400' ?>">
<a href="/admin.php" class="flex flex-col items-center py-1 <?= $currentPage === 'admin.php' ? 'text-emerald-600 dark:text-emerald-400 font-bold' : 'text-slate-500 dark:text-slate-400' ?>">
<i data-lucide="shield" class="w-4 h-4 mb-0.5"></i>
<span>Beheer</span>
</a>
@@ -159,21 +203,21 @@ require_once __DIR__ . '/env_badge.php';
</div>
</header>
<!-- Fociz Agenda Notificaties Modal -->
<div id="focizNotificationModal" class="hidden fixed inset-0 z-50 bg-black/80 backdrop-blur-sm items-center justify-center p-4">
<div class="bg-slate-900 border border-slate-800 rounded-2xl w-full max-w-md overflow-hidden shadow-2xl animate-in fade-in zoom-in-95 duration-200">
<!-- Fociz Agenda Notificaties Modal (Dual-Mode) -->
<div id="focizNotificationModal" class="hidden fixed inset-0 z-50 bg-black/60 dark:bg-black/80 backdrop-blur-sm items-center justify-center p-4">
<div class="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl w-full max-w-md overflow-hidden shadow-2xl animate-in fade-in zoom-in-95 duration-200">
<!-- Modal Header -->
<div class="p-5 border-b border-slate-800/80 flex items-center justify-between">
<div class="p-5 border-b border-slate-100 dark:border-slate-800/80 flex items-center justify-between">
<div class="flex items-center space-x-2.5">
<div class="w-9 h-9 rounded-xl bg-blue-500/10 border border-blue-500/30 text-blue-400 flex items-center justify-center font-bold">
<div class="w-9 h-9 rounded-xl bg-blue-50 dark:bg-blue-500/10 border border-blue-200 dark:border-blue-500/30 text-blue-600 dark:text-blue-400 flex items-center justify-center font-bold">
<i data-lucide="bell-ring" class="w-4 h-4"></i>
</div>
<div>
<h3 class="text-sm font-bold text-white">Agenda Push Meldingen</h3>
<p class="text-[11px] text-slate-400">Persoonlijke waarschuwingen bij actuele afspraken</p>
<h3 class="text-sm font-bold text-slate-900 dark:text-white">Agenda Push Meldingen</h3>
<p class="text-[11px] text-slate-500 dark:text-slate-400">Persoonlijke waarschuwingen bij actuele afspraken</p>
</div>
</div>
<button type="button" onclick="closeNotificationModal()" class="text-slate-500 hover:text-white p-1 rounded-lg transition">
<button type="button" onclick="closeNotificationModal()" class="text-slate-400 hover:text-slate-700 dark:hover:text-white p-1 rounded-lg transition">
<i data-lucide="x" class="w-4 h-4"></i>
</button>
</div>
@@ -181,19 +225,19 @@ require_once __DIR__ . '/env_badge.php';
<!-- Inhoud Formulier -->
<form onsubmit="saveNotificationPreferences(event)" class="p-5 space-y-4 text-xs">
<!-- Browser Permissie Banner -->
<div id="notifPermGranted" class="hidden p-3 rounded-xl bg-emerald-500/10 border border-emerald-500/30 text-emerald-300 flex items-center justify-between">
<div id="notifPermGranted" class="hidden p-3 rounded-xl bg-emerald-50 dark:bg-emerald-500/10 border border-emerald-200 dark:border-emerald-500/30 text-emerald-800 dark:text-emerald-300 flex items-center justify-between">
<div class="flex items-center space-x-2">
<i data-lucide="check-circle" class="w-4 h-4 text-emerald-400 flex-shrink-0"></i>
<i data-lucide="check-circle" class="w-4 h-4 text-emerald-600 dark:text-emerald-400 flex-shrink-0"></i>
<span class="text-[11px]">Browser pushberichten zijn actief</span>
</div>
<button type="button" onclick="focizTestNotification()" class="px-2 py-1 rounded-lg bg-emerald-500/20 hover:bg-emerald-500/30 text-emerald-300 font-semibold text-[10px] transition">
<button type="button" onclick="focizTestNotification()" class="px-2 py-1 rounded-lg bg-emerald-100 dark:bg-emerald-500/20 hover:bg-emerald-200 dark:hover:bg-emerald-500/30 text-emerald-800 dark:text-emerald-300 font-semibold text-[10px] transition">
Test Melding
</button>
</div>
<div id="notifPermRequest" class="p-3 rounded-xl bg-blue-500/10 border border-blue-500/30 text-blue-200 flex items-center justify-between">
<div id="notifPermRequest" class="p-3 rounded-xl bg-blue-50 dark:bg-blue-500/10 border border-blue-200 dark:border-blue-500/30 text-blue-900 dark:text-blue-200 flex items-center justify-between">
<div class="flex items-center space-x-2">
<i data-lucide="bell" class="w-4 h-4 text-blue-400 flex-shrink-0"></i>
<i data-lucide="bell" class="w-4 h-4 text-blue-600 dark:text-blue-400 flex-shrink-0"></i>
<span class="text-[11px]">Toestemming browser vereist</span>
</div>
<button type="button" onclick="focizRequestPermission()" class="px-2.5 py-1 rounded-lg bg-blue-600 hover:bg-blue-500 text-white font-bold text-[10px] transition shadow">
@@ -201,29 +245,29 @@ require_once __DIR__ . '/env_badge.php';
</button>
</div>
<div id="notifPermDenied" class="hidden p-3 rounded-xl bg-red-500/10 border border-red-500/30 text-red-300 text-[11px] leading-relaxed">
<i data-lucide="alert-triangle" class="w-4 h-4 text-red-400 inline mr-1 -mt-0.5"></i>
Browser meldingen zijn geblokkeerd. Klik op het slotje links in de browser adresbalk om meldingen toe te staan.
<div id="notifPermDenied" class="hidden p-3 rounded-xl bg-red-50 dark:bg-red-500/10 border border-red-200 dark:border-red-500/30 text-red-800 dark:text-red-300 text-[11px] leading-relaxed">
<i data-lucide="alert-triangle" class="w-4 h-4 text-red-600 dark:text-red-400 inline mr-1 -mt-0.5"></i>
Browser meldingen zijn geblokkeerd. Klik op het slotje links in de adresbalk om meldingen toe te staan.
</div>
<!-- Toggle Meldingen Inschakelen -->
<div class="flex items-center justify-between p-3 rounded-xl bg-slate-950/60 border border-slate-800">
<div class="flex items-center justify-between p-3 rounded-xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800">
<div>
<span class="font-semibold text-white block">Meldingen Actief</span>
<span class="text-[10px] text-slate-400">Automatisch waarschuwen bij naderende afspraken</span>
<span class="font-semibold text-slate-900 dark:text-white block">Meldingen Actief</span>
<span class="text-[10px] text-slate-500 dark:text-slate-400">Automatisch waarschuwen bij naderende afspraken</span>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" id="notifEnabledInput" class="sr-only peer">
<div class="w-9 h-5 bg-slate-800 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-slate-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-blue-600"></div>
<div class="w-9 h-5 bg-slate-200 dark:bg-slate-800 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-slate-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-emerald-600"></div>
</label>
</div>
<!-- Vooraankondigingstijd -->
<div>
<label class="block font-semibold text-slate-300 mb-1">
<label class="block font-semibold text-slate-700 dark:text-slate-300 mb-1">
Hoeveel tijd van tevoren waarschuwen?
</label>
<select id="notifLeadTimeSelect" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-2 text-white focus:outline-none focus:border-blue-500">
<select id="notifLeadTimeSelect" class="w-full bg-slate-50 dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-2 text-slate-900 dark:text-white focus:outline-none focus:border-emerald-500">
<option value="0">0 minuten (Precies op aanvangstijd)</option>
<option value="2">2 minuten van tevoren</option>
<option value="5" selected>5 minuten van tevoren (Aanbevolen)</option>
@@ -236,10 +280,10 @@ require_once __DIR__ . '/env_badge.php';
<!-- Aantal Herhalingen & Interval Grid -->
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block font-semibold text-slate-300 mb-1">
<label class="block font-semibold text-slate-700 dark:text-slate-300 mb-1">
Aantal herhalingen
</label>
<select id="notifRepeatCountSelect" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-2 text-white focus:outline-none focus:border-blue-500">
<select id="notifRepeatCountSelect" class="w-full bg-slate-50 dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-2 text-slate-900 dark:text-white focus:outline-none focus:border-emerald-500">
<option value="1">1x (Alleen 1e melding)</option>
<option value="2" selected>2x (Aanbevolen)</option>
<option value="3">3x</option>
@@ -248,10 +292,10 @@ require_once __DIR__ . '/env_badge.php';
</div>
<div>
<label class="block font-semibold text-slate-300 mb-1">
<label class="block font-semibold text-slate-700 dark:text-slate-300 mb-1">
Herhalingsinterval
</label>
<select id="notifIntervalSelect" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-2 text-white focus:outline-none focus:border-blue-500">
<select id="notifIntervalSelect" class="w-full bg-slate-50 dark:bg-slate-950 border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-2 text-slate-900 dark:text-white focus:outline-none focus:border-emerald-500">
<option value="1">Elke 1 minuut</option>
<option value="2" selected>Elke 2 minuten</option>
<option value="3">Elke 3 minuten</option>
@@ -261,28 +305,28 @@ require_once __DIR__ . '/env_badge.php';
</div>
<!-- Geluidssignaal Toggle -->
<div class="flex items-center justify-between p-3 rounded-xl bg-slate-950/60 border border-slate-800">
<div class="flex items-center justify-between p-3 rounded-xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800">
<div class="flex items-center space-x-2">
<i data-lucide="volume-2" class="w-4 h-4 text-blue-400"></i>
<i data-lucide="volume-2" class="w-4 h-4 text-emerald-600 dark:text-emerald-400"></i>
<div>
<span class="font-semibold text-white block">Geluidssignaal</span>
<span class="text-[10px] text-slate-400">Zachte bel/chime afspelen bij melding</span>
<span class="font-semibold text-slate-900 dark:text-white block">Geluidssignaal</span>
<span class="text-[10px] text-slate-500 dark:text-slate-400">Zachte chime afspelen bij melding</span>
</div>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" id="notifSoundInput" checked class="sr-only peer">
<div class="w-9 h-5 bg-slate-800 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-slate-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-blue-600"></div>
<div class="w-9 h-5 bg-slate-200 dark:bg-slate-800 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-slate-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-emerald-600"></div>
</label>
</div>
<div id="notifSaveStatus" class="hidden text-emerald-400 text-center font-semibold text-[11px] py-1"></div>
<div id="notifSaveStatus" class="hidden text-emerald-600 dark:text-emerald-400 text-center font-semibold text-[11px] py-1"></div>
<!-- Knoppen -->
<div class="pt-2 flex items-center space-x-2">
<button type="button" onclick="closeNotificationModal()" class="flex-1 py-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-300 font-semibold transition">
<button type="button" onclick="closeNotificationModal()" class="flex-1 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-300 font-semibold transition">
Annuleren
</button>
<button type="submit" id="saveNotifBtn" class="flex-1 py-2 rounded-xl bg-blue-600 hover:bg-blue-500 text-white font-bold transition shadow-md shadow-blue-500/20">
<button type="submit" id="saveNotifBtn" class="flex-1 py-2 rounded-xl bg-emerald-600 hover:bg-emerald-500 text-white font-bold transition shadow-md shadow-emerald-600/20">
Voorkeuren Opslaan
</button>
</div>
@@ -291,5 +335,46 @@ require_once __DIR__ . '/env_badge.php';
</div>
<?php endif; ?>
<main class="flex-1 max-w-7xl w-full mx-auto p-4 sm:p-6 lg:p-8">
<script>
/**
* Universele Thema-controller voor Fociz
*/
function focizSetTheme(theme, saveServer = true) {
localStorage.setItem('fociz_theme', theme);
let effective = theme;
if (theme === 'system') {
effective = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
if (effective === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
// Update Lucide pictogrammen in header
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
// Update profiel preview selectoren als aanwezig op pagina
if (typeof updateProfileThemeUI === 'function') {
updateProfileThemeUI(theme);
}
if (saveServer) {
fetch('/api/theme.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ theme: theme })
}).catch(() => {});
}
}
function focizQuickToggleTheme() {
const isDark = document.documentElement.classList.contains('dark');
const nextTheme = isDark ? 'light' : 'dark';
focizSetTheme(nextTheme, true);
}
</script>
<main class="flex-1 max-w-7xl w-full mx-auto p-4 sm:p-6 lg:p-8">
+90 -88
View File
@@ -112,16 +112,16 @@ $dutchMonths = ['', 'januari', 'februari', 'maart', 'april', 'mei', 'juni', 'jul
$formattedDate = $dutchDays[date('w')] . ' ' . date('j') . ' ' . $dutchMonths[(int)date('n')] . ' ' . date('Y');
?>
<div class="space-y-6">
<div class="space-y-6 max-w-7xl mx-auto">
<!-- Top Banner: Datum, Hoofddoel & Integraties Status -->
<div class="bg-gradient-to-r from-slate-900 via-[#0e1626] to-slate-900 border border-slate-800 rounded-2xl p-6 shadow-2xl">
<div class="bg-white dark:bg-gradient-to-r dark:from-slate-900 dark:via-[#0e1626] dark:to-slate-900 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-2xl transition">
<div class="flex flex-col lg:flex-row lg:items-center justify-between gap-4">
<div>
<div class="flex items-center space-x-2 text-emerald-400 text-xs font-semibold uppercase tracking-wider mb-1">
<div class="flex items-center space-x-2 text-emerald-600 dark:text-emerald-400 text-xs font-bold uppercase tracking-wider mb-1">
<i data-lucide="calendar" class="w-4 h-4"></i>
<span><?= htmlspecialchars($formattedDate) ?></span>
</div>
<h1 class="text-2xl sm:text-3xl font-black text-white tracking-tight">
<h1 class="text-2xl sm:text-3xl font-black text-slate-900 dark:text-white tracking-tight">
Dagplanning & Structuur
</h1>
</div>
@@ -129,28 +129,28 @@ $formattedDate = $dutchDays[date('w')] . ' ' . date('j') . ' ' . $dutchMonths[(i
<!-- Integratie Status Badges -->
<div class="flex flex-wrap items-center gap-2">
<?php if ($isOutlookConnected): ?>
<div class="flex items-center space-x-2 px-3 py-1.5 rounded-xl bg-blue-950/60 border border-blue-800/60 text-blue-300 text-xs font-medium">
<span class="w-2 h-2 rounded-full bg-emerald-400 animate-pulse"></span>
<div class="flex items-center space-x-2 px-3 py-1.5 rounded-xl bg-blue-50 dark:bg-blue-950/60 border border-blue-200 dark:border-blue-800/60 text-blue-700 dark:text-blue-300 text-xs font-medium shadow-sm">
<span class="w-2 h-2 rounded-full bg-emerald-500 animate-pulse"></span>
<span>Outlook 365 Live</span>
<button onclick="location.reload()" title="Agenda Verversen" class="p-1 text-blue-400 hover:text-white rounded transition">
<button onclick="location.reload()" title="Agenda Verversen" class="p-1 text-blue-500 hover:text-blue-800 dark:text-blue-400 dark:hover:text-white rounded transition">
<i data-lucide="refresh-cw" class="w-3 h-3"></i>
</button>
</div>
<?php else: ?>
<a href="/profile.php" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-slate-800/80 border border-slate-700 text-slate-300 hover:text-white hover:bg-slate-700 text-xs font-medium transition">
<i data-lucide="link-2" class="w-3.5 h-3.5 text-blue-400"></i>
<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-sm">
<i data-lucide="link-2" class="w-3.5 h-3.5 text-blue-500"></i>
<span>Koppel Outlook</span>
</a>
<?php endif; ?>
<?php if ($isJiraLive): ?>
<a href="#jiraPanel" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-sky-950/60 border border-sky-800/60 text-sky-300 hover:text-white text-xs font-medium transition">
<span class="w-2 h-2 rounded-full bg-sky-400 animate-pulse"></span>
<a href="#jiraPanel" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-sky-50 dark:bg-sky-950/60 border border-sky-200 dark:border-sky-800/60 text-sky-700 dark:text-sky-300 hover:text-sky-900 dark:hover:text-white text-xs font-medium transition shadow-sm">
<span class="w-2 h-2 rounded-full bg-sky-500 animate-pulse"></span>
<span>Jira: <?= count($jiraIssues) ?> tickets</span>
</a>
<?php else: ?>
<a href="/profile.php" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-slate-800/80 border border-slate-700 text-slate-300 hover:text-white hover:bg-slate-700 text-xs font-medium transition">
<i data-lucide="trello" class="w-3.5 h-3.5 text-sky-400"></i>
<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-sm">
<i data-lucide="trello" class="w-3.5 h-3.5 text-sky-500"></i>
<span>Koppel Jira</span>
</a>
<?php endif; ?>
@@ -158,8 +158,8 @@ $formattedDate = $dutchDays[date('w')] . ' ' . date('j') . ' ' . $dutchMonths[(i
</div>
<!-- Dagdoel invoerveld -->
<div class="mt-5 pt-4 border-t border-slate-800/80">
<label class="block text-xs font-bold text-emerald-400 uppercase tracking-wider mb-1.5 flex items-center space-x-1.5">
<div class="mt-5 pt-4 border-t border-slate-100 dark:border-slate-800/80">
<label class="block text-xs font-bold text-emerald-700 dark:text-emerald-400 uppercase tracking-wider mb-1.5 flex items-center space-x-1.5">
<i data-lucide="target" class="w-4 h-4"></i>
<span>Mijn Belangrijkste Dagdoel (Nummer 1 Focus)</span>
</label>
@@ -169,12 +169,12 @@ $formattedDate = $dutchDays[date('w')] . ' ' . date('j') . ' ' . $dutchMonths[(i
id="focusGoalInput"
value="<?= htmlspecialchars($dailyPlan['focus_goal'] ?? '') ?>"
placeholder="Wat moet er vandaag absoluut gebeuren voor succes?"
class="flex-1 bg-slate-950/70 border border-slate-700/80 rounded-xl px-4 py-2.5 text-white placeholder-slate-500 text-sm focus:outline-none focus:ring-2 focus:ring-emerald-500/50 focus:border-emerald-500 font-medium transition"
class="flex-1 bg-slate-50 dark:bg-slate-950/70 border border-slate-300 dark:border-slate-700/80 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-emerald-500/50 focus:border-emerald-500 font-medium transition"
>
<button
onclick="saveGoal()"
id="saveGoalBtn"
class="px-4 py-2.5 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold text-xs rounded-xl transition flex items-center space-x-1 shadow-md shadow-emerald-500/20"
class="px-4 py-2.5 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold text-xs rounded-xl transition flex items-center space-x-1 shadow-md shadow-emerald-500/20 flex-shrink-0 cursor-pointer"
>
<i data-lucide="check-circle-2" class="w-4 h-4"></i>
<span>Opslaan</span>
@@ -190,101 +190,101 @@ $formattedDate = $dutchDays[date('w')] . ' ' . date('j') . ' ' . $dutchMonths[(i
<div class="lg:col-span-7 space-y-6">
<!-- Focus Modus Timer -->
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-6 shadow-xl relative overflow-hidden backdrop-blur-sm">
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 shadow-sm dark:shadow-xl relative overflow-hidden backdrop-blur-sm transition">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center space-x-2">
<div class="w-8 h-8 rounded-lg bg-emerald-500/10 text-emerald-400 flex items-center justify-center">
<div class="w-8 h-8 rounded-xl bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 flex items-center justify-center font-bold">
<i data-lucide="flame" class="w-4 h-4"></i>
</div>
<div>
<h3 class="text-sm font-bold text-white uppercase tracking-wider">Focus Modus</h3>
<p class="text-[11px] text-slate-400">Pomodoro & diepe concentratie</p>
<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 & diepe concentratie</p>
</div>
</div>
<div class="flex bg-slate-950/80 p-1 rounded-xl border border-slate-800 text-xs">
<div class="flex bg-slate-100 dark:bg-slate-950/80 p-1 rounded-xl border border-slate-200 dark:border-slate-800 text-xs">
<button onclick="setTimerPreset(25)" id="btnPreset25" class="px-2.5 py-1 rounded-lg font-bold bg-emerald-500 text-slate-950 transition">25m Focus</button>
<button onclick="setTimerPreset(50)" id="btnPreset50" class="px-2.5 py-1 rounded-lg text-slate-400 hover:text-slate-200 transition">50m Deep</button>
<button onclick="setTimerPreset(5)" id="btnPreset5" class="px-2.5 py-1 rounded-lg text-slate-400 hover:text-slate-200 transition">5m Pauze</button>
<button onclick="setTimerPreset(50)" id="btnPreset50" class="px-2.5 py-1 rounded-lg text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-200 transition">50m Deep</button>
<button onclick="setTimerPreset(5)" id="btnPreset5" class="px-2.5 py-1 rounded-lg text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-200 transition">5m Pauze</button>
</div>
</div>
<div class="text-center my-6">
<div id="timerDisplay" class="text-5xl sm:text-6xl font-black font-mono tracking-tight text-white mb-2">25:00</div>
<div class="min-h-[22px] text-xs text-slate-400 truncate max-w-sm mx-auto flex items-center justify-center space-x-1">
<span class="text-emerald-400 font-medium">Actieve focus:</span>
<span id="activeTaskDisplay" class="text-slate-200 font-semibold">Kies een taak hieronder</span>
<div id="timerDisplay" class="text-5xl sm:text-6xl font-black font-mono tracking-tight text-slate-900 dark:text-white mb-2">25:00</div>
<div class="min-h-[22px] text-xs text-slate-500 dark:text-slate-400 truncate max-w-sm mx-auto flex items-center justify-center space-x-1">
<span class="text-emerald-600 dark:text-emerald-400 font-medium">Actieve focus:</span>
<span id="activeTaskDisplay" class="text-slate-800 dark:text-slate-200 font-semibold">Kies een taak hieronder</span>
</div>
<div class="w-full bg-slate-950/80 h-2 rounded-full overflow-hidden mt-4 border border-slate-800/80">
<div class="w-full bg-slate-100 dark:bg-slate-950/80 h-2 rounded-full overflow-hidden mt-4 border border-slate-200 dark:border-slate-800/80">
<div id="timerProgress" class="h-full bg-gradient-to-r from-emerald-500 to-teal-400 transition-all duration-300 rounded-full" style="width: 0%"></div>
</div>
</div>
<div class="flex items-center justify-center space-x-3">
<button id="timerToggleBtn" onclick="toggleTimer()" class="flex items-center space-x-2 px-6 py-2.5 rounded-xl font-bold text-sm bg-emerald-500 hover:bg-emerald-600 text-slate-950 transition shadow-lg shadow-emerald-500/20">
<button id="timerToggleBtn" onclick="toggleTimer()" class="flex items-center space-x-2 px-6 py-2.5 rounded-xl font-bold text-sm bg-emerald-500 hover:bg-emerald-600 text-slate-950 transition shadow-lg shadow-emerald-500/20 cursor-pointer">
<i data-lucide="play" class="w-4 h-4 fill-current"></i>
<span id="timerToggleText">Start Focus</span>
</button>
<button onclick="resetTimer()" class="p-2.5 rounded-xl bg-slate-800/80 text-slate-400 hover:text-slate-200 hover:bg-slate-700 transition border border-slate-700/60" 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>
</button>
</div>
</div>
<!-- Takenlijst -->
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 shadow-xl backdrop-blur-sm">
<div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-800">
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 shadow-sm dark:shadow-xl backdrop-blur-sm transition">
<div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-100 dark:border-slate-800">
<div>
<h3 class="text-sm font-bold 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 class="text-xs font-normal text-slate-400">(<?= count($tasks) ?>)</span>
<span class="text-xs font-normal text-slate-500 dark:text-slate-400">(<?= count($tasks) ?>)</span>
</h3>
</div>
<button onclick="toggleAddTaskForm()" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-emerald-500 hover:bg-emerald-600 text-slate-950 text-xs font-bold transition shadow-md shadow-emerald-500/20">
<button onclick="toggleAddTaskForm()" class="flex items-center space-x-1.5 px-3 py-1.5 rounded-xl bg-emerald-500 hover:bg-emerald-600 text-slate-950 text-xs font-bold transition shadow-md shadow-emerald-500/20 cursor-pointer">
<i data-lucide="plus" class="w-4 h-4"></i>
<span>Nieuwe Taak</span>
</button>
</div>
<!-- Nieuwe taak formulier (verborgen by default) -->
<div id="addTaskForm" class="hidden mb-4 p-4 rounded-xl bg-slate-950/90 border border-emerald-500/30 space-y-3">
<div id="addTaskForm" class="hidden mb-4 p-4 rounded-2xl bg-slate-50 dark:bg-slate-950/90 border border-emerald-500/30 space-y-3 transition">
<div>
<label class="block text-[11px] font-medium text-slate-400 mb-1">Taaktitel</label>
<input type="text" id="newTaskTitle" placeholder="Wat moet er vandaag gedaan worden?" class="w-full bg-slate-900 border border-slate-800 rounded-lg px-3 py-2 text-white text-xs placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-emerald-500">
<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-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-emerald-500">
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block text-[11px] font-medium text-slate-400 mb-1">Prioriteit</label>
<select id="newTaskPriority" class="w-full bg-slate-900 border border-slate-800 rounded-lg px-2.5 py-1.5 text-white text-xs focus:outline-none">
<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">
<option value="P1">P1 - Brandend / Hoogste Focus</option>
<option value="P2" selected>P2 - Belangrijk (Standaard)</option>
<option value="P3">P3 - Regulier / Lage druk</option>
</select>
</div>
<div>
<label class="block text-[11px] font-medium text-slate-400 mb-1">Tijdblok (Starttijd)</label>
<input type="text" id="newTaskTime" placeholder="Bijv. 09:30" class="w-full bg-slate-900 border border-slate-800 rounded-lg px-2.5 py-1.5 text-white text-xs font-mono focus:outline-none">
<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>
<div class="flex space-x-2 pt-1">
<button onclick="submitNewTask()" class="px-4 py-1.5 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold rounded-lg text-xs transition">Opslaan</button>
<button onclick="toggleAddTaskForm()" class="px-3 py-1.5 bg-slate-800 hover:bg-slate-700 text-slate-400 rounded-lg text-xs transition">Annuleren</button>
<button onclick="submitNewTask()" class="px-4 py-1.5 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold rounded-lg text-xs transition cursor-pointer">Opslaan</button>
<button onclick="toggleAddTaskForm()" class="px-3 py-1.5 bg-slate-200 hover:bg-slate-300 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-400 rounded-lg text-xs transition cursor-pointer">Annuleren</button>
</div>
</div>
<!-- Taken weergave -->
<div class="space-y-2" id="tasksContainer">
<?php if (empty($tasks)): ?>
<div class="text-center py-8 text-slate-500 text-xs">
<div class="text-center py-8 text-slate-400 dark:text-slate-500 text-xs">
Nog geen taken gepland voor vandaag. Klik op 'Nieuwe Taak' of importeer een Jira ticket hieronder.
</div>
<?php else: ?>
<?php foreach ($tasks as $task): ?>
<div class="group flex items-center justify-between p-3 rounded-xl border <?= $task['is_completed'] ? 'bg-slate-950/30 border-slate-900 opacity-60' : 'bg-slate-950/60 border-slate-800 hover:border-slate-700' ?> transition" id="task-row-<?= $task['id'] ?>">
<div class="group flex items-center justify-between p-3 rounded-2xl border <?= $task['is_completed'] ? 'bg-slate-50/50 dark:bg-slate-950/30 border-slate-200 dark:border-slate-900 opacity-60' : 'bg-slate-50 dark:bg-slate-950/60 border-slate-200 dark:border-slate-800 hover:border-slate-300 dark:hover:border-slate-700' ?> transition shadow-sm" id="task-row-<?= $task['id'] ?>">
<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-emerald-500 border-emerald-500 text-slate-950 font-bold' : 'border-slate-700 hover:border-emerald-400 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-emerald-500 border-emerald-500 text-slate-950 font-bold' : 'border-slate-300 dark:border-slate-700 hover:border-emerald-500 bg-white dark:bg-slate-900' ?>">
<?php if ($task['is_completed']): ?>
<i data-lucide="check" class="w-3.5 h-3.5 stroke-[3]"></i>
<?php endif; ?>
@@ -293,24 +293,24 @@ $formattedDate = $dutchDays[date('w')] . ' ' . date('j') . ' ' . $dutchMonths[(i
<div class="truncate">
<div class="flex items-center space-x-1.5 truncate">
<?php if ($task['source'] === 'JIRA'): ?>
<span class="px-1.5 py-0.2 rounded bg-sky-500/10 border border-sky-500/20 text-sky-400 font-mono text-[9px] font-bold">
<span class="px-1.5 py-0.2 rounded bg-sky-500/10 border border-sky-500/20 text-sky-600 dark:text-sky-400 font-mono text-[9px] font-bold">
JIRA
</span>
<?php endif; ?>
<span class="text-xs font-medium truncate <?= $task['is_completed'] ? 'line-through text-slate-500' : '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']) ?>
</span>
</div>
<div class="flex items-center space-x-2 mt-0.5">
<?php if (!empty($task['time_block_start'])): ?>
<span class="text-[10px] 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>
<span><?= htmlspecialchars($task['time_block_start']) ?></span>
</span>
<?php endif; ?>
<?php if (!empty($task['external_url'])): ?>
<a href="<?= htmlspecialchars($task['external_url']) ?>" target="_blank" class="text-[10px] text-sky-400 hover:underline flex items-center space-x-0.5">
<a href="<?= htmlspecialchars($task['external_url']) ?>" target="_blank" class="text-[10px] text-sky-600 dark:text-sky-400 hover:underline flex items-center space-x-0.5">
<span>Open in Jira</span>
<i data-lucide="external-link" class="w-2.5 h-2.5"></i>
</a>
@@ -320,17 +320,17 @@ $formattedDate = $dutchDays[date('w')] . ' ' . date('j') . ' ' . $dutchMonths[(i
</div>
<div class="flex items-center space-x-2 flex-shrink-0">
<span class="text-[10px] font-bold px-2 py-0.5 rounded-full <?= $task['priority'] === 'P1' ? 'bg-red-500/20 text-red-400 border border-red-500/30' : ($task['priority'] === 'P2' ? 'bg-amber-500/20 text-amber-400 border border-amber-500/30' : 'bg-slate-800 text-slate-400') ?>">
<span class="text-[10px] font-bold px-2 py-0.5 rounded-full <?= $task['priority'] === 'P1' ? 'bg-red-500/15 text-red-700 dark:text-red-400 border border-red-500/30' : ($task['priority'] === 'P2' ? 'bg-amber-500/15 text-amber-700 dark:text-amber-400 border border-amber-500/30' : 'bg-slate-200 dark:bg-slate-800 text-slate-600 dark:text-slate-400') ?>">
<?= htmlspecialchars($task['priority']) ?>
</span>
<?php if (!$task['is_completed']): ?>
<button onclick="selectFocusTask('<?= htmlspecialchars(addslashes($task['title'])) ?>')" title="Koppel aan Focus Timer" class="p-1.5 rounded-lg text-slate-400 hover:text-emerald-400 hover:bg-emerald-500/10 transition">
<button onclick="selectFocusTask('<?= htmlspecialchars(addslashes($task['title'])) ?>')" title="Koppel aan Focus Timer" class="p-1.5 rounded-lg text-slate-400 hover:text-emerald-600 dark:hover:text-emerald-400 hover:bg-emerald-500/10 transition">
<i data-lucide="flame" class="w-3.5 h-3.5"></i>
</button>
<?php endif; ?>
<button onclick="deleteTask(<?= $task['id'] ?>)" title="Verwijderen" class="p-1.5 rounded-lg text-slate-600 hover:text-red-400 hover:bg-red-500/10 opacity-0 group-hover:opacity-100 transition">
<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">
<i data-lucide="trash-2" class="w-3.5 h-3.5"></i>
</button>
</div>
@@ -341,38 +341,38 @@ $formattedDate = $dutchDays[date('w')] . ' ' . date('j') . ' ' . $dutchMonths[(i
</div>
<!-- Jira Snelle Import Widget -->
<div id="jiraPanel" class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 shadow-xl backdrop-blur-sm">
<div class="flex items-center justify-between pb-3 border-b border-slate-800 mb-3">
<div id="jiraPanel" class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 shadow-sm dark:shadow-xl 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 space-x-2">
<i data-lucide="trello" class="w-4 h-4 text-sky-400"></i>
<h3 class="text-sm font-bold text-white uppercase tracking-wider">
<i data-lucide="trello" class="w-4 h-4 text-sky-500"></i>
<h3 class="text-sm font-bold text-slate-900 dark:text-white uppercase tracking-wider">
Mijn Jira Tickets
</h3>
<span class="px-2 py-0.5 rounded-full text-[10px] font-bold <?= $isJiraLive ? 'bg-sky-500/20 text-sky-400 border border-sky-500/30' : 'bg-slate-800 text-slate-400' ?>">
<span class="px-2 py-0.5 rounded-full text-[10px] font-bold <?= $isJiraLive ? 'bg-sky-500/15 text-sky-700 dark:text-sky-400 border border-sky-500/30' : 'bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400' ?>">
<?= count($jiraIssues) ?>
</span>
</div>
<a href="/profile.php" class="text-xs text-slate-400 hover:text-sky-300 transition flex items-center space-x-1">
<a href="/profile.php" class="text-xs text-slate-500 dark:text-slate-400 hover:text-sky-600 dark:hover:text-sky-300 transition flex items-center space-x-1">
<span>Beheren</span>
<i data-lucide="chevron-right" class="w-3.5 h-3.5"></i>
</a>
</div>
<?php if (empty($jiraIssues)): ?>
<div class="text-center py-6 text-slate-500 text-xs">
<div class="text-center py-6 text-slate-400 dark:text-slate-500 text-xs">
Geen openstaande tickets gevonden in Jira.
</div>
<?php else: ?>
<div class="space-y-2 max-h-64 overflow-y-auto pr-1">
<?php foreach (array_slice($jiraIssues, 0, 6) as $issue): ?>
<div class="flex items-center justify-between p-2.5 rounded-xl bg-slate-950/60 border border-slate-800/80 hover:border-slate-700 transition">
<div class="flex items-center justify-between p-2.5 rounded-2xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800/80 hover:border-slate-300 dark:hover:border-slate-700 transition shadow-sm">
<div class="truncate mr-2">
<div class="flex items-center space-x-2">
<span class="font-mono text-[10px] font-bold text-sky-400 bg-sky-500/10 px-1.5 py-0.5 rounded">
<span class="font-mono text-[10px] font-bold text-sky-600 dark:text-sky-400 bg-sky-500/10 px-1.5 py-0.5 rounded">
<?= htmlspecialchars($issue['key']) ?>
</span>
<span class="text-xs font-semibold text-white truncate">
<span class="text-xs font-semibold text-slate-900 dark:text-white truncate">
<?= htmlspecialchars($issue['summary']) ?>
</span>
</div>
@@ -383,7 +383,7 @@ $formattedDate = $dutchDays[date('w')] . ' ' . date('j') . ' ' . $dutchMonths[(i
<button
onclick="quickImportJira(this, '<?= htmlspecialchars(addslashes($issue['summary'])) ?>', '<?= htmlspecialchars($issue['key']) ?>', '<?= htmlspecialchars(addslashes($issue['url'] ?? '')) ?>')"
class="flex items-center space-x-1 text-[11px] font-bold text-emerald-400 hover:text-emerald-300 bg-emerald-500/10 hover:bg-emerald-500/20 border border-emerald-500/20 px-2 py-1 rounded-lg transition flex-shrink-0"
class="flex items-center space-x-1 text-[11px] font-bold text-emerald-700 dark:text-emerald-400 hover:text-emerald-800 dark:hover:text-emerald-300 bg-emerald-500/10 hover:bg-emerald-500/20 border border-emerald-500/20 px-2 py-1 rounded-lg transition flex-shrink-0 cursor-pointer"
title="Plan in als dagtaak"
>
<i data-lucide="plus" class="w-3 h-3"></i>
@@ -396,34 +396,34 @@ $formattedDate = $dutchDays[date('w')] . ' ' . date('j') . ' ' . $dutchMonths[(i
</div>
<!-- Dagnotities & Reflectie -->
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 shadow-xl backdrop-blur-sm">
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 shadow-sm dark:shadow-xl backdrop-blur-sm transition">
<div class="flex items-center space-x-2 mb-3">
<i data-lucide="book-open" class="w-4 h-4 text-emerald-400"></i>
<h3 class="text-sm font-bold text-white uppercase tracking-wider">Dagnotities & Kladblok</h3>
<i data-lucide="book-open" class="w-4 h-4 text-emerald-600 dark:text-emerald-400"></i>
<h3 class="text-sm font-bold text-slate-900 dark:text-white uppercase tracking-wider">Dagnotities & Kladblok</h3>
</div>
<textarea
id="dailyNotesInput"
rows="3"
placeholder="Belangrijke aantekeningen, reflecties of snelle memo's voor vandaag..."
onblur="saveGoal()"
class="w-full bg-slate-950/70 border border-slate-800 rounded-xl p-3 text-white text-xs placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-emerald-500 resize-none transition"
class="w-full bg-slate-50 dark:bg-slate-950/70 border border-slate-300 dark:border-slate-800 rounded-2xl 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-emerald-500 resize-none transition"
><?= htmlspecialchars($dailyPlan['notes'] ?? '') ?></textarea>
</div>
</div>
<!-- Rechter kolom: Timeblocking & Outlook Tijdlijn -->
<div class="lg:col-span-5 space-y-6">
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 shadow-xl backdrop-blur-sm">
<div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-800">
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 shadow-sm dark:shadow-xl backdrop-blur-sm transition">
<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">
<i data-lucide="clock" class="w-5 h-5 text-emerald-400"></i>
<h3 class="text-sm font-bold text-white uppercase tracking-wider">Tijdlijn & Time-blocking</h3>
<i data-lucide="clock" class="w-5 h-5 text-emerald-600 dark:text-emerald-400"></i>
<h3 class="text-sm font-bold text-slate-900 dark:text-white uppercase tracking-wider">Tijdlijn & Time-blocking</h3>
</div>
<div class="flex items-center space-x-2">
<?php if ($isOutlookConnected): ?>
<span class="px-2 py-0.5 rounded bg-blue-500/10 border border-blue-500/20 text-blue-400 text-[10px] font-bold">Outlook 365</span>
<span class="px-2 py-0.5 rounded bg-blue-500/10 border border-blue-500/20 text-blue-700 dark:text-blue-400 text-[10px] font-bold">Outlook 365</span>
<?php endif; ?>
<span class="text-xs 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>
@@ -442,17 +442,17 @@ $formattedDate = $dutchDays[date('w')] . ' ' . date('j') . ' ' . $dutchMonths[(i
return !empty($t['time_block_start']) && (int)explode(':', $t['time_block_start'])[0] === $hourInt;
});
?>
<div class="flex items-start group min-h-[50px] border-b border-slate-800/40 pb-2 last:border-0">
<div class="w-14 text-xs font-mono font-medium text-slate-400 pt-1 flex-shrink-0">
<div class="flex items-start group min-h-[50px] border-b border-slate-100 dark:border-slate-800/40 pb-2 last:border-0">
<div class="w-14 text-xs font-mono font-medium text-slate-500 dark:text-slate-400 pt-1 flex-shrink-0">
<?= $hour ?>
</div>
<div class="flex-1 space-y-1.5">
<!-- Outlook meetings -->
<?php foreach ($slotEvents as $evt): ?>
<div class="flex items-center justify-between p-2 rounded-xl bg-blue-950/50 border border-blue-800/60 text-blue-100 text-xs shadow-sm">
<div class="flex items-center justify-between p-2 rounded-xl bg-blue-50 dark:bg-blue-950/50 border border-blue-200 dark:border-blue-800/60 text-blue-900 dark:text-blue-100 text-xs shadow-sm">
<div class="flex items-center space-x-2 truncate mr-2">
<span class="px-1.5 py-0.5 rounded bg-blue-500/20 text-blue-400 font-mono text-[10px] font-bold">
<span class="px-1.5 py-0.5 rounded bg-blue-500/15 text-blue-700 dark:text-blue-400 font-mono text-[10px] font-bold">
<?= htmlspecialchars($evt['start']) ?> - <?= htmlspecialchars($evt['end']) ?>
</span>
<span class="font-semibold truncate" title="<?= htmlspecialchars($evt['subject']) ?>">
@@ -460,7 +460,7 @@ $formattedDate = $dutchDays[date('w')] . ' ' . date('j') . ' ' . $dutchMonths[(i
</span>
</div>
<?php if (!empty($evt['meeting_url'])): ?>
<a href="<?= htmlspecialchars($evt['meeting_url']) ?>" target="_blank" class="flex items-center space-x-1 text-[10px] text-blue-300 hover:text-white bg-blue-600/30 hover:bg-blue-600/50 px-2 py-0.5 rounded-lg flex-shrink-0 transition">
<a href="<?= htmlspecialchars($evt['meeting_url']) ?>" target="_blank" class="flex items-center space-x-1 text-[10px] text-white bg-blue-600 hover:bg-blue-700 px-2 py-0.5 rounded-lg flex-shrink-0 transition">
<i data-lucide="video" class="w-3 h-3"></i>
<span>Deelnemen</span>
</a>
@@ -470,21 +470,21 @@ $formattedDate = $dutchDays[date('w')] . ' ' . date('j') . ' ' . $dutchMonths[(i
<!-- Geplande taken -->
<?php foreach ($slotTasks as $t): ?>
<div class="flex items-center justify-between p-2 rounded-xl border text-xs <?= $t['is_completed'] ? 'bg-slate-900/40 border-slate-800 text-slate-500 line-through' : 'bg-emerald-950/30 border-emerald-800/40 text-emerald-100' ?>">
<div class="flex items-center justify-between p-2 rounded-xl border text-xs <?= $t['is_completed'] ? 'bg-slate-100 dark:bg-slate-900/40 border-slate-200 dark:border-slate-800 text-slate-400 dark:text-slate-500 line-through' : 'bg-emerald-50 dark:bg-emerald-950/30 border-emerald-200 dark:border-emerald-800/40 text-emerald-900 dark:text-emerald-100' ?>">
<div class="flex items-center space-x-2 truncate mr-2">
<span class="px-1.5 py-0.5 rounded bg-emerald-500/20 text-emerald-400 font-mono text-[10px] font-bold">
<span class="px-1.5 py-0.5 rounded bg-emerald-500/15 text-emerald-700 dark:text-emerald-400 font-mono text-[10px] font-bold">
<?= htmlspecialchars($t['time_block_start']) ?>
</span>
<span class="font-semibold truncate"><?= htmlspecialchars($t['title']) ?></span>
</div>
<span class="text-[10px] font-bold px-1.5 py-0.5 rounded bg-emerald-500/20 text-emerald-400">
<span class="text-[10px] font-bold px-1.5 py-0.5 rounded bg-emerald-500/20 text-emerald-700 dark:text-emerald-400">
<?= $t['priority'] ?>
</span>
</div>
<?php endforeach; ?>
<?php if (empty($slotEvents) && empty($slotTasks)): ?>
<button onclick="quickSchedule('<?= $hour ?>')" class="w-full text-left py-1 px-2 rounded-lg border border-dashed border-transparent hover:border-slate-800 hover:bg-slate-950/40 text-slate-600 hover:text-slate-400 text-xs transition">
<button onclick="quickSchedule('<?= $hour ?>')" class="w-full text-left py-1 px-2 rounded-lg border border-dashed border-transparent hover:border-slate-300 dark:hover:border-slate-800 hover:bg-slate-50 dark:hover:bg-slate-950/40 text-slate-400 dark:text-slate-600 hover:text-slate-700 dark:hover:text-slate-400 text-xs transition cursor-pointer">
+ Plan taak om <?= $hour ?>
</button>
<?php endif; ?>
@@ -522,9 +522,11 @@ function setTimerPreset(minutes) {
updateTimerDisplay();
document.getElementById('timerToggleText').innerText = 'Start Focus';
document.getElementById('btnPreset25').className = minutes === 25 ? 'px-2.5 py-1 rounded-lg font-bold bg-emerald-500 text-slate-950' : 'px-2.5 py-1 rounded-lg text-slate-400 hover:text-slate-200';
document.getElementById('btnPreset50').className = minutes === 50 ? 'px-2.5 py-1 rounded-lg font-bold bg-emerald-500 text-slate-950' : 'px-2.5 py-1 rounded-lg text-slate-400 hover:text-slate-200';
document.getElementById('btnPreset5').className = minutes === 5 ? 'px-2.5 py-1 rounded-lg font-bold bg-teal-500 text-slate-950' : 'px-2.5 py-1 rounded-lg text-slate-400 hover:text-slate-200';
const inactiveClass = 'px-2.5 py-1 rounded-lg text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-200 transition';
const activeClass = 'px-2.5 py-1 rounded-lg font-bold bg-emerald-500 text-slate-950 transition';
document.getElementById('btnPreset25').className = minutes === 25 ? activeClass : inactiveClass;
document.getElementById('btnPreset50').className = minutes === 50 ? activeClass : inactiveClass;
document.getElementById('btnPreset5').className = minutes === 5 ? activeClass : inactiveClass;
}
function toggleTimer() {
+290 -115
View File
@@ -198,47 +198,50 @@ $appConfig = microsoft_get_app_config();
// Notificatie-instellingen
$notifSettings = get_user_notification_settings($userId);
// Thema ophalen
$userTheme = get_user_theme($userId);
$pageTitle = 'Mijn Profiel & Koppelingen — Fociz';
require_once __DIR__ . '/includes/header.php';
?>
<div class="space-y-8 max-w-5xl mx-auto pb-12">
<!-- Profiel Header Card -->
<div class="relative overflow-hidden bg-slate-900/90 border border-slate-800 rounded-3xl p-6 sm:p-8 shadow-2xl backdrop-blur-xl">
<div class="relative overflow-hidden bg-white dark:bg-slate-900/90 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-8 shadow-sm dark:shadow-2xl backdrop-blur-xl transition">
<div class="absolute -top-20 -right-20 w-72 h-72 bg-emerald-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="flex items-center space-x-4 sm:space-x-5">
<div class="w-16 h-16 sm:w-20 sm:h-20 rounded-2xl bg-gradient-to-tr from-emerald-600 to-teal-400 p-0.5 shadow-xl shadow-emerald-500/20 flex-shrink-0">
<div class="w-full h-full rounded-2xl bg-slate-950 flex items-center justify-center font-black text-2xl sm:text-3xl text-emerald-400 uppercase">
<div class="w-full h-full rounded-2xl bg-white dark:bg-slate-950 flex items-center justify-center font-black text-2xl sm:text-3xl text-emerald-600 dark:text-emerald-400 uppercase">
<?= strtoupper(substr($userProfile['name'], 0, 1)) ?>
</div>
</div>
<div class="space-y-1">
<div class="flex flex-wrap items-center gap-2">
<h1 class="text-2xl sm:text-3xl font-black text-white tracking-tight">
<h1 class="text-2xl sm:text-3xl font-black text-slate-900 dark:text-white tracking-tight">
<?= htmlspecialchars($userProfile['name']) ?>
</h1>
<?php if ($userProfile['role'] === 'ADMIN'): ?>
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/20 border border-emerald-500/40 text-emerald-400 text-xs font-bold flex items-center space-x-1">
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/15 border border-emerald-500/30 text-emerald-700 dark:text-emerald-400 text-xs font-bold flex items-center space-x-1">
<i data-lucide="shield" class="w-3 h-3"></i>
<span>Beheerder</span>
</span>
<?php else: ?>
<span class="px-2.5 py-0.5 rounded-full bg-blue-500/20 border border-blue-500/40 text-blue-400 text-xs font-bold flex items-center space-x-1">
<span class="px-2.5 py-0.5 rounded-full bg-blue-500/15 border border-blue-500/30 text-blue-700 dark:text-blue-400 text-xs font-bold flex items-center space-x-1">
<i data-lucide="user" class="w-3 h-3"></i>
<span>Collega</span>
</span>
<?php endif; ?>
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-xs font-semibold flex items-center space-x-1">
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-700 dark:text-emerald-400 text-xs font-semibold flex items-center space-x-1">
<i data-lucide="shield-check" class="w-3 h-3"></i>
<span>2FA Beveiligd</span>
</span>
</div>
<p class="text-xs text-slate-400 flex items-center space-x-2">
<p class="text-xs text-slate-500 dark:text-slate-400 flex items-center space-x-2">
<span><?= htmlspecialchars($userProfile['email']) ?></span>
<span>•</span>
<span>Lid sinds <?= date('d-m-Y', strtotime($userProfile['created_at'])) ?></span>
@@ -248,8 +251,8 @@ require_once __DIR__ . '/includes/header.php';
<?php if ($userProfile['role'] === 'ADMIN'): ?>
<div class="flex-shrink-0">
<a href="/admin.php" class="inline-flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-200 border border-slate-700 text-xs font-semibold transition shadow-md">
<i data-lucide="shield-alert" class="w-4 h-4 text-emerald-400"></i>
<a href="/admin.php" class="inline-flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-800 dark:text-slate-200 border border-slate-200 dark:border-slate-700 text-xs font-semibold transition shadow-sm">
<i data-lucide="shield-alert" class="w-4 h-4 text-emerald-600 dark:text-emerald-400"></i>
<span>Systeembeheer Openen</span>
</a>
</div>
@@ -259,45 +262,180 @@ require_once __DIR__ . '/includes/header.php';
<!-- Meldingen Banner -->
<?php if ($message): ?>
<div class="p-4 rounded-2xl flex items-start space-x-3 text-sm animate-in fade-in duration-200 <?= $messageType === 'success' ? 'bg-emerald-500/10 border border-emerald-500/30 text-emerald-200' : 'bg-red-500/10 border border-red-500/30 text-red-200' ?>">
<i data-lucide="<?= $messageType === 'success' ? 'check-circle-2' : 'alert-triangle' ?>" class="w-5 h-5 flex-shrink-0 mt-0.5 <?= $messageType === 'success' ? 'text-emerald-400' : 'text-red-400' ?>"></i>
<div class="p-4 rounded-2xl flex items-start space-x-3 text-sm animate-in fade-in duration-200 <?= $messageType === 'success' ? 'bg-emerald-500/10 border border-emerald-500/30 text-emerald-800 dark:text-emerald-200' : 'bg-red-500/10 border border-red-500/30 text-red-800 dark:text-red-200' ?>">
<i data-lucide="<?= $messageType === 'success' ? 'check-circle-2' : 'alert-triangle' ?>" class="w-5 h-5 flex-shrink-0 mt-0.5 <?= $messageType === 'success' ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400' ?>"></i>
<div class="flex-1 font-medium"><?= htmlspecialchars($message) ?></div>
</div>
<?php endif; ?>
<!-- Sectie 1: Mijn Microsoft 365 Outlook Agenda -->
<div class="bg-slate-900/80 border border-slate-800 rounded-3xl p-6 sm:p-7 shadow-xl">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-6 border-b border-slate-800/80">
<!-- Sectie 0: Weergave & Thema Instellingen (Dark & Light mode) -->
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl 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 items-center space-x-3.5">
<div class="w-12 h-12 rounded-2xl bg-blue-500/10 border border-blue-500/20 flex items-center justify-center text-blue-400 font-bold shadow-md">
<div class="w-12 h-12 rounded-2xl bg-purple-500/10 border border-purple-500/20 flex items-center justify-center text-purple-600 dark:text-purple-400 font-bold shadow-sm">
<i data-lucide="palette" class="w-6 h-6"></i>
</div>
<div>
<div class="flex items-center space-x-2">
<h2 class="text-lg font-bold text-slate-900 dark:text-white tracking-tight">Weergave & Thema</h2>
<span id="themeStatusBadge" class="px-2.5 py-0.5 rounded-full bg-emerald-500/15 border border-emerald-500/30 text-emerald-700 dark:text-emerald-400 text-[10px] font-bold">
Actief: <?= ucfirst($userTheme) ?>
</span>
</div>
<p class="text-xs text-slate-500 dark:text-slate-400">Kies uw gewenste uiterlijk: rustig donker, kraakhelder licht of synchroniseer automatisch met uw apparaat.</p>
</div>
</div>
</div>
<div class="mt-6 grid grid-cols-1 sm:grid-cols-3 gap-4">
<!-- Optie 1: Donker (Dark) -->
<button type="button" onclick="selectThemePreference('dark')" id="themeBtn-dark" class="theme-card relative text-left p-4 rounded-2xl border-2 transition duration-150 flex flex-col justify-between group hover:shadow-md cursor-pointer bg-slate-900 border-slate-700 text-white">
<div class="w-full h-24 rounded-xl bg-slate-950 p-2.5 border border-slate-800 mb-3 flex flex-col justify-between overflow-hidden shadow-inner">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-1.5">
<span class="w-2 h-2 rounded-full bg-red-400/80"></span>
<span class="w-2 h-2 rounded-full bg-amber-400/80"></span>
<span class="w-2 h-2 rounded-full bg-emerald-400/80"></span>
</div>
<span class="text-[9px] font-mono text-slate-500">fociz.dark</span>
</div>
<div class="space-y-1.5">
<div class="h-2 w-3/4 bg-emerald-500/40 rounded"></div>
<div class="h-2 w-1/2 bg-slate-800 rounded"></div>
</div>
<div class="flex space-x-1">
<div class="h-3 w-8 bg-slate-800 rounded"></div>
<div class="h-3 w-10 bg-emerald-500/20 rounded"></div>
</div>
</div>
<div>
<div class="flex items-center justify-between">
<span class="text-sm font-bold text-white flex items-center space-x-1.5">
<i data-lucide="moon" class="w-4 h-4 text-purple-400"></i>
<span>Donkere Modus</span>
</span>
<span id="themeCheck-dark" class="theme-check hidden w-5 h-5 rounded-full bg-emerald-500 text-slate-950 items-center justify-center">
<i data-lucide="check" class="w-3.5 h-3.5 stroke-[3]"></i>
</span>
</div>
<p class="text-[11px] text-slate-400 mt-1 leading-relaxed">
Diepe contrasten, rustig voor de ogen in de avond of donkere werkplek.
</p>
</div>
</button>
<!-- Optie 2: Licht (Light) -->
<button type="button" onclick="selectThemePreference('light')" id="themeBtn-light" class="theme-card relative text-left p-4 rounded-2xl border-2 transition duration-150 flex flex-col justify-between group hover:shadow-md cursor-pointer bg-white border-slate-200 text-slate-900">
<div class="w-full h-24 rounded-xl bg-slate-100 p-2.5 border border-slate-200 mb-3 flex flex-col justify-between overflow-hidden shadow-inner">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-1.5">
<span class="w-2 h-2 rounded-full bg-red-400/80"></span>
<span class="w-2 h-2 rounded-full bg-amber-400/80"></span>
<span class="w-2 h-2 rounded-full bg-emerald-400/80"></span>
</div>
<span class="text-[9px] font-mono text-slate-400">fociz.light</span>
</div>
<div class="space-y-1.5">
<div class="h-2 w-3/4 bg-emerald-600/40 rounded"></div>
<div class="h-2 w-1/2 bg-slate-300 rounded"></div>
</div>
<div class="flex space-x-1">
<div class="h-3 w-8 bg-slate-200 rounded"></div>
<div class="h-3 w-10 bg-emerald-100 rounded"></div>
</div>
</div>
<div>
<div class="flex items-center justify-between">
<span class="text-sm font-bold text-slate-900 flex items-center space-x-1.5">
<i data-lucide="sun" class="w-4 h-4 text-amber-500"></i>
<span>Lichte Modus</span>
</span>
<span id="themeCheck-light" class="theme-check hidden w-5 h-5 rounded-full bg-emerald-500 text-slate-950 items-center justify-center">
<i data-lucide="check" class="w-3.5 h-3.5 stroke-[3]"></i>
</span>
</div>
<p class="text-[11px] text-slate-500 mt-1 leading-relaxed">
Kraakhelder, fris en professioneel voor overdag en felle kantoorverlichting.
</p>
</div>
</button>
<!-- Optie 3: Systeem (Auto) -->
<button type="button" onclick="selectThemePreference('system')" id="themeBtn-system" class="theme-card relative text-left p-4 rounded-2xl border-2 transition duration-150 flex flex-col justify-between group hover:shadow-md cursor-pointer bg-slate-50 dark:bg-slate-900 border-slate-300 dark:border-slate-700">
<div class="w-full h-24 rounded-xl border border-slate-300 dark:border-slate-800 mb-3 flex overflow-hidden shadow-inner">
<!-- Linker helft licht -->
<div class="w-1/2 bg-slate-100 p-2 flex flex-col justify-between border-r border-slate-200">
<div class="flex space-x-1">
<span class="w-1.5 h-1.5 rounded-full bg-slate-300"></span>
<span class="w-1.5 h-1.5 rounded-full bg-slate-300"></span>
</div>
<div class="h-2 w-3/4 bg-emerald-600/50 rounded"></div>
<div class="h-2 w-1/2 bg-slate-300 rounded"></div>
</div>
<!-- Rechter helft donker -->
<div class="w-1/2 bg-slate-950 p-2 flex flex-col justify-between">
<div class="flex justify-end space-x-1">
<span class="w-1.5 h-1.5 rounded-full bg-slate-700"></span>
<span class="w-1.5 h-1.5 rounded-full bg-slate-700"></span>
</div>
<div class="h-2 w-3/4 bg-emerald-400/50 rounded"></div>
<div class="h-2 w-1/2 bg-slate-800 rounded"></div>
</div>
</div>
<div>
<div class="flex items-center justify-between">
<span class="text-sm font-bold text-slate-900 dark:text-white flex items-center space-x-1.5">
<i data-lucide="laptop" class="w-4 h-4 text-blue-500"></i>
<span>Systeem Volgen</span>
</span>
<span id="themeCheck-system" class="theme-check hidden w-5 h-5 rounded-full bg-emerald-500 text-slate-950 items-center justify-center">
<i data-lucide="check" class="w-3.5 h-3.5 stroke-[3]"></i>
</span>
</div>
<p class="text-[11px] text-slate-500 dark:text-slate-400 mt-1 leading-relaxed">
Schakelt automatisch mee met uw Windows, macOS of browser voorkeur.
</p>
</div>
</button>
</div>
</div>
<!-- Sectie 1: Mijn Microsoft 365 Outlook Agenda -->
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl 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 items-center space-x-3.5">
<div class="w-12 h-12 rounded-2xl bg-blue-500/10 border border-blue-500/20 flex items-center justify-center text-blue-600 dark:text-blue-400 font-bold shadow-sm">
<i data-lucide="calendar" class="w-6 h-6"></i>
</div>
<div>
<div class="flex items-center space-x-2">
<h2 class="text-lg font-bold text-white tracking-tight">Mijn Microsoft 365 Agenda</h2>
<h2 class="text-lg font-bold text-slate-900 dark:text-white tracking-tight">Mijn Microsoft 365 Agenda</h2>
<?php if ($isOutlookConnected): ?>
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/15 border border-emerald-500/30 text-emerald-400 text-[10px] font-bold flex items-center space-x-1">
<span class="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse"></span>
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/15 border border-emerald-500/30 text-emerald-700 dark:text-emerald-400 text-[10px] font-bold flex items-center space-x-1">
<span class="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse"></span>
<span>Live Verbonden</span>
</span>
<?php else: ?>
<span class="px-2.5 py-0.5 rounded-full bg-slate-800 text-slate-400 text-[10px] font-bold">
<span class="px-2.5 py-0.5 rounded-full bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400 text-[10px] font-bold">
Niet Gekoppeld
</span>
<?php endif; ?>
</div>
<p class="text-xs text-slate-400">Synchroniseer uw agenda-afspraken automatisch met uw dagplanning</p>
<p class="text-xs text-slate-500 dark:text-slate-400">Synchroniseer uw agenda-afspraken automatisch met uw dagplanning</p>
</div>
</div>
<?php if ($isOutlookConnected): ?>
<div class="flex items-center space-x-2">
<a href="/auth/oauth_microsoft.php" class="px-3 py-1.5 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-300 text-xs font-medium transition" title="Opnieuw autoriseren bij Microsoft">
<a href="/auth/oauth_microsoft.php" class="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 border border-slate-200 dark:border-slate-700 text-xs font-medium transition" title="Opnieuw autoriseren bij Microsoft">
Opnieuw Verbinden
</a>
<form method="POST" onsubmit="return confirm('Weet u zeker dat u uw Microsoft Outlook agenda wilt ontkoppelen?');">
<input type="hidden" name="action" value="disconnect_outlook">
<button type="submit" class="px-3 py-1.5 rounded-xl bg-red-500/10 hover:bg-red-500/20 text-red-400 border border-red-500/20 text-xs font-medium transition">
<button type="submit" class="px-3 py-1.5 rounded-xl bg-red-500/10 hover:bg-red-500/20 text-red-600 dark:text-red-400 border border-red-500/20 text-xs font-medium transition">
Ontkoppelen
</button>
</form>
@@ -308,40 +446,40 @@ require_once __DIR__ . '/includes/header.php';
<div class="mt-6">
<?php if ($isOutlookConnected): ?>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div class="p-4 rounded-2xl bg-slate-950/60 border border-slate-800 space-y-1.5">
<span class="text-[10px] uppercase tracking-wider font-semibold text-slate-400 block">Gekoppeld Microsoft Account</span>
<span class="text-sm font-bold text-white block truncate"><?= htmlspecialchars($outlookSettings['account_name'] ?? 'Microsoft Gebruiker') ?></span>
<span class="text-xs text-emerald-400 block truncate"><?= htmlspecialchars($outlookSettings['account_email'] ?? $userProfile['email']) ?></span>
<div class="p-4 rounded-2xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800 space-y-1.5">
<span class="text-[10px] uppercase tracking-wider font-semibold text-slate-500 dark:text-slate-400 block">Gekoppeld Microsoft Account</span>
<span class="text-sm font-bold text-slate-900 dark:text-white block truncate"><?= htmlspecialchars($outlookSettings['account_name'] ?? 'Microsoft Gebruiker') ?></span>
<span class="text-xs text-emerald-600 dark:text-emerald-400 block truncate"><?= htmlspecialchars($outlookSettings['account_email'] ?? $userProfile['email']) ?></span>
</div>
<div class="p-4 rounded-2xl bg-slate-950/60 border border-slate-800 space-y-1.5">
<span class="text-[10px] uppercase tracking-wider font-semibold text-slate-400 block">Microsoft Teams Koppeling</span>
<span class="text-sm font-bold text-white flex items-center space-x-1.5">
<i data-lucide="video" class="w-4 h-4 text-blue-400"></i>
<div class="p-4 rounded-2xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800 space-y-1.5">
<span class="text-[10px] uppercase tracking-wider font-semibold text-slate-500 dark:text-slate-400 block">Microsoft Teams Koppeling</span>
<span class="text-sm font-bold text-slate-900 dark:text-white flex items-center space-x-1.5">
<i data-lucide="video" class="w-4 h-4 text-blue-500"></i>
<span>Automatische Meeting Links</span>
</span>
<span class="text-xs text-slate-400 block">Vergaderlinks in uw agenda worden direct klikbaar in uw dagplanning</span>
<span class="text-xs text-slate-500 dark:text-slate-400 block">Vergaderlinks in uw agenda worden direct klikbaar in uw dagplanning</span>
</div>
</div>
<div class="mt-4 p-3.5 rounded-2xl bg-emerald-500/10 border border-emerald-500/20 text-emerald-300 text-xs flex items-center justify-between">
<div class="mt-4 p-3.5 rounded-2xl bg-emerald-500/10 border border-emerald-500/20 text-emerald-800 dark:text-emerald-300 text-xs flex items-center justify-between">
<div class="flex items-center space-x-2">
<i data-lucide="check-circle" class="w-4 h-4 text-emerald-400 flex-shrink-0"></i>
<span>Uw agenda synchroniseert live. Afspraken van vandaag verschijnen direct in uw <a href="/planner.php" class="underline font-semibold text-white">Dagplanning</a>.</span>
<i data-lucide="check-circle" class="w-4 h-4 text-emerald-600 dark:text-emerald-400 flex-shrink-0"></i>
<span>Uw agenda synchroniseert live. Afspraken van vandaag verschijnen direct in uw <a href="/planner.php" class="underline font-semibold text-slate-900 dark:text-white">Dagplanning</a>.</span>
</div>
<a href="/planner.php" class="px-3 py-1 rounded-lg bg-emerald-500/20 hover:bg-emerald-500/30 text-emerald-200 font-semibold text-xs transition flex-shrink-0">
<a href="/planner.php" class="px-3 py-1 rounded-lg bg-emerald-500/20 hover:bg-emerald-500/30 text-emerald-800 dark:text-emerald-200 font-semibold text-xs transition flex-shrink-0">
Naar Dagplanning &rarr;
</a>
</div>
<?php else: ?>
<div class="p-6 rounded-2xl bg-slate-950/60 border border-slate-800 text-center space-y-4">
<div class="w-14 h-14 rounded-2xl bg-blue-500/10 border border-blue-500/20 text-blue-400 flex items-center justify-center mx-auto">
<div class="p-6 rounded-2xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800 text-center space-y-4">
<div class="w-14 h-14 rounded-2xl bg-blue-500/10 border border-blue-500/20 text-blue-600 dark:text-blue-400 flex items-center justify-center mx-auto">
<i data-lucide="calendar-plus" class="w-7 h-7"></i>
</div>
<div class="max-w-md mx-auto space-y-1">
<h3 class="text-base font-bold text-white">Verbind uw Microsoft Outlook Agenda</h3>
<p class="text-xs text-slate-400 leading-relaxed">
<h3 class="text-base font-bold text-slate-900 dark:text-white">Verbind uw Microsoft Outlook Agenda</h3>
<p class="text-xs text-slate-500 dark:text-slate-400 leading-relaxed">
Krijg uw dagelijkse afspraken automatisch te zien in Fociz en ontvang herinneringen vóórdat uw vergaderingen beginnen.
</p>
</div>
@@ -350,7 +488,7 @@ require_once __DIR__ . '/includes/header.php';
<div>
<form method="POST">
<input type="hidden" name="action" value="connect_outlook">
<button type="submit" class="inline-flex items-center space-x-2 px-6 py-3 rounded-xl bg-blue-600 hover:bg-blue-500 text-white font-bold text-xs transition shadow-xl shadow-blue-500/25">
<button type="submit" class="inline-flex items-center space-x-2 px-6 py-3 rounded-xl bg-blue-600 hover:bg-blue-500 text-white font-bold text-xs transition shadow-xl shadow-blue-500/25 cursor-pointer">
<i data-lucide="log-in" class="w-4 h-4"></i>
<span>Koppel Mijn Outlook Agenda</span>
</button>
@@ -358,11 +496,11 @@ require_once __DIR__ . '/includes/header.php';
<span class="text-[11px] text-slate-500 block mt-2">U wordt veilig doorgestuurd naar Microsoft om in te loggen</span>
</div>
<?php else: ?>
<div class="p-3.5 rounded-xl bg-amber-500/10 border border-amber-500/30 text-amber-300 text-xs max-w-lg mx-auto">
<i data-lucide="alert-circle" class="w-4 h-4 text-amber-400 inline mr-1 -mt-0.5"></i>
<div class="p-3.5 rounded-xl bg-amber-500/10 border border-amber-500/30 text-amber-800 dark:text-amber-300 text-xs max-w-lg mx-auto">
<i data-lucide="alert-circle" class="w-4 h-4 text-amber-500 inline mr-1 -mt-0.5"></i>
Microsoft 365 koppeling is nog niet geconfigureerd door de beheerder.
<?php if ($userProfile['role'] === 'ADMIN'): ?>
<a href="/admin.php" class="underline font-bold text-white ml-1">Stel Azure in via Systeembeheer &rarr;</a>
<a href="/admin.php" class="underline font-bold text-slate-900 dark:text-white ml-1">Stel Azure in via Systeembeheer &rarr;</a>
<?php else: ?>
Vraag uw beheerder om dit in te schakelen.
<?php endif; ?>
@@ -374,33 +512,33 @@ require_once __DIR__ . '/includes/header.php';
</div>
<!-- Sectie 2: Mijn Atlassian Jira Koppeling -->
<div class="bg-slate-900/80 border border-slate-800 rounded-3xl p-6 sm:p-7 shadow-xl">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-6 border-b border-slate-800/80">
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl 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 items-center space-x-3.5">
<div class="w-12 h-12 rounded-2xl bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center text-indigo-400 font-bold shadow-md">
<div class="w-12 h-12 rounded-2xl bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center text-indigo-600 dark:text-indigo-400 font-bold shadow-sm">
<i data-lucide="check-square" class="w-6 h-6"></i>
</div>
<div>
<div class="flex items-center space-x-2">
<h2 class="text-lg font-bold text-white tracking-tight">Mijn Atlassian Jira Koppeling</h2>
<h2 class="text-lg font-bold text-slate-900 dark:text-white tracking-tight">Mijn Atlassian Jira Koppeling</h2>
<?php if ($isJiraConnected): ?>
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/15 border border-emerald-500/30 text-emerald-400 text-[10px] font-bold">
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/15 border border-emerald-500/30 text-emerald-700 dark:text-emerald-400 text-[10px] font-bold">
Verbonden
</span>
<?php else: ?>
<span class="px-2.5 py-0.5 rounded-full bg-slate-800 text-slate-400 text-[10px] font-bold">
<span class="px-2.5 py-0.5 rounded-full bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400 text-[10px] font-bold">
Niet Gekoppeld
</span>
<?php endif; ?>
</div>
<p class="text-xs text-slate-400">Importeer uw toegewezen Jira issues direct naar uw dagelijkse takenlijst</p>
<p class="text-xs text-slate-500 dark:text-slate-400">Importeer uw toegewezen Jira issues direct naar uw dagelijkse takenlijst</p>
</div>
</div>
<?php if ($isJiraConnected): ?>
<form method="POST" onsubmit="return confirm('Weet u zeker dat u Jira wilt ontkoppelen?');">
<input type="hidden" name="action" value="disconnect_jira">
<button type="submit" class="px-3 py-1.5 rounded-xl bg-red-500/10 hover:bg-red-500/20 text-red-400 border border-red-500/20 text-xs font-medium transition">
<button type="submit" class="px-3 py-1.5 rounded-xl bg-red-500/10 hover:bg-red-500/20 text-red-600 dark:text-red-400 border border-red-500/20 text-xs font-medium transition">
Jira Ontkoppelen
</button>
</form>
@@ -412,34 +550,34 @@ require_once __DIR__ . '/includes/header.php';
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label class="block text-xs font-semibold text-slate-300 mb-1.5">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5">
Jira Cloud Domein
</label>
<input type="text" name="jira_domain" value="<?= htmlspecialchars($activeJiraDomain) ?>" placeholder="https://uwbedrijf.atlassian.net" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-white placeholder-slate-600 focus:outline-none focus:border-indigo-500 font-mono">
<input type="text" name="jira_domain" value="<?= htmlspecialchars($activeJiraDomain) ?>" placeholder="https://uwbedrijf.atlassian.net" class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-600 focus:outline-none focus:border-indigo-500 font-mono">
<span class="text-[10px] text-slate-500 mt-1 block">Standaard ingevuld door beheerder indien beschikbaar</span>
</div>
<div>
<label class="block text-xs font-semibold text-slate-300 mb-1.5">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5">
Uw Jira E-mailadres
</label>
<input type="email" name="jira_email" value="<?= htmlspecialchars($jiraSettings['jira_email'] ?? $userProfile['email']) ?>" placeholder="naam@bedrijf.nl" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-white placeholder-slate-600 focus:outline-none focus:border-indigo-500">
<input type="email" name="jira_email" value="<?= htmlspecialchars($jiraSettings['jira_email'] ?? $userProfile['email']) ?>" placeholder="naam@bedrijf.nl" class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-600 focus:outline-none focus:border-indigo-500">
</div>
</div>
<div>
<div class="flex items-center justify-between mb-1.5">
<label class="text-xs font-semibold text-slate-300">
<label class="text-xs font-semibold text-slate-700 dark:text-slate-300">
Persoonlijk Atlassian API Token
</label>
<a href="https://id.atlassian.com/manage-profile/security/api-tokens" target="_blank" rel="noopener noreferrer" class="text-[10px] text-indigo-400 hover:underline flex items-center space-x-1">
<a href="https://id.atlassian.com/manage-profile/security/api-tokens" target="_blank" rel="noopener noreferrer" class="text-[10px] text-indigo-600 dark:text-indigo-400 hover:underline flex items-center space-x-1">
<span>API Token Aanmaken</span>
<i data-lucide="external-link" class="w-3 h-3"></i>
</a>
</div>
<div class="relative">
<input type="password" id="jiraApiTokenInput" name="jira_api_token" value="<?= !empty($jiraSettings['jira_api_token']) ? '••••••••••••••••' : '' ?>" placeholder="Plak hier uw Atlassian API token..." class="w-full bg-slate-950 border border-slate-800 rounded-xl pl-3.5 pr-10 py-2.5 text-xs text-white placeholder-slate-600 focus:outline-none focus:border-indigo-500">
<button type="button" onclick="toggleJiraToken()" class="absolute inset-y-0 right-0 pr-3 flex items-center text-slate-500 hover:text-slate-300">
<input type="password" id="jiraApiTokenInput" name="jira_api_token" value="<?= !empty($jiraSettings['jira_api_token']) ? '••••••••••••••••' : '' ?>" placeholder="Plak hier uw Atlassian API token..." class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl pl-3.5 pr-10 py-2.5 text-xs text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-600 focus:outline-none focus:border-indigo-500">
<button type="button" onclick="toggleJiraToken()" class="absolute inset-y-0 right-0 pr-3 flex items-center text-slate-400 hover:text-slate-600 dark:hover:text-slate-300">
<i data-lucide="eye" class="w-4 h-4" id="eyeJiraIcon"></i>
</button>
</div>
@@ -447,12 +585,12 @@ require_once __DIR__ . '/includes/header.php';
<div class="pt-2 flex items-center justify-between">
<?php if ($isJiraConnected && !empty($jiraSettings['account_name'])): ?>
<span class="text-xs text-emerald-400 flex items-center space-x-1.5">
<span class="text-xs text-emerald-600 dark:text-emerald-400 flex items-center space-x-1.5">
<i data-lucide="check" class="w-4 h-4"></i>
<span>Verbonden als: <strong><?= htmlspecialchars($jiraSettings['account_name']) ?></strong></span>
</span>
<?php else: ?>
<span class="text-[11px] text-slate-400">Verbinding wordt automatisch gevalideerd bij het opslaan</span>
<span class="text-[11px] text-slate-500 dark:text-slate-400">Verbinding wordt automatisch gevalideerd bij het opslaan</span>
<?php endif; ?>
<button type="submit" class="px-5 py-2.5 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-bold transition shadow-lg shadow-indigo-500/20">
@@ -463,39 +601,39 @@ require_once __DIR__ . '/includes/header.php';
</div>
<!-- Sectie 3: Mijn Meldingen & Agenda Push Notificaties -->
<div class="bg-slate-900/80 border border-slate-800 rounded-3xl p-6 sm:p-7 shadow-xl">
<div class="flex items-center space-x-3.5 pb-6 border-b border-slate-800/80">
<div class="w-12 h-12 rounded-2xl bg-emerald-500/10 border border-emerald-500/20 flex items-center justify-center text-emerald-400 font-bold shadow-md">
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl transition">
<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-emerald-500/10 border border-emerald-500/20 flex items-center justify-center text-emerald-600 dark:text-emerald-400 font-bold shadow-sm">
<i data-lucide="bell" class="w-6 h-6"></i>
</div>
<div>
<h2 class="text-lg font-bold text-white tracking-tight">Mijn Meldingen & Agenda Herinneringen</h2>
<p class="text-xs text-slate-400">Krijg realtime meldingen vanuit uw browser zodra een afspraak nadert</p>
<h2 class="text-lg font-bold text-slate-900 dark:text-white tracking-tight">Mijn Meldingen & Agenda Herinneringen</h2>
<p class="text-xs text-slate-500 dark:text-slate-400">Krijg realtime meldingen vanuit uw browser zodra een afspraak nadert</p>
</div>
</div>
<div class="mt-6 space-y-5">
<!-- Browser Permissie Banner in Profiel -->
<div id="profileNotifPermGranted" class="hidden p-4 rounded-2xl bg-emerald-500/10 border border-emerald-500/30 text-emerald-300 flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<div id="profileNotifPermGranted" class="hidden p-4 rounded-2xl bg-emerald-500/10 border border-emerald-500/30 text-emerald-800 dark:text-emerald-300 flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<div class="flex items-center space-x-2.5">
<i data-lucide="check-circle" class="w-5 h-5 text-emerald-400 flex-shrink-0"></i>
<i data-lucide="check-circle" class="w-5 h-5 text-emerald-600 dark:text-emerald-400 flex-shrink-0"></i>
<div>
<strong class="block text-xs text-white">Browser Pushberichten zijn Actief</strong>
<span class="text-[11px] text-emerald-300/80">Uw browser heeft toestemming om bureaubladmeldingen weer te geven.</span>
<strong class="block text-xs text-slate-900 dark:text-white">Browser Pushberichten zijn Actief</strong>
<span class="text-[11px] text-emerald-700 dark:text-emerald-300/80">Uw browser heeft toestemming om bureaubladmeldingen weer te geven.</span>
</div>
</div>
<button type="button" onclick="focizTestNotification()" class="px-3 py-1.5 rounded-xl bg-emerald-500/20 hover:bg-emerald-500/30 text-emerald-300 font-bold text-xs transition flex items-center space-x-1.5 flex-shrink-0">
<button type="button" onclick="focizTestNotification()" class="px-3 py-1.5 rounded-xl bg-emerald-500/20 hover:bg-emerald-500/30 text-emerald-800 dark:text-emerald-300 font-bold text-xs transition flex items-center space-x-1.5 flex-shrink-0">
<i data-lucide="send" class="w-3.5 h-3.5"></i>
<span>Verzend Test Melding</span>
</button>
</div>
<div id="profileNotifPermRequest" class="p-4 rounded-2xl bg-blue-500/10 border border-blue-500/30 text-blue-200 flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<div id="profileNotifPermRequest" class="p-4 rounded-2xl bg-blue-500/10 border border-blue-500/30 text-blue-800 dark:text-blue-200 flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<div class="flex items-center space-x-2.5">
<i data-lucide="bell-ring" class="w-5 h-5 text-blue-400 flex-shrink-0"></i>
<i data-lucide="bell-ring" class="w-5 h-5 text-blue-600 dark:text-blue-400 flex-shrink-0"></i>
<div>
<strong class="block text-xs text-white">Toestemming van Browser Vereist</strong>
<span class="text-[11px] text-blue-300/80">Klik op de knop om pushmeldingen in te schakelen voor Fociz.</span>
<strong class="block text-xs text-slate-900 dark:text-white">Toestemming van Browser Vereist</strong>
<span class="text-[11px] text-blue-700 dark:text-blue-300/80">Klik op de knop om pushmeldingen in te schakelen voor Fociz.</span>
</div>
</div>
<button type="button" onclick="focizRequestPermission()" class="px-4 py-2 rounded-xl bg-blue-600 hover:bg-blue-500 text-white font-bold text-xs transition shadow flex-shrink-0">
@@ -503,31 +641,31 @@ require_once __DIR__ . '/includes/header.php';
</button>
</div>
<div id="profileNotifPermDenied" class="hidden p-4 rounded-2xl bg-red-500/10 border border-red-500/30 text-red-300 text-xs leading-relaxed">
<i data-lucide="alert-triangle" class="w-4 h-4 text-red-400 inline mr-1 -mt-0.5"></i>
<div id="profileNotifPermDenied" class="hidden p-4 rounded-2xl bg-red-500/10 border border-red-500/30 text-red-800 dark:text-red-300 text-xs leading-relaxed">
<i data-lucide="alert-triangle" class="w-4 h-4 text-red-600 dark:text-red-400 inline mr-1 -mt-0.5"></i>
Meldingen zijn momenteel geblokkeerd in uw browser. Klik links in de adresbalk op het slotje/site-instellingen en zet "Meldingen" op "Toestaan".
</div>
<form method="POST" class="space-y-4">
<input type="hidden" name="action" value="save_notifications">
<div class="flex items-center justify-between p-4 rounded-2xl bg-slate-950/60 border border-slate-800">
<div class="flex items-center justify-between p-4 rounded-2xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800">
<div>
<span class="text-xs font-bold text-white block">Meldingen Actief</span>
<span class="text-[11px] text-slate-400">Automatisch waarschuwen bij naderende afspraken</span>
<span class="text-xs font-bold text-slate-900 dark:text-white block">Meldingen Actief</span>
<span class="text-[11px] text-slate-500 dark:text-slate-400">Automatisch waarschuwen bij naderende afspraken</span>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" name="notif_enabled" <?= !empty($notifSettings['enabled']) ? 'checked' : '' ?> class="sr-only peer">
<div class="w-11 h-6 bg-slate-800 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-slate-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-emerald-600"></div>
<div class="w-11 h-6 bg-slate-300 dark:bg-slate-800 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-slate-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-emerald-600"></div>
</label>
</div>
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div>
<label class="block text-xs font-semibold text-slate-300 mb-1.5">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5">
Vooraankondiging
</label>
<select name="lead_time_minutes" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-white focus:outline-none focus:border-emerald-500">
<select name="lead_time_minutes" class="w-full bg-white dark:bg-slate-950 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:border-emerald-500">
<option value="0" <?= (int)$notifSettings['lead_time_minutes'] === 0 ? 'selected' : '' ?>>0 minuten (Precies op aanvang)</option>
<option value="2" <?= (int)$notifSettings['lead_time_minutes'] === 2 ? 'selected' : '' ?>>2 minuten van tevoren</option>
<option value="5" <?= (int)$notifSettings['lead_time_minutes'] === 5 ? 'selected' : '' ?>>5 minuten van tevoren (Aanbevolen)</option>
@@ -538,10 +676,10 @@ require_once __DIR__ . '/includes/header.php';
</div>
<div>
<label class="block text-xs font-semibold text-slate-300 mb-1.5">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5">
Aantal herhalingen
</label>
<select name="repeat_count" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-white focus:outline-none focus:border-emerald-500">
<select name="repeat_count" class="w-full bg-white dark:bg-slate-950 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:border-emerald-500">
<option value="1" <?= (int)$notifSettings['repeat_count'] === 1 ? 'selected' : '' ?>>1x (Alleen eerste melding)</option>
<option value="2" <?= (int)$notifSettings['repeat_count'] === 2 ? 'selected' : '' ?>>2x herhalen (Aanbevolen)</option>
<option value="3" <?= (int)$notifSettings['repeat_count'] === 3 ? 'selected' : '' ?>>3x herhalen</option>
@@ -550,10 +688,10 @@ require_once __DIR__ . '/includes/header.php';
</div>
<div>
<label class="block text-xs font-semibold text-slate-300 mb-1.5">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5">
Herhalingsinterval
</label>
<select name="repeat_interval_minutes" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-white focus:outline-none focus:border-emerald-500">
<select name="repeat_interval_minutes" class="w-full bg-white dark:bg-slate-950 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:border-emerald-500">
<option value="1" <?= (int)$notifSettings['repeat_interval_minutes'] === 1 ? 'selected' : '' ?>>Elke 1 minuut</option>
<option value="2" <?= (int)$notifSettings['repeat_interval_minutes'] === 2 ? 'selected' : '' ?>>Elke 2 minuten</option>
<option value="3" <?= (int)$notifSettings['repeat_interval_minutes'] === 3 ? 'selected' : '' ?>>Elke 3 minuten</option>
@@ -562,22 +700,22 @@ require_once __DIR__ . '/includes/header.php';
</div>
</div>
<div class="flex items-center justify-between p-4 rounded-2xl bg-slate-950/60 border border-slate-800">
<div class="flex items-center justify-between p-4 rounded-2xl bg-slate-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800">
<div class="flex items-center space-x-2.5">
<i data-lucide="volume-2" class="w-4 h-4 text-emerald-400"></i>
<i data-lucide="volume-2" class="w-4 h-4 text-emerald-600 dark:text-emerald-400"></i>
<div>
<span class="text-xs font-bold text-white block">Subtiel Geluidssignaal</span>
<span class="text-[11px] text-slate-400">Speel een zachte chime af bij binnenkomst van de herinnering</span>
<span class="text-xs font-bold text-slate-900 dark:text-white block">Subtiel Geluidssignaal</span>
<span class="text-[11px] text-slate-500 dark:text-slate-400">Speel een zachte chime af bij binnenkomst van de herinnering</span>
</div>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" name="sound_enabled" <?= !empty($notifSettings['sound_enabled']) ? 'checked' : '' ?> class="sr-only peer">
<div class="w-11 h-6 bg-slate-800 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-slate-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-emerald-600"></div>
<div class="w-11 h-6 bg-slate-300 dark:bg-slate-800 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-slate-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-emerald-600"></div>
</label>
</div>
<div class="flex justify-end pt-2">
<button type="submit" class="px-5 py-2.5 rounded-xl bg-emerald-600 hover:bg-emerald-500 text-slate-950 text-xs font-bold transition shadow-lg shadow-emerald-600/20">
<button type="submit" class="px-5 py-2.5 rounded-xl bg-emerald-600 hover:bg-emerald-500 text-white dark:text-slate-950 text-xs font-bold transition shadow-lg shadow-emerald-600/20">
Notificatievoorkeuren Opslaan
</button>
</div>
@@ -588,32 +726,32 @@ require_once __DIR__ . '/includes/header.php';
<!-- Sectie 4: Account & Beveiliging (Wachtwoord & 2FA) -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<!-- Profielnaam formulier -->
<div class="bg-slate-900/80 border border-slate-800 rounded-3xl p-6 sm:p-7 shadow-xl space-y-4">
<div class="flex items-center space-x-3 pb-4 border-b border-slate-800/80">
<i data-lucide="user" class="w-5 h-5 text-emerald-400"></i>
<h3 class="text-base font-bold text-white">Persoonlijke Gegevens</h3>
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl space-y-4 transition">
<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-5 h-5 text-emerald-600 dark:text-emerald-400"></i>
<h3 class="text-base font-bold text-slate-900 dark:text-white">Persoonlijke Gegevens</h3>
</div>
<form method="POST" class="space-y-4">
<input type="hidden" name="action" value="update_profile">
<div>
<label class="block text-xs font-semibold text-slate-300 mb-1.5">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5">
Weergavenaam
</label>
<input type="text" name="name" required value="<?= htmlspecialchars($userProfile['name']) ?>" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-white focus:outline-none focus:border-emerald-500">
<input type="text" name="name" required value="<?= htmlspecialchars($userProfile['name']) ?>" class="w-full bg-white dark:bg-slate-950 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:border-emerald-500">
</div>
<div>
<label class="block text-xs font-semibold 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
</label>
<input type="email" readonly disabled value="<?= htmlspecialchars($userProfile['email']) ?>" class="w-full bg-slate-950/50 border border-slate-800/60 rounded-xl px-3.5 py-2.5 text-xs text-slate-500 cursor-not-allowed">
<input type="email" readonly disabled value="<?= htmlspecialchars($userProfile['email']) ?>" class="w-full bg-slate-100 dark:bg-slate-950/50 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>
</div>
<div class="flex justify-end pt-2">
<button type="submit" class="px-4 py-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-white text-xs font-semibold transition border border-slate-700">
<button type="submit" class="px-4 py-2 rounded-xl bg-slate-900 hover:bg-slate-800 text-white dark:bg-slate-800 dark:hover:bg-slate-700 dark:text-white text-xs font-semibold transition border border-slate-900 dark:border-slate-700 shadow-sm">
Naam Opslaan
</button>
</div>
@@ -621,38 +759,38 @@ require_once __DIR__ . '/includes/header.php';
</div>
<!-- Wachtwoord Wijzigen Formulier -->
<div class="bg-slate-900/80 border border-slate-800 rounded-3xl p-6 sm:p-7 shadow-xl space-y-4">
<div class="flex items-center space-x-3 pb-4 border-b border-slate-800/80">
<i data-lucide="key" class="w-5 h-5 text-emerald-400"></i>
<h3 class="text-base font-bold text-white">Wachtwoord Wijzigen</h3>
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl space-y-4 transition">
<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-5 h-5 text-emerald-600 dark:text-emerald-400"></i>
<h3 class="text-base font-bold text-slate-900 dark:text-white">Wachtwoord Wijzigen</h3>
</div>
<form method="POST" class="space-y-3">
<input type="hidden" name="action" value="change_password">
<div>
<label class="block text-xs font-semibold text-slate-300 mb-1">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">
Huidig Wachtwoord
</label>
<input type="password" name="current_password" required class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2 text-xs text-white focus:outline-none focus:border-emerald-500">
<input type="password" name="current_password" required class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl px-3.5 py-2 text-xs text-slate-900 dark:text-white focus:outline-none focus:border-emerald-500">
</div>
<div>
<label class="block text-xs font-semibold text-slate-300 mb-1">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">
Nieuw Wachtwoord (min. 8 tekens)
</label>
<input type="password" name="new_password" required minlength="8" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2 text-xs text-white focus:outline-none focus:border-emerald-500">
<input type="password" name="new_password" required minlength="8" class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl px-3.5 py-2 text-xs text-slate-900 dark:text-white focus:outline-none focus:border-emerald-500">
</div>
<div>
<label class="block text-xs font-semibold text-slate-300 mb-1">
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">
Bevestig Nieuw Wachtwoord
</label>
<input type="password" name="confirm_password" required minlength="8" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2 text-xs text-white focus:outline-none focus:border-emerald-500">
<input type="password" name="confirm_password" required minlength="8" class="w-full bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-800 rounded-xl px-3.5 py-2 text-xs text-slate-900 dark:text-white focus:outline-none focus:border-emerald-500">
</div>
<div class="flex justify-end pt-2">
<button type="submit" class="px-4 py-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-white text-xs font-semibold transition border border-slate-700">
<button type="submit" class="px-4 py-2 rounded-xl bg-slate-900 hover:bg-slate-800 text-white dark:bg-slate-800 dark:hover:bg-slate-700 dark:text-white text-xs font-semibold transition border border-slate-900 dark:border-slate-700 shadow-sm">
Wachtwoord Wijzigen
</button>
</div>
@@ -662,6 +800,39 @@ require_once __DIR__ . '/includes/header.php';
</div>
<script>
// --- Thema Selector Functionaliteit ---
function selectThemePreference(theme) {
if (typeof focizSetTheme === 'function') {
focizSetTheme(theme, true);
}
updateProfileThemeUI(theme);
}
function updateProfileThemeUI(theme) {
const themes = ['dark', 'light', 'system'];
themes.forEach(t => {
const btn = document.getElementById('themeBtn-' + t);
const check = document.getElementById('themeCheck-' + t);
if (!btn || !check) return;
if (t === theme) {
btn.classList.add('ring-2', 'ring-emerald-500', 'border-emerald-500');
check.classList.remove('hidden');
check.classList.add('flex');
} else {
btn.classList.remove('ring-2', 'ring-emerald-500', 'border-emerald-500');
check.classList.add('hidden');
check.classList.remove('flex');
}
});
const badge = document.getElementById('themeStatusBadge');
if (badge) {
const label = theme.charAt(0).toUpperCase() + theme.slice(1);
badge.innerText = 'Actief: ' + label;
}
}
function toggleJiraToken() {
const input = document.getElementById('jiraApiTokenInput');
const icon = document.getElementById('eyeJiraIcon');
@@ -676,8 +847,13 @@ function toggleJiraToken() {
if (window.lucide) lucide.createIcons();
}
// Sync banner status met browser permissie
// Sync banner status met browser permissie & activeer actuele thema kaart
document.addEventListener('DOMContentLoaded', () => {
// Initialiseer geselecteerde thema-kaart
const activeTheme = localStorage.getItem('fociz_theme') || '<?= $userTheme ?>' || 'dark';
updateProfileThemeUI(activeTheme);
// Permissie status
if (!("Notification" in window)) return;
const grantedEl = document.getElementById('profileNotifPermGranted');
const reqEl = document.getElementById('profileNotifPermRequest');
@@ -700,4 +876,3 @@ document.addEventListener('DOMContentLoaded', () => {
</script>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
+57 -58
View File
@@ -35,37 +35,37 @@ $roadmapItems = $stmt->fetchAll();
$quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
?>
<div class="space-y-6">
<div class="space-y-6 max-w-7xl mx-auto">
<!-- Header -->
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 bg-slate-900/80 border border-slate-800 rounded-2xl p-6 shadow-xl">
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl transition">
<div>
<div class="flex items-center space-x-2 text-emerald-400 text-xs font-semibold uppercase tracking-wider mb-1">
<div class="flex items-center space-x-2 text-emerald-600 dark:text-emerald-400 text-xs font-bold uppercase tracking-wider mb-1">
<i data-lucide="map" class="w-4 h-4"></i>
<span>Planning & Strategie</span>
</div>
<h1 class="text-2xl sm:text-3xl font-black text-white tracking-tight">
<h1 class="text-2xl sm:text-3xl font-black text-slate-900 dark:text-white tracking-tight">
Roadmap & Tijdlijn
</h1>
<p class="text-slate-400 text-xs sm:text-sm mt-1">
<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.
</p>
</div>
<button onclick="document.getElementById('newItemModal').classList.remove('hidden')" class="flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-emerald-500 hover:bg-emerald-600 text-slate-950 text-xs font-bold transition shadow-lg shadow-emerald-500/20 flex-shrink-0">
<button onclick="document.getElementById('newItemModal').classList.remove('hidden')" class="flex items-center space-x-2 px-4 py-2.5 rounded-xl bg-emerald-500 hover:bg-emerald-600 text-slate-950 text-xs font-bold transition shadow-lg shadow-emerald-500/20 flex-shrink-0 cursor-pointer">
<i data-lucide="plus" class="w-4 h-4"></i>
<span>Nieuw Item</span>
</button>
</div>
<!-- Filters: Quarters & Status -->
<div class="flex flex-wrap items-center justify-between gap-3 bg-slate-900/40 border border-slate-800/80 rounded-2xl p-4">
<div class="flex flex-wrap items-center justify-between gap-3 bg-white dark:bg-slate-900/40 border border-slate-200 dark:border-slate-800/80 rounded-2xl p-4 shadow-sm transition">
<!-- Quarter Tabs -->
<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-xl transition font-medium <?= $selectedQuarter === 'ALL' ? 'bg-emerald-500 text-slate-950 font-bold' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800' ?>">
<a href="/roadmap.php?quarter=ALL&status=<?= htmlspecialchars($selectedStatus) ?>" class="px-3 py-1.5 rounded-xl transition font-medium <?= $selectedQuarter === 'ALL' ? 'bg-emerald-500 text-slate-950 font-bold shadow-sm' : '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
</a>
<?php foreach ($quarters as $q): ?>
<a href="/roadmap.php?quarter=<?= $q ?>&status=<?= htmlspecialchars($selectedStatus) ?>" class="px-3 py-1.5 rounded-xl transition font-medium <?= $selectedQuarter === $q ? 'bg-emerald-500 text-slate-950 font-bold' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-800' ?>">
<a href="/roadmap.php?quarter=<?= $q ?>&status=<?= htmlspecialchars($selectedStatus) ?>" class="px-3 py-1.5 rounded-xl transition font-medium <?= $selectedQuarter === $q ? 'bg-emerald-500 text-slate-950 font-bold shadow-sm' : '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 ?>
</a>
<?php endforeach; ?>
@@ -73,8 +73,8 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
<!-- Status Filter -->
<div class="flex items-center space-x-2 text-xs">
<span class="text-slate-500">Status:</span>
<select onchange="window.location.href='/roadmap.php?quarter=<?= htmlspecialchars($selectedQuarter) ?>&status='+this.value" class="bg-slate-800 border border-slate-700 rounded-xl px-2.5 py-1 text-white text-xs focus:outline-none">
<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 dark:bg-slate-800 border border-slate-300 dark:border-slate-700 rounded-xl px-2.5 py-1 text-slate-900 dark:text-white text-xs focus:outline-none">
<option value="ALL" <?= $selectedStatus === 'ALL' ? 'selected' : '' ?>>Alle Statussen</option>
<option value="PLANNED" <?= $selectedStatus === 'PLANNED' ? 'selected' : '' ?>>Gepland</option>
<option value="IN_PROGRESS" <?= $selectedStatus === 'IN_PROGRESS' ? 'selected' : '' ?>>In Uitvoering</option>
@@ -87,38 +87,38 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
<!-- Roadmap Items Lijst -->
<div class="space-y-4">
<?php if (empty($roadmapItems)): ?>
<div class="bg-slate-900/60 border border-slate-800/80 rounded-2xl p-12 text-center">
<div class="bg-white dark:bg-slate-900/60 border border-slate-200 dark:border-slate-800/80 rounded-3xl p-12 text-center shadow-sm">
<i data-lucide="map-pin" class="w-12 h-12 text-emerald-500/40 mx-auto mb-3"></i>
<h3 class="text-base font-bold text-white">Geen items gevonden op de roadmap</h3>
<p class="text-xs text-slate-400 mt-1 max-w-sm mx-auto">
Ga naar een <a href="/brainstorm.php" class="text-amber-400 underline">Brainstorm sessie</a> en zet ideeën met één klik om naar de roadmap, of voeg handmatig een item toe.
<h3 class="text-base font-bold 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">
Ga naar een <a href="/brainstorm.php" class="text-amber-600 dark:text-amber-400 underline font-semibold">Brainstorm sessie</a> en zet ideeën met één klik om naar de roadmap, of voeg handmatig een item toe.
</p>
</div>
<?php else: ?>
<?php foreach ($roadmapItems as $item): ?>
<div class="bg-slate-900/80 border border-slate-800 hover:border-slate-700 rounded-2xl p-5 shadow-lg transition space-y-3" id="roadmap-item-<?= $item['id'] ?>">
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 hover:border-slate-300 dark:hover:border-slate-700 rounded-3xl p-5 shadow-sm hover:shadow-md dark:shadow-lg transition space-y-3" id="roadmap-item-<?= $item['id'] ?>">
<!-- Top header van item -->
<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">
<!-- Quarter badge -->
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/15 text-emerald-400 font-mono text-xs font-bold border border-emerald-500/30">
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/15 text-emerald-700 dark:text-emerald-400 font-mono text-xs font-bold border border-emerald-500/30">
<?= htmlspecialchars($item['quarter']) ?>
</span>
<!-- Type badge -->
<span class="px-2 py-0.5 rounded-full bg-slate-800 text-slate-300 text-[10px] font-semibold">
<span class="px-2 py-0.5 rounded-full bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300 text-[10px] font-semibold">
<?= htmlspecialchars($item['type']) ?>
</span>
<!-- Priority badge -->
<span class="text-[10px] font-bold px-2 py-0.5 rounded-full <?= $item['priority'] === 'CRITICAL' ? 'bg-red-500/20 text-red-400' : ($item['priority'] === 'HIGH' ? 'bg-amber-500/20 text-amber-400' : 'bg-slate-800 text-slate-400') ?>">
<span class="text-[10px] font-bold px-2 py-0.5 rounded-full <?= $item['priority'] === 'CRITICAL' ? 'bg-red-500/15 text-red-700 dark:text-red-400 border border-red-500/30' : ($item['priority'] === 'HIGH' ? 'bg-amber-500/15 text-amber-700 dark:text-amber-400 border border-amber-500/30' : 'bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400') ?>">
<?= htmlspecialchars($item['priority']) ?>
</span>
<!-- Jira Issue Key link -->
<?php if (!empty($item['jira_issue_key'])): ?>
<a href="/profile.php" class="flex items-center space-x-1 px-2 py-0.5 rounded-full bg-blue-950/60 border border-blue-800/60 text-blue-300 text-[10px] font-mono hover:underline">
<a href="/profile.php" class="flex items-center space-x-1 px-2 py-0.5 rounded-full bg-blue-50 dark:bg-blue-950/60 border border-blue-200 dark:border-blue-800/60 text-blue-700 dark:text-blue-300 text-[10px] font-mono hover:underline">
<i data-lucide="layers" class="w-3 h-3"></i>
<span><?= htmlspecialchars($item['jira_issue_key']) ?></span>
</a>
@@ -127,14 +127,14 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
<!-- Status Selector -->
<div class="flex items-center space-x-2">
<select onchange="updateRoadmapStatus(<?= $item['id'] ?>, this.value)" class="bg-slate-950 border border-slate-700 rounded-lg px-2.5 py-1 text-xs text-slate-200 font-semibold focus:outline-none">
<select onchange="updateRoadmapStatus(<?= $item['id'] ?>, this.value)" class="bg-slate-50 dark:bg-slate-950 border border-slate-300 dark:border-slate-700 rounded-xl px-2.5 py-1 text-xs text-slate-800 dark:text-slate-200 font-semibold focus:outline-none">
<option value="PLANNED" <?= $item['status'] === 'PLANNED' ? 'selected' : '' ?>>⏳ Gepland</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="COMPLETED" <?= $item['status'] === 'COMPLETED' ? 'selected' : '' ?>>✅ Voltooid</option>
</select>
<button onclick="deleteRoadmapItem(<?= $item['id'] ?>)" title="Verwijderen" class="p-1.5 rounded-lg text-slate-600 hover:text-red-400 hover:bg-red-500/10 transition">
<button onclick="deleteRoadmapItem(<?= $item['id'] ?>)" title="Verwijderen" class="p-1.5 rounded-lg text-slate-400 hover:text-red-600 dark:text-slate-600 dark:hover:text-red-400 hover:bg-red-500/10 transition cursor-pointer">
<i data-lucide="trash-2" class="w-4 h-4"></i>
</button>
</div>
@@ -142,11 +142,11 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
<!-- Titel & Beschrijving -->
<div>
<h3 class="text-base font-bold text-white leading-snug">
<h3 class="text-base font-bold text-slate-900 dark:text-white leading-snug">
<?= htmlspecialchars($item['title']) ?>
</h3>
<?php if (!empty($item['description'])): ?>
<p class="text-slate-400 text-xs mt-1 whitespace-pre-wrap">
<p class="text-slate-600 dark:text-slate-400 text-xs mt-1 whitespace-pre-wrap leading-relaxed">
<?= htmlspecialchars($item['description']) ?>
</p>
<?php endif; ?>
@@ -154,33 +154,33 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
<!-- Origin Brainstorm snippet -->
<?php if (!empty($item['origin_brainstorm_card_id'])): ?>
<div class="bg-slate-950/50 rounded-xl p-2.5 text-[11px] text-slate-400 flex items-center space-x-2 border border-slate-800">
<i data-lucide="lightbulb" class="w-3.5 h-3.5 text-amber-400 flex-shrink-0"></i>
<div class="bg-slate-50 dark:bg-slate-950/50 rounded-xl p-2.5 text-[11px] text-slate-500 dark:text-slate-400 flex items-center space-x-2 border border-slate-200 dark:border-slate-800">
<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>
</div>
<?php endif; ?>
<!-- Voortgangsbalk & Deadline -->
<div class="pt-2 border-t 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 -->
<div class="flex items-center space-x-3 flex-1 max-w-md">
<span class="text-slate-400 text-[11px] font-medium w-16">Voortgang:</span>
<div class="flex-1 bg-slate-950 h-2 rounded-full overflow-hidden border border-slate-800">
<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-950 h-2 rounded-full overflow-hidden border border-slate-200 dark:border-slate-800">
<div class="bg-gradient-to-r from-emerald-500 to-teal-400 h-full transition-all" style="width: <?= $item['progress'] ?>%"></div>
</div>
<span class="font-mono text-slate-200 font-bold w-10 text-right"><?= $item['progress'] ?>%</span>
<span class="font-mono text-slate-800 dark:text-slate-200 font-bold w-10 text-right"><?= $item['progress'] ?>%</span>
<div class="flex space-x-1">
<button onclick="updateRoadmapProgress(<?= $item['id'] ?>, 25)" class="px-1.5 py-0.5 rounded bg-slate-800 text-[10px] text-slate-400 hover:text-white">25%</button>
<button onclick="updateRoadmapProgress(<?= $item['id'] ?>, 50)" class="px-1.5 py-0.5 rounded bg-slate-800 text-[10px] text-slate-400 hover:text-white">50%</button>
<button onclick="updateRoadmapProgress(<?= $item['id'] ?>, 100)" class="px-1.5 py-0.5 rounded bg-emerald-500/20 text-[10px] text-emerald-400 hover:text-emerald-300 font-bold">100%</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-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-1.5 py-0.5 rounded bg-emerald-500/20 text-[10px] text-emerald-700 dark:text-emerald-400 hover:text-emerald-800 dark:hover:text-emerald-300 font-bold cursor-pointer">100%</button>
</div>
</div>
<!-- Deadline & Creator -->
<div class="flex items-center space-x-3 text-slate-500 text-[11px]">
<?php if (!empty($item['due_date'])): ?>
<span class="flex items-center space-x-1 text-slate-300">
<i data-lucide="calendar" class="w-3.5 h-3.5 text-emerald-400"></i>
<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-emerald-600 dark:text-emerald-400"></i>
<span>Deadline: <?= date('d-m-Y', strtotime($item['due_date'])) ?></span>
</span>
<?php endif; ?>
@@ -194,33 +194,33 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
</div>
<!-- Modal: Nieuw Roadmap Item Handmatig Toevoegen -->
<div id="newItemModal" class="hidden fixed inset-0 z-50 bg-black/70 backdrop-blur-sm flex items-center justify-center p-4">
<div class="bg-slate-900 border border-slate-800 rounded-2xl p-6 shadow-2xl max-w-lg w-full">
<div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-800">
<h3 class="text-base font-bold text-white flex items-center space-x-2">
<i data-lucide="map" class="w-4 h-4 text-emerald-400"></i>
<div id="newItemModal" class="hidden fixed inset-0 z-50 bg-black/60 dark:bg-black/70 backdrop-blur-sm flex items-center justify-center p-4">
<div class="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 shadow-2xl max-w-lg w-full transition">
<div class="flex items-center justify-between mb-4 pb-3 border-b border-slate-100 dark:border-slate-800">
<h3 class="text-base font-bold text-slate-900 dark:text-white flex items-center space-x-2">
<i data-lucide="map" class="w-4 h-4 text-emerald-600 dark:text-emerald-400"></i>
<span>Nieuw Roadmap Item Toevoegen</span>
</h3>
<button onclick="document.getElementById('newItemModal').classList.add('hidden')" class="text-slate-400 hover:text-white">
<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-5 h-5"></i>
</button>
</div>
<div class="space-y-4">
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Titel / Doel</label>
<input type="text" id="manualTitle" placeholder="Bijv. 2FA Authenticatie afronden" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2 text-white text-xs placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-emerald-500">
<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 dark:bg-slate-950 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-emerald-500">
</div>
<div>
<label class="block text-xs font-medium 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-950 border border-slate-800 rounded-xl p-3 text-white text-xs placeholder-slate-500 focus:outline-none resize-none"></textarea>
<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 dark:bg-slate-950 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 resize-none"></textarea>
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Kwartaal</label>
<select id="manualQuarter" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-2 text-white text-xs focus:outline-none">
<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 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">
<option value="Q1">Q1</option>
<option value="Q2">Q2</option>
<option value="Q3" selected>Q3</option>
@@ -228,8 +228,8 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
</select>
</div>
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Type</label>
<select id="manualType" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-2 text-white text-xs focus:outline-none">
<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 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">
<option value="FEATURE" selected>Feature</option>
<option value="EPIC">Epic</option>
<option value="MILESTONE">Mijlpaal</option>
@@ -240,8 +240,8 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Prioriteit</label>
<select id="manualPriority" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-2 text-white text-xs focus:outline-none">
<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 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">
<option value="CRITICAL">Kritiek</option>
<option value="HIGH" selected>Hoog</option>
<option value="MEDIUM">Normaal</option>
@@ -249,21 +249,21 @@ $quarters = ['Q1', 'Q2', 'Q3', 'Q4'];
</select>
</div>
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Jira Issue Key (optioneel)</label>
<input type="text" id="manualJiraKey" placeholder="Bijv. FOC-101" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-1.5 text-white text-xs font-mono focus:outline-none">
<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 dark:bg-slate-950 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">
</div>
</div>
<div>
<label class="block text-xs font-medium text-slate-300 mb-1">Streefdatum</label>
<input type="date" id="manualDueDate" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-1.5 text-white text-xs focus:outline-none">
<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 dark:bg-slate-950 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">
</div>
<div class="flex space-x-2 pt-2">
<button onclick="submitManualItem()" class="flex-1 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold py-2.5 px-4 rounded-xl text-xs transition">
<button onclick="submitManualItem()" class="flex-1 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold py-2.5 px-4 rounded-xl text-xs transition cursor-pointer">
Toevoegen aan Roadmap
</button>
<button onclick="document.getElementById('newItemModal').classList.add('hidden')" class="px-4 py-2.5 bg-slate-800 hover:bg-slate-700 text-slate-300 rounded-xl text-xs transition">
<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
</button>
</div>
@@ -326,4 +326,3 @@ async function submitManualItem() {
</script>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
+51 -51
View File
@@ -65,43 +65,44 @@ $invites = $db->query("
ORDER BY i.created_at DESC
")->fetchAll();
$pageTitle = 'Team & Uitnodigingen — Fociz';
require_once __DIR__ . '/includes/header.php';
?>
<div class="space-y-6">
<div class="space-y-6 max-w-7xl mx-auto pb-12">
<!-- Header -->
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-6 shadow-xl">
<div class="flex items-center space-x-2 text-emerald-400 text-xs font-semibold uppercase tracking-wider mb-1">
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl transition">
<div class="flex items-center space-x-2 text-emerald-600 dark:text-emerald-400 text-xs font-bold uppercase tracking-wider mb-1">
<i data-lucide="shield" class="w-4 h-4"></i>
<span>Beheerderspaneel</span>
</div>
<h1 class="text-2xl sm:text-3xl font-black text-white tracking-tight">
<h1 class="text-2xl sm:text-3xl font-black text-slate-900 dark:text-white tracking-tight">
Team & Uitnodigingen
</h1>
<p class="text-slate-400 text-xs sm:text-sm mt-1">
<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.
</p>
</div>
<?php if ($error): ?>
<div class="p-4 rounded-xl bg-red-500/10 border border-red-500/30 text-red-400 text-xs font-semibold flex items-center space-x-2">
<div class="p-4 rounded-2xl bg-red-500/10 border border-red-500/30 text-red-700 dark:text-red-400 text-xs font-semibold flex items-center space-x-2">
<i data-lucide="alert-triangle" class="w-4 h-4"></i>
<span><?= htmlspecialchars($error) ?></span>
</div>
<?php endif; ?>
<?php if ($message && $generatedLink): ?>
<div class="p-5 rounded-2xl bg-emerald-950/40 border border-emerald-500/40 text-white space-y-2 shadow-xl">
<div class="flex items-center space-x-2 text-emerald-400 font-bold text-xs">
<div class="p-5 rounded-3xl bg-emerald-50 dark:bg-emerald-950/40 border border-emerald-300 dark:border-emerald-500/40 text-slate-900 dark:text-white space-y-2 shadow-sm dark:shadow-xl transition">
<div class="flex items-center space-x-2 text-emerald-700 dark:text-emerald-400 font-bold text-xs">
<i data-lucide="check-circle-2" class="w-4 h-4"></i>
<span><?= htmlspecialchars($message) ?></span>
</div>
<p class="text-xs text-slate-300">
<p class="text-xs text-slate-600 dark:text-slate-300">
Kopieer onderstaande beveiligde registratielink en stuur deze naar de collega:
</p>
<div class="flex items-center space-x-2 bg-slate-950 p-2.5 rounded-xl border border-slate-800">
<input type="text" readonly id="inviteLinkInput" value="<?= htmlspecialchars($generatedLink) ?>" class="bg-transparent text-emerald-300 font-mono text-xs flex-1 outline-none">
<button onclick="copyInviteLink()" class="px-3 py-1.5 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold text-xs rounded-lg transition flex items-center space-x-1">
<div class="flex items-center space-x-2 bg-white dark:bg-slate-950 p-2.5 rounded-2xl border border-emerald-200 dark:border-slate-800">
<input type="text" readonly id="inviteLinkInput" value="<?= htmlspecialchars($generatedLink) ?>" class="bg-transparent text-emerald-700 dark:text-emerald-300 font-mono text-xs flex-1 outline-none">
<button onclick="copyInviteLink()" class="px-3 py-1.5 bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold text-xs rounded-xl transition flex items-center space-x-1 cursor-pointer">
<i data-lucide="copy" class="w-3.5 h-3.5"></i>
<span id="copyBtnText">Kopiëren</span>
</button>
@@ -110,9 +111,9 @@ require_once __DIR__ . '/includes/header.php';
<?php endif; ?>
<!-- Uitnodiging Genereren Kaart -->
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-6 shadow-xl">
<h3 class="text-base font-bold text-white mb-4 flex items-center space-x-2">
<i data-lucide="user-plus" class="w-5 h-5 text-emerald-400"></i>
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl transition">
<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-emerald-600 dark:text-emerald-400"></i>
<span>Nieuwe Collega Uitnodigen</span>
</h3>
@@ -120,20 +121,20 @@ require_once __DIR__ . '/includes/header.php';
<input type="hidden" name="action" value="create_invite">
<div class="md:col-span-6">
<label class="block text-xs font-medium 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-950 border border-slate-800 rounded-xl px-4 py-2.5 text-white placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-emerald-500 text-xs">
<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 dark:bg-slate-950 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-emerald-500 text-xs">
</div>
<div class="md:col-span-3">
<label class="block text-xs font-medium text-slate-300 mb-1">Rol</label>
<select name="role" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3 py-2.5 text-white text-xs focus:outline-none">
<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 dark:bg-slate-950 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">
<option value="MEMBER">Collega (Standaard)</option>
<option value="ADMIN">Mede-beheerder</option>
</select>
</div>
<div class="md:col-span-3">
<button type="submit" class="w-full bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold py-2.5 px-4 rounded-xl text-xs transition shadow-lg shadow-emerald-500/20 flex items-center justify-center space-x-2">
<button type="submit" class="w-full bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold py-2.5 px-4 rounded-xl text-xs transition shadow-lg shadow-emerald-500/20 flex items-center justify-center space-x-2 cursor-pointer">
<i data-lucide="link" class="w-4 h-4"></i>
<span>Genereer Link</span>
</button>
@@ -142,17 +143,17 @@ require_once __DIR__ . '/includes/header.php';
</div>
<!-- Actieve Gebruikers Tabel -->
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-6 shadow-xl space-y-4">
<div class="flex items-center justify-between pb-3 border-b border-slate-800">
<h3 class="text-sm font-bold text-white uppercase tracking-wider flex items-center space-x-2">
<i data-lucide="users" class="w-4 h-4 text-emerald-400"></i>
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl space-y-4 transition">
<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">
<i data-lucide="users" class="w-4 h-4 text-emerald-600 dark:text-emerald-400"></i>
<span>Geregistreerde Teamleden (<?= count($users) ?>)</span>
</h3>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left text-xs text-slate-300">
<thead class="bg-slate-950/60 text-slate-400 uppercase text-[10px] tracking-wider border-b border-slate-800">
<table class="w-full text-left text-xs text-slate-700 dark:text-slate-300">
<thead class="bg-slate-50 dark:bg-slate-950/60 text-slate-500 dark:text-slate-400 uppercase text-[10px] tracking-wider border-b border-slate-200 dark:border-slate-800">
<tr>
<th class="p-3">Naam & E-mail</th>
<th class="p-3">Rol</th>
@@ -161,34 +162,34 @@ require_once __DIR__ . '/includes/header.php';
<th class="p-3 text-right">Acties</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-800/60">
<tbody class="divide-y divide-slate-100 dark:divide-slate-800/60">
<?php foreach ($users as $u): ?>
<tr class="hover:bg-slate-800/30 transition">
<tr class="hover:bg-slate-50 dark:hover:bg-slate-800/30 transition">
<td class="p-3">
<div class="font-bold text-white"><?= htmlspecialchars($u['name']) ?></div>
<div class="text-[11px] text-slate-400 font-mono"><?= htmlspecialchars($u['email']) ?></div>
<div class="font-bold text-slate-900 dark:text-white"><?= htmlspecialchars($u['name']) ?></div>
<div class="text-[11px] text-slate-500 dark:text-slate-400 font-mono"><?= htmlspecialchars($u['email']) ?></div>
</td>
<td class="p-3">
<span class="px-2 py-0.5 rounded text-[10px] font-bold <?= $u['role'] === 'ADMIN' ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30' : 'bg-slate-800 text-slate-300' ?>">
<span class="px-2 py-0.5 rounded text-[10px] font-bold <?= $u['role'] === 'ADMIN' ? 'bg-emerald-500/15 text-emerald-700 dark:text-emerald-400 border border-emerald-500/30' : 'bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300' ?>">
<?= $u['role'] === 'ADMIN' ? 'Beheerder' : 'Collega' ?>
</span>
</td>
<td class="p-3">
<span class="px-2 py-0.5 rounded-full bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 text-[10px] font-medium flex items-center space-x-1 w-max">
<span class="px-2 py-0.5 rounded-full bg-emerald-500/10 text-emerald-700 dark:text-emerald-400 border border-emerald-500/20 text-[10px] font-medium flex items-center space-x-1 w-max">
<i data-lucide="shield-check" class="w-3 h-3"></i>
<span>2FA Actief</span>
</span>
</td>
<td class="p-3 text-slate-400">
<td class="p-3 text-slate-500 dark:text-slate-400">
<?= date('d-m-Y', strtotime($u['created_at'])) ?>
</td>
<td class="p-3 text-right">
<?php if ($u['id'] !== $adminUser['id']): ?>
<a href="/users.php?delete_user=<?= $u['id'] ?>" onclick="return confirm('Gebruiker verwijderen?')" class="text-slate-500 hover:text-red-400 transition p-1">
<a href="/users.php?delete_user=<?= $u['id'] ?>" onclick="return confirm('Gebruiker verwijderen?')" class="text-slate-400 hover:text-red-600 dark:text-slate-500 dark:hover:text-red-400 transition p-1 cursor-pointer">
<i data-lucide="trash-2" class="w-4 h-4 inline"></i>
</a>
<?php else: ?>
<span class="text-[10px] text-slate-600 font-medium">Uzelf</span>
<span class="text-[10px] text-slate-400 dark:text-slate-600 font-medium">Uzelf</span>
<?php endif; ?>
</td>
</tr>
@@ -199,17 +200,17 @@ require_once __DIR__ . '/includes/header.php';
</div>
<!-- Uitstaande Uitnodigingen Tabel -->
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-6 shadow-xl space-y-4">
<div class="flex items-center justify-between pb-3 border-b border-slate-800">
<h3 class="text-sm font-bold text-white uppercase tracking-wider flex items-center space-x-2">
<i data-lucide="mail" class="w-4 h-4 text-amber-400"></i>
<div class="bg-white dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 rounded-3xl p-6 sm:p-7 shadow-sm dark:shadow-xl space-y-4 transition">
<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">
<i data-lucide="mail" class="w-4 h-4 text-amber-500"></i>
<span>Uitnodigingen Status (<?= count($invites) ?>)</span>
</h3>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left text-xs text-slate-300">
<thead class="bg-slate-950/60 text-slate-400 uppercase text-[10px] tracking-wider border-b border-slate-800">
<table class="w-full text-left text-xs text-slate-700 dark:text-slate-300">
<thead class="bg-slate-50 dark:bg-slate-950/60 text-slate-500 dark:text-slate-400 uppercase text-[10px] tracking-wider border-b border-slate-200 dark:border-slate-800">
<tr>
<th class="p-3">Uitgenodigd E-mailadres</th>
<th class="p-3">Rol</th>
@@ -218,29 +219,29 @@ require_once __DIR__ . '/includes/header.php';
<th class="p-3 text-right">Actie</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-800/60">
<tbody class="divide-y divide-slate-100 dark:divide-slate-800/60">
<?php if (empty($invites)): ?>
<tr><td colspan="5" class="p-4 text-center text-slate-500">Nog geen uitnodigingen verstuurd.</td></tr>
<tr><td colspan="5" class="p-4 text-center text-slate-400 dark:text-slate-500">Nog geen uitnodigingen verstuurd.</td></tr>
<?php else: ?>
<?php foreach ($invites as $inv):
$isUsed = !empty($inv['used_at']);
$isExpired = strtotime($inv['expires_at']) < time();
?>
<tr class="hover:bg-slate-800/30 transition">
<td class="p-3 font-mono"><?= htmlspecialchars($inv['email']) ?></td>
<tr class="hover:bg-slate-50 dark:hover:bg-slate-800/30 transition">
<td class="p-3 font-mono text-slate-900 dark:text-white"><?= htmlspecialchars($inv['email']) ?></td>
<td class="p-3"><?= htmlspecialchars($inv['role']) ?></td>
<td class="p-3">
<?php if ($isUsed): ?>
<span class="px-2 py-0.5 rounded text-[10px] font-bold bg-emerald-500/20 text-emerald-400">Geaccepteerd</span>
<span class="px-2 py-0.5 rounded text-[10px] font-bold bg-emerald-500/15 text-emerald-700 dark:text-emerald-400 border border-emerald-500/30">Geaccepteerd</span>
<?php elseif ($isExpired): ?>
<span class="px-2 py-0.5 rounded text-[10px] font-bold bg-red-500/20 text-red-400">Verlopen</span>
<span class="px-2 py-0.5 rounded text-[10px] font-bold bg-red-500/15 text-red-700 dark:text-red-400 border border-red-500/30">Verlopen</span>
<?php else: ?>
<span class="px-2 py-0.5 rounded text-[10px] font-bold bg-amber-500/20 text-amber-400">In afwachting</span>
<span class="px-2 py-0.5 rounded text-[10px] font-bold bg-amber-500/15 text-amber-700 dark:text-amber-400 border border-amber-500/30">In afwachting</span>
<?php endif; ?>
</td>
<td class="p-3 text-slate-400"><?= date('d-m-Y H:i', strtotime($inv['expires_at'])) ?></td>
<td class="p-3 text-slate-500 dark:text-slate-400"><?= date('d-m-Y H:i', strtotime($inv['expires_at'])) ?></td>
<td class="p-3 text-right">
<a href="/users.php?delete_invite=<?= $inv['id'] ?>" onclick="return confirm('Uitnodiging intrekken?')" class="text-slate-500 hover:text-red-400 transition p-1">
<a href="/users.php?delete_invite=<?= $inv['id'] ?>" onclick="return confirm('Uitnodiging intrekken?')" class="text-slate-400 hover:text-red-600 dark:text-slate-500 dark:hover:text-red-400 transition p-1 cursor-pointer">
<i data-lucide="trash-2" class="w-4 h-4 inline"></i>
</a>
</td>
@@ -266,4 +267,3 @@ function copyInviteLink() {
</script>
<?php require_once __DIR__ . '/includes/footer.php'; ?>