Schone start na index corruptie

This commit is contained in:
2026-09-09 14:31:23 +02:00
commit a5324548ec
41 changed files with 9351 additions and 0 deletions
+901
View File
@@ -0,0 +1,901 @@
<?php
/**
* Fociz Persoonlijk Profiel & Koppelingen Portaal (Voor alle gebruikers: Beheerders & Collega's)
*/
require_once __DIR__ . '/includes/auth.php';
require_once __DIR__ . '/includes/integrations/microsoft.php';
require_once __DIR__ . '/includes/integrations/jira.php';
// Iedere ingelogde gebruiker heeft toegang tot zijn/haar eigen profiel
$user = require_auth();
$userId = (int)$user['id'];
$db = get_db_connection();
$message = null;
$messageType = 'success';
if (!empty($_GET['success'])) {
$message = $_GET['success'];
$messageType = 'success';
} elseif (!empty($_GET['error'])) {
$message = $_GET['error'];
$messageType = 'error';
}
// POST Verwerking VÓÓR headers zodat redirects en mutaties soepel verlopen
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
// 1. Outlook koppelen via OAuth
if ($action === 'connect_outlook') {
$appConfig = microsoft_get_app_config();
if (!$appConfig['is_configured']) {
$message = ($user['role'] === 'ADMIN')
? "Configureer eerst de Application (Client) ID en het Client Secret in het Systeembeheer."
: "Microsoft 365 is nog niet ingesteld door de beheerder van uw organisatie. Vraag uw beheerder om de koppeling te activeren.";
$messageType = 'error';
} else {
header("Location: /auth/oauth_microsoft.php");
exit;
}
}
// 2. Outlook ontkoppelen (alleen persoonlijke tokens van deze gebruiker wissen)
elseif ($action === 'disconnect_outlook') {
microsoft_disconnect($userId);
header('Location: /profile.php?success=' . urlencode('Uw Microsoft Outlook agenda is succesvol ontkoppeld.'));
exit;
}
// 3. Jira Opslaan & Testen
elseif ($action === 'save_jira') {
$companyDomain = jira_get_company_domain();
$rawDomain = trim($_POST['jira_domain'] ?? '');
$jiraDomain = !empty($rawDomain) ? jira_normalize_domain($rawDomain) : $companyDomain;
$jiraEmail = trim($_POST['jira_email'] ?? '');
$jiraToken = trim($_POST['jira_api_token'] ?? '');
// Haal bestaande instellingen op
$stmtExisting = $db->prepare("SELECT * FROM integrations WHERE user_id = ? AND provider = 'JIRA'");
$stmtExisting->execute([$userId]);
$existing = $stmtExisting->fetch();
$existingSettings = json_decode($existing['settings'] ?? '{}', true) ?: [];
if (($jiraToken === '' || $jiraToken === '••••••••••••••••') && !empty($existingSettings['jira_api_token']) && $existingSettings['jira_api_token'] !== '••••••••••••••••') {
$jiraToken = $existingSettings['jira_api_token'];
}
$accountName = $existingSettings['account_name'] ?? '';
$accountId = $existingSettings['account_id'] ?? '';
if (!empty($jiraDomain) && !empty($jiraEmail) && !empty($jiraToken)) {
$testRes = jira_test_connection($jiraDomain, $jiraEmail, $jiraToken);
if (!$testRes['success']) {
$message = "Jira Verbindingsfout: " . $testRes['error'];
$messageType = 'error';
} else {
$accountName = $testRes['user']['displayName'] ?? 'Jira Gebruiker';
$accountId = $testRes['user']['accountId'] ?? '';
$message = "Verbinding met Jira geslaagd! Ingelogd als: {$accountName}";
$messageType = 'success';
}
} else {
$message = "Jira instellingen opgeslagen.";
$messageType = 'success';
}
$newSettings = [
'jira_domain' => $jiraDomain,
'jira_email' => $jiraEmail,
'jira_api_token' => $jiraToken,
'account_name' => $accountName,
'account_id' => $accountId,
];
$stmt = $db->prepare("
INSERT INTO integrations (user_id, provider, is_enabled, is_demo_mode, settings, last_sync_at)
VALUES (?, 'JIRA', 1, 0, ?, NOW())
ON DUPLICATE KEY UPDATE
is_demo_mode = 0,
settings = VALUES(settings),
last_sync_at = NOW()
");
$stmt->execute([$userId, json_encode($newSettings)]);
unset($_SESSION["jira_issues_user_{$userId}"]);
}
// 4. Jira ontkoppelen
elseif ($action === 'disconnect_jira') {
jira_disconnect($userId);
header('Location: /profile.php?success=' . urlencode('Atlassian Jira is succesvol ontkoppeld.'));
exit;
}
// 5. Notificatievoorkeuren opslaan
elseif ($action === 'save_notifications') {
$settings = [
'enabled' => isset($_POST['notif_enabled']) ? 1 : 0,
'lead_time_minutes' => (int)($_POST['lead_time_minutes'] ?? 5),
'repeat_count' => (int)($_POST['repeat_count'] ?? 2),
'repeat_interval_minutes' => (int)($_POST['repeat_interval_minutes'] ?? 2),
'sound_enabled' => isset($_POST['sound_enabled']) ? 1 : 0,
];
update_user_notification_settings($userId, $settings);
$message = "Uw persoonlijke notificatievoorkeuren zijn succesvol opgeslagen.";
$messageType = 'success';
}
// 6. Profielnaam bijwerken
elseif ($action === 'update_profile') {
$name = trim($_POST['name'] ?? '');
if (strlen($name) < 2) {
$message = "Voer een geldige naam in van minimaal 2 tekens.";
$messageType = 'error';
} else {
$stmt = $db->prepare("UPDATE users SET name = ? WHERE id = ?");
$stmt->execute([$name, $userId]);
$_SESSION['user_name'] = $name;
$user['name'] = $name;
$message = "Uw profielnaam is succesvol bijgewerkt.";
$messageType = 'success';
}
}
// 7. Wachtwoord wijzigen
elseif ($action === 'change_password') {
$currentPassword = $_POST['current_password'] ?? '';
$newPassword = $_POST['new_password'] ?? '';
$confirmPassword = $_POST['confirm_password'] ?? '';
$stmtU = $db->prepare("SELECT password_hash FROM users WHERE id = ?");
$stmtU->execute([$userId]);
$storedHash = $stmtU->fetchColumn();
if (!password_verify($currentPassword, $storedHash)) {
$message = "Uw huidige wachtwoord is niet correct ingevoerd.";
$messageType = 'error';
} elseif (strlen($newPassword) < 8) {
$message = "Het nieuwe wachtwoord moet minimaal 8 tekens lang zijn.";
$messageType = 'error';
} elseif ($newPassword !== $confirmPassword) {
$message = "Het nieuwe wachtwoord en de bevestiging komen niet overeen.";
$messageType = 'error';
} else {
$newHash = password_hash($newPassword, PASSWORD_DEFAULT);
$stmtUp = $db->prepare("UPDATE users SET password_hash = ? WHERE id = ?");
$stmtUp->execute([$newHash, $userId]);
$message = "Uw wachtwoord is succesvol gewijzigd.";
$messageType = 'success';
}
}
}
// Actuele gegevens ophalen
$stmtUser = $db->prepare("SELECT * FROM users WHERE id = ?");
$stmtUser->execute([$userId]);
$userProfile = $stmtUser->fetch();
// Outlook status ophalen
$stmtOutlook = $db->prepare("SELECT * FROM integrations WHERE user_id = ? AND provider = 'OUTLOOK'");
$stmtOutlook->execute([$userId]);
$outlookRow = $stmtOutlook->fetch();
$isOutlookConnected = !empty($outlookRow['access_token']) && empty($outlookRow['is_demo_mode']);
$outlookSettings = json_decode($outlookRow['settings'] ?? '{}', true) ?: [];
// Jira status ophalen
$stmtJira = $db->prepare("SELECT * FROM integrations WHERE user_id = ? AND provider = 'JIRA'");
$stmtJira->execute([$userId]);
$jiraRow = $stmtJira->fetch();
$jiraSettings = json_decode($jiraRow['settings'] ?? '{}', true) ?: [];
$isJiraConnected = !empty($jiraSettings['jira_api_token']);
$companyJiraDomain = jira_get_company_domain();
$activeJiraDomain = !empty($jiraSettings['jira_domain']) ? $jiraSettings['jira_domain'] : $companyJiraDomain;
// Centrale Azure App configuratie status
$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-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-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-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/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/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-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-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>
</p>
</div>
</div>
<?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-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>
<?php endif; ?>
</div>
</div>
<!-- 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-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 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-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-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-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-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-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-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-600 dark:text-red-400 border border-red-500/20 text-xs font-medium transition">
Ontkoppelen
</button>
</form>
</div>
<?php endif; ?>
</div>
<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-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-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-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-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-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-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-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-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>
<?php if ($appConfig['is_configured']): ?>
<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 cursor-pointer">
<i data-lucide="log-in" class="w-4 h-4"></i>
<span>Koppel Mijn Outlook Agenda</span>
</button>
</form>
<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-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-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; ?>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
</div>
<!-- Sectie 2: Mijn Atlassian Jira Koppeling -->
<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-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-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-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-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-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-600 dark:text-red-400 border border-red-500/20 text-xs font-medium transition">
Jira Ontkoppelen
</button>
</form>
<?php endif; ?>
</div>
<form method="POST" class="mt-6 space-y-4">
<input type="hidden" name="action" value="save_jira">
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<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-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-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-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-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-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-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>
</div>
<div class="pt-2 flex items-center justify-between">
<?php if ($isJiraConnected && !empty($jiraSettings['account_name'])): ?>
<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-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">
Jira Opslaan & Testen
</button>
</div>
</form>
</div>
<!-- Sectie 3: Mijn Meldingen & Agenda Push Notificaties -->
<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-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-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-600 dark:text-emerald-400 flex-shrink-0"></i>
<div>
<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-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-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-600 dark:text-blue-400 flex-shrink-0"></i>
<div>
<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">
Toestemming Verlenen
</button>
</div>
<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-50 dark:bg-slate-950/60 border border-slate-200 dark:border-slate-800">
<div>
<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-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-700 dark:text-slate-300 mb-1.5">
Vooraankondiging
</label>
<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>
<option value="10" <?= (int)$notifSettings['lead_time_minutes'] === 10 ? 'selected' : '' ?>>10 minuten van tevoren</option>
<option value="15" <?= (int)$notifSettings['lead_time_minutes'] === 15 ? 'selected' : '' ?>>15 minuten van tevoren</option>
<option value="30" <?= (int)$notifSettings['lead_time_minutes'] === 30 ? 'selected' : '' ?>>30 minuten van tevoren</option>
</select>
</div>
<div>
<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-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>
<option value="5" <?= (int)$notifSettings['repeat_count'] === 5 ? 'selected' : '' ?>>5x herhalen</option>
</select>
</div>
<div>
<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-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>
<option value="5" <?= (int)$notifSettings['repeat_interval_minutes'] === 5 ? 'selected' : '' ?>>Elke 5 minuten</option>
</select>
</div>
</div>
<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-600 dark:text-emerald-400"></i>
<div>
<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-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-white dark:text-slate-950 text-xs font-bold transition shadow-lg shadow-emerald-600/20">
Notificatievoorkeuren Opslaan
</button>
</div>
</form>
</div>
</div>
<!-- Sectie 4: Account & Beveiliging (Wachtwoord & 2FA) -->
<div class="space-y-6">
<!-- 2FA Beveiliging Card -->
<div class="p-5 rounded-3xl bg-emerald-50/80 dark:bg-emerald-500/10 border border-emerald-200 dark:border-emerald-500/25 flex flex-col sm:flex-row sm:items-center justify-between gap-4 shadow-sm">
<div class="flex items-center space-x-3.5">
<div class="w-12 h-12 rounded-2xl bg-emerald-500/20 border border-emerald-500/30 flex items-center justify-center text-emerald-600 dark:text-emerald-400 font-bold shadow-sm flex-shrink-0">
<i data-lucide="shield-check" class="w-6 h-6"></i>
</div>
<div>
<div class="flex items-center space-x-2">
<h3 class="text-sm font-bold text-slate-900 dark:text-white">Tweestapsverificatie (2FA) is Actief</h3>
<span class="px-2 py-0.5 rounded-full bg-emerald-500 text-slate-950 font-bold text-[10px]">Beveiligd</span>
</div>
<p class="text-xs text-slate-600 dark:text-slate-400 mt-0.5">
Uw Fociz account is optimaal beveiligd met een Authenticator app (TOTP) voor maximale privacy- en dataveiligheid.
</p>
</div>
</div>
<div class="text-xs font-mono font-medium text-emerald-700 dark:text-emerald-400 flex items-center space-x-1.5 flex-shrink-0 self-end sm:self-center">
<i data-lucide="lock" class="w-4 h-4"></i>
<span>Verplicht & Actief</span>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Profielnaam formulier -->
<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-700 dark:text-slate-300 mb-1.5">
Weergavenaam
</label>
<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-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-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-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>
</form>
</div>
<!-- Wachtwoord Wijzigen Formulier -->
<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-700 dark:text-slate-300 mb-1">
Huidig Wachtwoord
</label>
<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-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-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-700 dark:text-slate-300 mb-1">
Bevestig Nieuw Wachtwoord
</label>
<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-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>
</form>
</div>
</div>
</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');
if (!input || !icon) return;
if (input.type === 'password') {
input.type = 'text';
icon.setAttribute('data-lucide', 'eye-off');
} else {
input.type = 'password';
icon.setAttribute('data-lucide', 'eye');
}
if (window.lucide) lucide.createIcons();
}
// 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');
const deniedEl = document.getElementById('profileNotifPermDenied');
if (Notification.permission === 'granted') {
if (grantedEl) grantedEl.classList.remove('hidden');
if (reqEl) reqEl.classList.add('hidden');
if (deniedEl) deniedEl.classList.add('hidden');
} else if (Notification.permission === 'denied') {
if (grantedEl) grantedEl.classList.add('hidden');
if (reqEl) reqEl.classList.add('hidden');
if (deniedEl) deniedEl.classList.remove('hidden');
} else {
if (grantedEl) grantedEl.classList.add('hidden');
if (reqEl) reqEl.classList.remove('hidden');
if (deniedEl) deniedEl.classList.add('hidden');
}
});
</script>
<?php require_once __DIR__ . '/includes/footer.php'; ?>