Dev #42
@@ -156,18 +156,7 @@ $boardsJson = json_encode($boards, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT
|
||||
Koppel Jira Cloud
|
||||
</a>
|
||||
</div>
|
||||
<?php elseif ($isLive): ?>
|
||||
<!-- Live Status Subbalk -->
|
||||
<div class="mt-4 pt-3 border-t border-slate-100 dark:border-slate-800/60 flex flex-wrap items-center justify-between text-xs text-slate-500 dark:text-slate-400 gap-2">
|
||||
<div class="flex items-center space-x-2">
|
||||
<i data-lucide="check-circle-2" class="w-3.5 h-3.5 text-emerald-500"></i>
|
||||
<span>Verbonden met <strong class="text-slate-700 dark:text-slate-200"><?= htmlspecialchars($domain) ?></strong> als <strong class="text-slate-700 dark:text-slate-200"><?= htmlspecialchars($accountName ?: $email) ?></strong></span>
|
||||
</div>
|
||||
<div class="text-[11px] text-slate-400">
|
||||
Laatste synchronisatie: <?= date('d-m-Y H:i', strtotime($lastSync)) ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php elseif (!empty($syncError)): ?>
|
||||
<?php if (!empty($syncError)): ?>
|
||||
<!-- Synchronisatiefout Banner -->
|
||||
<div class="mt-4 p-3 rounded-xl bg-red-50 dark:bg-red-950/30 border border-red-200 dark:border-red-900/50 flex items-center space-x-3 text-xs text-red-700 dark:text-red-300">
|
||||
<i data-lucide="alert-triangle" class="w-4 h-4 text-red-500 flex-shrink-0"></i>
|
||||
@@ -177,162 +166,162 @@ $boardsJson = json_encode($boards, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT
|
||||
<a href="/profile.php#integraties" class="underline hover:no-underline font-semibold">Controleer instellingen</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Hub Voettekst: Live Status & Filters Uitklapknop (Rechtsonder) -->
|
||||
<div class="mt-4 pt-3 border-t border-slate-100 dark:border-slate-800/60 flex flex-wrap items-center justify-between text-xs text-slate-500 dark:text-slate-400 gap-2">
|
||||
<div class="flex items-center space-x-2">
|
||||
<?php if ($isLive): ?>
|
||||
<i data-lucide="check-circle-2" class="w-3.5 h-3.5 text-emerald-500"></i>
|
||||
<span>Verbonden met <strong class="text-slate-700 dark:text-slate-200"><?= htmlspecialchars($domain) ?></strong> als <strong class="text-slate-700 dark:text-slate-200"><?= htmlspecialchars($accountName ?: $email) ?></strong></span>
|
||||
<span class="text-slate-300 dark:text-slate-700 hidden sm:inline">•</span>
|
||||
<span class="text-[11px] text-slate-400 hidden sm:inline">Sync: <?= date('d-m-Y H:i', strtotime($lastSync)) ?></span>
|
||||
<?php elseif ($isDemo): ?>
|
||||
<i data-lucide="database" class="w-3.5 h-3.5 text-amber-500"></i>
|
||||
<span>Demodataset actief met voorbeeldtickets</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- 4 KPI Statistieken Kaarten -->
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<!-- Kaart 1: Aan mij toegewezen -->
|
||||
<div onclick="switchTab('assigned')" class="fociz-card-interactive p-4 cursor-pointer group">
|
||||
<!-- Uitklapknop in de rechter onderhoek -->
|
||||
<div class="flex items-center space-x-2 ml-auto">
|
||||
<button type="button"
|
||||
onclick="toggleJiraFiltersDrawer()"
|
||||
id="btnToggleFiltersDrawer"
|
||||
class="flex items-center space-x-2 px-3 py-1.5 rounded-xl text-xs font-semibold bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-200 border border-slate-200 dark:border-slate-700 transition cursor-pointer shadow-2xs group">
|
||||
<i data-lucide="sliders-horizontal" class="w-3.5 h-3.5 text-indigo-500 group-hover:rotate-12 transition-transform"></i>
|
||||
<span>Filters & Statistieken</span>
|
||||
<span id="activeFilterBadge" class="hidden px-1.5 py-0.2 rounded-full text-[10px] font-black bg-indigo-600 text-white leading-tight">0</span>
|
||||
<i data-lucide="chevron-down" id="filtersDrawerChevron" class="w-3.5 h-3.5 transition-transform duration-200"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Uitklapbare Filters & Statistieken Drawer -->
|
||||
<div id="jiraFiltersDrawer" class="hidden mt-4 pt-4 border-t border-slate-100 dark:border-slate-800/80 space-y-4">
|
||||
|
||||
<!-- 1. 4 KPI Statistieken Kaarten -->
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-3">
|
||||
<div onclick="switchTab('assigned')" class="p-3.5 rounded-xl bg-slate-50 dark:bg-slate-800/50 hover:bg-slate-100 dark:hover:bg-slate-800 border border-slate-200/70 dark:border-slate-700/60 cursor-pointer transition group">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-xs font-bold text-slate-500 dark:text-slate-400">Aan mij toegewezen</span>
|
||||
<div class="w-8 h-8 rounded-xl bg-blue-50 dark:bg-blue-950/40 text-blue-600 dark:text-blue-400 flex items-center justify-center transition group-hover:scale-110">
|
||||
<i data-lucide="user-check" class="w-4 h-4"></i>
|
||||
<div class="w-7 h-7 rounded-lg bg-blue-50 dark:bg-blue-950/40 text-blue-600 dark:text-blue-400 flex items-center justify-center transition group-hover:scale-110">
|
||||
<i data-lucide="user-check" class="w-3.5 h-3.5"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 flex items-baseline space-x-2">
|
||||
<span id="statAssignedCount" class="text-2xl font-black text-slate-900 dark:text-white"><?= count($assignedIssues) ?></span>
|
||||
<div class="mt-2 flex items-baseline space-x-2">
|
||||
<span id="statAssignedCount" class="text-xl font-black text-slate-900 dark:text-white"><?= count($assignedIssues) ?></span>
|
||||
<span class="text-[11px] text-slate-400 font-medium">persoonlijke taken</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Kaart 2: Mijn Teams & Projecten -->
|
||||
<div onclick="switchTab('team')" class="fociz-card-interactive p-4 cursor-pointer group">
|
||||
<div onclick="switchTab('team')" class="p-3.5 rounded-xl bg-slate-50 dark:bg-slate-800/50 hover:bg-slate-100 dark:hover:bg-slate-800 border border-slate-200/70 dark:border-slate-700/60 cursor-pointer transition group">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-xs font-bold text-slate-500 dark:text-slate-400">Team & Projecten</span>
|
||||
<div class="w-8 h-8 rounded-xl bg-purple-50 dark:bg-purple-950/40 text-purple-600 dark:text-purple-400 flex items-center justify-center transition group-hover:scale-110">
|
||||
<i data-lucide="users" class="w-4 h-4"></i>
|
||||
<div class="w-7 h-7 rounded-lg bg-purple-50 dark:bg-purple-950/40 text-purple-600 dark:text-purple-400 flex items-center justify-center transition group-hover:scale-110">
|
||||
<i data-lucide="users" class="w-3.5 h-3.5"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 flex items-baseline space-x-2">
|
||||
<span id="statTeamCount" class="text-2xl font-black text-slate-900 dark:text-white"><?= count($teamIssues) ?></span>
|
||||
<div class="mt-2 flex items-baseline space-x-2">
|
||||
<span id="statTeamCount" class="text-xl font-black text-slate-900 dark:text-white"><?= count($teamIssues) ?></span>
|
||||
<span class="text-[11px] text-slate-400 font-medium">in actieve projecten</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Kaart 3: In Uitvoering -->
|
||||
<div onclick="switchTab('in_progress')" class="fociz-card-interactive p-4 cursor-pointer group">
|
||||
<div onclick="switchTab('in_progress')" class="p-3.5 rounded-xl bg-slate-50 dark:bg-slate-800/50 hover:bg-slate-100 dark:hover:bg-slate-800 border border-slate-200/70 dark:border-slate-700/60 cursor-pointer transition group">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-xs font-bold text-slate-500 dark:text-slate-400">In Uitvoering</span>
|
||||
<div class="w-8 h-8 rounded-xl bg-amber-50 dark:bg-amber-950/40 text-amber-600 dark:text-amber-400 flex items-center justify-center transition group-hover:scale-110">
|
||||
<i data-lucide="clock" class="w-4 h-4"></i>
|
||||
<div class="w-7 h-7 rounded-lg bg-amber-50 dark:bg-amber-950/40 text-amber-600 dark:text-amber-400 flex items-center justify-center transition group-hover:scale-110">
|
||||
<i data-lucide="clock" class="w-3.5 h-3.5"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 flex items-baseline space-x-2">
|
||||
<span id="statInProgressCount" class="text-2xl font-black text-slate-900 dark:text-white">...</span>
|
||||
<div class="mt-2 flex items-baseline space-x-2">
|
||||
<span id="statInProgressCount" class="text-xl font-black text-slate-900 dark:text-white">...</span>
|
||||
<span class="text-[11px] text-slate-400 font-medium">actief mee bezig</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Kaart 4: Urgent / P1 -->
|
||||
<div onclick="filterByUrgent()" class="fociz-card-interactive p-4 cursor-pointer group">
|
||||
<div onclick="filterByUrgent()" class="p-3.5 rounded-xl bg-slate-50 dark:bg-slate-800/50 hover:bg-slate-100 dark:hover:bg-slate-800 border border-slate-200/70 dark:border-slate-700/60 cursor-pointer transition group">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-xs font-bold text-slate-500 dark:text-slate-400">Hoge Prioriteit / Urgent</span>
|
||||
<div class="w-8 h-8 rounded-xl bg-rose-50 dark:bg-rose-950/40 text-rose-600 dark:text-rose-400 flex items-center justify-center transition group-hover:scale-110">
|
||||
<i data-lucide="alert-circle" class="w-4 h-4"></i>
|
||||
<div class="w-7 h-7 rounded-lg bg-rose-50 dark:bg-rose-950/40 text-rose-600 dark:text-rose-400 flex items-center justify-center transition group-hover:scale-110">
|
||||
<i data-lucide="alert-circle" class="w-3.5 h-3.5"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 flex items-baseline space-x-2">
|
||||
<span id="statHighPriorityCount" class="text-2xl font-black text-slate-900 dark:text-white">...</span>
|
||||
<div class="mt-2 flex items-baseline space-x-2">
|
||||
<span id="statHighPriorityCount" class="text-xl font-black text-slate-900 dark:text-white">...</span>
|
||||
<span class="text-[11px] text-slate-400 font-medium">Highest / High</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 1. Snelle Project Switcher (Pill Tabs) -->
|
||||
<div class="fociz-card p-4 sm:p-5">
|
||||
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-2 pb-3 mb-3 border-b border-slate-100 dark:border-slate-800/80">
|
||||
<div class="flex items-center space-x-2.5">
|
||||
<div class="w-8 h-8 rounded-xl bg-indigo-50 dark:bg-indigo-950/50 text-indigo-600 dark:text-indigo-400 flex items-center justify-center font-bold">
|
||||
<i data-lucide="folder-kanban" class="w-4 h-4"></i>
|
||||
<!-- 2. Snelle Project Switcher (Pill Tabs) -->
|
||||
<div class="p-3.5 rounded-xl bg-slate-50 dark:bg-slate-800/30 border border-slate-200/70 dark:border-slate-800">
|
||||
<div class="flex items-center justify-between pb-2 mb-2 border-b border-slate-200/60 dark:border-slate-800">
|
||||
<div class="flex items-center space-x-2">
|
||||
<i data-lucide="folder-kanban" class="w-3.5 h-3.5 text-indigo-500"></i>
|
||||
<span class="text-xs font-bold text-slate-900 dark:text-white uppercase tracking-wider">Jira Projecten</span>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-xs font-bold text-slate-900 dark:text-white uppercase tracking-wider">Jira Projecten</h2>
|
||||
<p class="text-[11px] text-slate-500 dark:text-slate-400">Klik op een project om direct te filteren</p>
|
||||
<span class="text-[11px] text-slate-400"><?= count($allProjects) ?> projecten</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-[11px] text-slate-400 hidden sm:block">
|
||||
<span><?= count($allProjects) ?> actieve projecten gevonden</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2 overflow-x-auto pb-1" id="projectPillsContainer">
|
||||
<!-- Alle Projecten Pill -->
|
||||
<button type="button" onclick="selectProject('')" data-project="" class="project-pill flex items-center space-x-2 px-3.5 py-2 rounded-xl text-xs font-bold transition cursor-pointer bg-indigo-600 text-white shadow-sm shadow-indigo-600/20 flex-shrink-0">
|
||||
<i data-lucide="layers" class="w-3.5 h-3.5"></i>
|
||||
<button type="button" onclick="selectProject('')" data-project="" class="project-pill flex items-center space-x-1.5 px-3 py-1.5 rounded-xl text-xs font-bold transition cursor-pointer bg-indigo-600 text-white shadow-xs flex-shrink-0">
|
||||
<i data-lucide="layers" class="w-3 h-3"></i>
|
||||
<span>Alle Projecten</span>
|
||||
<span class="px-2 py-0.5 rounded-full text-[10px] bg-white/20 text-white font-black"><?= count($allIssues) ?></span>
|
||||
<span class="px-1.5 py-0.5 rounded-full text-[10px] bg-white/20 text-white font-black"><?= count($allIssues) ?></span>
|
||||
</button>
|
||||
|
||||
<!-- Per project pills -->
|
||||
<?php foreach ($allProjects as $pName => $pData): ?>
|
||||
<button type="button" onclick="selectProject('<?= htmlspecialchars(addslashes($pName)) ?>')" data-project="<?= htmlspecialchars($pName) ?>" class="project-pill flex items-center space-x-2 px-3.5 py-2 rounded-xl text-xs font-bold transition cursor-pointer bg-slate-100 dark:bg-slate-800/80 text-slate-700 dark:text-slate-300 hover:bg-slate-200 dark:hover:bg-slate-700/80 border border-slate-200/80 dark:border-slate-700/80 flex-shrink-0">
|
||||
<button type="button" onclick="selectProject('<?= htmlspecialchars(addslashes($pName)) ?>')" data-project="<?= htmlspecialchars($pName) ?>" class="project-pill flex items-center space-x-1.5 px-3 py-1.5 rounded-xl text-xs font-bold transition cursor-pointer bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300 hover:bg-slate-200/70 dark:hover:bg-slate-700 border border-slate-200 dark:border-slate-700 flex-shrink-0">
|
||||
<?php if (!empty($pData['key'])): ?>
|
||||
<span class="px-1.5 py-0.5 rounded text-[10px] font-mono font-black bg-indigo-100 dark:bg-indigo-950/80 text-indigo-700 dark:text-indigo-300"><?= htmlspecialchars($pData['key']) ?></span>
|
||||
<span class="px-1 py-0.5 rounded text-[10px] font-mono font-black bg-indigo-100 dark:bg-indigo-950/80 text-indigo-700 dark:text-indigo-300"><?= htmlspecialchars($pData['key']) ?></span>
|
||||
<?php else: ?>
|
||||
<i data-lucide="folder" class="w-3.5 h-3.5 text-slate-400"></i>
|
||||
<i data-lucide="folder" class="w-3 h-3 text-slate-400"></i>
|
||||
<?php endif; ?>
|
||||
<span><?= htmlspecialchars($pName) ?></span>
|
||||
<span class="px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-slate-200 dark:bg-slate-700 text-slate-600 dark:text-slate-300"><?= $projectCounts[$pName] ?? 0 ?></span>
|
||||
<span class="px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-300"><?= $projectCounts[$pName] ?? 0 ?></span>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2. Servicedesk Wachtrijfilter Sub-balk (DX / SD) -->
|
||||
<div id="queueFiltersBar" class="fociz-card p-4 bg-gradient-to-r from-slate-50 via-indigo-50/30 to-sky-50/20 dark:from-[#0c0f17] dark:via-indigo-950/20 dark:to-sky-950/20 border-indigo-200/70 dark:border-indigo-900/40">
|
||||
<div class="flex flex-col md:flex-row md:items-center justify-between gap-3">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="w-8 h-8 rounded-xl bg-indigo-500/15 text-indigo-600 dark:text-indigo-400 flex items-center justify-center font-bold flex-shrink-0">
|
||||
<i data-lucide="filter" class="w-4 h-4"></i>
|
||||
</div>
|
||||
<div>
|
||||
<!-- 3. Servicedesk Wachtrijfilter Sub-balk (DX / SD) -->
|
||||
<div id="queueFiltersBar" class="p-3.5 rounded-xl bg-gradient-to-r from-slate-50 via-indigo-50/20 to-sky-50/10 dark:from-slate-900 dark:via-indigo-950/20 dark:to-sky-950/10 border border-indigo-100 dark:border-indigo-900/40">
|
||||
<div class="flex flex-col md:flex-row md:items-center justify-between gap-2.5">
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="text-xs font-bold text-slate-900 dark:text-white">Servicedesk Wachtrijfilters</span>
|
||||
<i data-lucide="filter" class="w-3.5 h-3.5 text-indigo-500"></i>
|
||||
<span class="text-xs font-bold text-slate-900 dark:text-white">Servicedesk Wachtrijen</span>
|
||||
<?php if (!empty($defaultQueueFilter)): ?>
|
||||
<span class="text-[10px] font-bold px-2 py-0.5 rounded-full bg-indigo-100 text-indigo-800 dark:bg-indigo-950/70 dark:text-indigo-300 border border-indigo-200 dark:border-indigo-800/80">
|
||||
Jouw voorkeur: <?= htmlspecialchars($defaultQueueFilter) ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<p class="text-[11px] text-slate-500 dark:text-slate-400">
|
||||
Filtert op onderwerp logging routering (DX voor koppelingen & endpoints, SD voor reguliere support)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Knoppen rij voor wachtrijen -->
|
||||
<div class="flex items-center gap-2 overflow-x-auto" id="queueButtonsContainer">
|
||||
<button type="button" onclick="selectQueueFilter('')" data-queue="" class="queue-pill flex items-center space-x-1.5 px-3 py-1.5 rounded-xl text-xs font-bold transition cursor-pointer bg-slate-200/80 dark:bg-slate-800 text-slate-700 dark:text-slate-300 flex-shrink-0">
|
||||
<i data-lucide="list" class="w-3.5 h-3.5"></i>
|
||||
<div class="flex items-center gap-1.5 overflow-x-auto" id="queueButtonsContainer">
|
||||
<button type="button" onclick="selectQueueFilter('')" data-queue="" class="queue-pill flex items-center space-x-1 px-2.5 py-1.5 rounded-xl text-xs font-bold transition cursor-pointer bg-slate-200/80 dark:bg-slate-800 text-slate-700 dark:text-slate-300 flex-shrink-0">
|
||||
<i data-lucide="list" class="w-3 h-3"></i>
|
||||
<span>Alle Wachtrijen</span>
|
||||
<span id="queueCount_all" class="px-1.5 py-0.5 rounded-full text-[10px] bg-slate-300 dark:bg-slate-700 font-bold">0</span>
|
||||
</button>
|
||||
|
||||
<button type="button" onclick="selectQueueFilter('DX')" data-queue="DX" class="queue-pill flex items-center space-x-1.5 px-3 py-1.5 rounded-xl text-xs font-bold transition cursor-pointer bg-slate-100 dark:bg-slate-800/80 text-slate-700 dark:text-slate-300 hover:bg-slate-200 dark:hover:bg-slate-700/80 border border-slate-200/80 dark:border-slate-700/80 flex-shrink-0">
|
||||
<i data-lucide="zap" class="w-3.5 h-3.5 text-amber-500"></i>
|
||||
<span>DX Wachtrij (Koppelingen)</span>
|
||||
<button type="button" onclick="selectQueueFilter('DX')" data-queue="DX" class="queue-pill flex items-center space-x-1 px-2.5 py-1.5 rounded-xl text-xs font-bold transition cursor-pointer bg-white dark:bg-slate-800/80 text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700 border border-slate-200 dark:border-slate-700 flex-shrink-0">
|
||||
<i data-lucide="zap" class="w-3 h-3 text-amber-500"></i>
|
||||
<span>DX (Koppelingen)</span>
|
||||
<span id="queueCount_DX" class="px-1.5 py-0.5 rounded-full text-[10px] bg-amber-100 dark:bg-amber-950/60 text-amber-800 dark:text-amber-300 font-bold">0</span>
|
||||
</button>
|
||||
|
||||
<button type="button" onclick="selectQueueFilter('SD')" data-queue="SD" class="queue-pill flex items-center space-x-1.5 px-3 py-1.5 rounded-xl text-xs font-bold transition cursor-pointer bg-slate-100 dark:bg-slate-800/80 text-slate-700 dark:text-slate-300 hover:bg-slate-200 dark:hover:bg-slate-700/80 border border-slate-200/80 dark:border-slate-700/80 flex-shrink-0">
|
||||
<i data-lucide="wrench" class="w-3.5 h-3.5 text-sky-500"></i>
|
||||
<span>SD Wachtrij (Regulier)</span>
|
||||
<button type="button" onclick="selectQueueFilter('SD')" data-queue="SD" class="queue-pill flex items-center space-x-1 px-2.5 py-1.5 rounded-xl text-xs font-bold transition cursor-pointer bg-white dark:bg-slate-800/80 text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700 border border-slate-200 dark:border-slate-700 flex-shrink-0">
|
||||
<i data-lucide="wrench" class="w-3 h-3 text-sky-500"></i>
|
||||
<span>SD (Regulier)</span>
|
||||
<span id="queueCount_SD" class="px-1.5 py-0.5 rounded-full text-[10px] bg-sky-100 dark:bg-sky-950/60 text-sky-800 dark:text-sky-300 font-bold">0</span>
|
||||
</button>
|
||||
|
||||
<?php foreach ($queueFilters as $qf):
|
||||
$code = $qf['filter_code'] ?? '';
|
||||
if ($code === 'DX' || $code === 'SD' || empty($code)) continue;
|
||||
?>
|
||||
<button type="button" onclick="selectQueueFilter('<?= htmlspecialchars($code) ?>')" data-queue="<?= htmlspecialchars($code) ?>" class="queue-pill flex items-center space-x-1.5 px-3 py-1.5 rounded-xl text-xs font-bold transition cursor-pointer bg-slate-100 dark:bg-slate-800/80 text-slate-700 dark:text-slate-300 hover:bg-slate-200 dark:hover:bg-slate-700/80 border border-slate-200/80 dark:border-slate-700/80 flex-shrink-0">
|
||||
<i data-lucide="filter" class="w-3.5 h-3.5 text-indigo-500"></i>
|
||||
<button type="button" onclick="selectQueueFilter('<?= htmlspecialchars($code) ?>')" data-queue="<?= htmlspecialchars($code) ?>" class="queue-pill flex items-center space-x-1 px-2.5 py-1.5 rounded-xl text-xs font-bold transition cursor-pointer bg-white dark:bg-slate-800/80 text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700 border border-slate-200 dark:border-slate-700 flex-shrink-0">
|
||||
<i data-lucide="filter" class="w-3 h-3 text-indigo-500"></i>
|
||||
<span><?= htmlspecialchars($qf['filter_name'] ?? $code) ?></span>
|
||||
<span id="queueCount_<?= htmlspecialchars($code) ?>" class="px-1.5 py-0.5 rounded-full text-[10px] bg-indigo-100 dark:bg-indigo-950/60 text-indigo-800 dark:text-indigo-300 font-bold">0</span>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php if ($isAdmin): ?>
|
||||
<a href="/admin.php#jira-wachtrijen" title="Wachtrijfilters beheren in Admin" class="p-1.5 rounded-xl text-slate-400 hover:text-slate-700 dark:hover:text-slate-200 hover:bg-slate-200/60 dark:hover:bg-slate-800 transition cursor-pointer flex-shrink-0">
|
||||
<a href="/admin.php#jira-wachtrijen" title="Wachtrijfilters beheren in Admin" class="p-1 rounded-lg text-slate-400 hover:text-slate-700 dark:hover:text-slate-200 hover:bg-slate-200/60 dark:hover:bg-slate-800 transition cursor-pointer flex-shrink-0">
|
||||
<i data-lucide="settings" class="w-3.5 h-3.5"></i>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
@@ -340,28 +329,12 @@ $boardsJson = json_encode($boards, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filterbalk & Zoekveld -->
|
||||
<div class="fociz-card p-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-3">
|
||||
|
||||
<!-- Zoekveld (key of titel) -->
|
||||
<div class="md:col-span-4 relative">
|
||||
<i data-lucide="search" class="w-4 h-4 text-slate-400 absolute left-3.5 top-1/2 -translate-y-1/2 pointer-events-none"></i>
|
||||
<input
|
||||
type="text"
|
||||
id="jiraSearchInput"
|
||||
placeholder="Zoek op ticket key (bijv. FOC-101) of titel..."
|
||||
oninput="applyFilters()"
|
||||
class="w-full bg-slate-50 dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-xl pl-9 pr-8 py-2 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/40 transition placeholder-slate-400"
|
||||
>
|
||||
<button onclick="clearSearch()" id="clearSearchBtn" class="hidden absolute right-2.5 top-1/2 -translate-y-1/2 text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 cursor-pointer">
|
||||
<i data-lucide="x" class="w-3.5 h-3.5"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Filter: Project -->
|
||||
<div class="md:col-span-2">
|
||||
<select id="filterProject" onchange="onProjectSelectChange(this.value)" class="w-full bg-slate-50 dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-2 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/40 cursor-pointer">
|
||||
<!-- 4. Gedetailleerde Filter Dropdowns -->
|
||||
<div class="p-3.5 rounded-xl bg-slate-50 dark:bg-slate-800/30 border border-slate-200/70 dark:border-slate-800">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-2.5">
|
||||
<div>
|
||||
<label class="block text-[11px] font-semibold text-slate-500 dark:text-slate-400 mb-1">Project</label>
|
||||
<select id="filterProject" onchange="onProjectSelectChange(this.value)" class="w-full bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 rounded-xl px-2.5 py-1.5 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/40 cursor-pointer">
|
||||
<option value="">Alle projecten</option>
|
||||
<?php foreach ($allProjects as $pName => $pData): ?>
|
||||
<option value="<?= htmlspecialchars($pName) ?>"><?= htmlspecialchars($pName) ?></option>
|
||||
@@ -369,9 +342,9 @@ $boardsJson = json_encode($boards, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Filter: Type (Story, Bug, Task, etc.) -->
|
||||
<div class="md:col-span-2">
|
||||
<select id="filterType" onchange="applyFilters()" class="w-full bg-slate-50 dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-2 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/40 cursor-pointer">
|
||||
<div>
|
||||
<label class="block text-[11px] font-semibold text-slate-500 dark:text-slate-400 mb-1">Type</label>
|
||||
<select id="filterType" onchange="applyFilters()" class="w-full bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 rounded-xl px-2.5 py-1.5 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/40 cursor-pointer">
|
||||
<option value="">Alle typen</option>
|
||||
<?php foreach ($allTypes as $t): ?>
|
||||
<option value="<?= htmlspecialchars($t) ?>"><?= htmlspecialchars($t) ?></option>
|
||||
@@ -379,9 +352,9 @@ $boardsJson = json_encode($boards, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Filter: Prioriteit -->
|
||||
<div class="md:col-span-2">
|
||||
<select id="filterPriority" onchange="applyFilters()" class="w-full bg-slate-50 dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-2 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/40 cursor-pointer">
|
||||
<div>
|
||||
<label class="block text-[11px] font-semibold text-slate-500 dark:text-slate-400 mb-1">Prioriteit</label>
|
||||
<select id="filterPriority" onchange="applyFilters()" class="w-full bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 rounded-xl px-2.5 py-1.5 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/40 cursor-pointer">
|
||||
<option value="">Alle prioriteiten</option>
|
||||
<option value="Highest">Highest</option>
|
||||
<option value="High">High</option>
|
||||
@@ -390,60 +363,83 @@ $boardsJson = json_encode($boards, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Filter: Status -->
|
||||
<div class="md:col-span-2 flex items-center space-x-2">
|
||||
<select id="filterStatus" onchange="applyFilters()" class="w-full bg-slate-50 dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-2 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/40 cursor-pointer">
|
||||
<div>
|
||||
<label class="block text-[11px] font-semibold text-slate-500 dark:text-slate-400 mb-1">Status</label>
|
||||
<select id="filterStatus" onchange="applyFilters()" class="w-full bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 rounded-xl px-2.5 py-1.5 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/40 cursor-pointer">
|
||||
<option value="">Alle statussen</option>
|
||||
<?php foreach ($allStatuses as $s): ?>
|
||||
<option value="<?= htmlspecialchars($s) ?>"><?= htmlspecialchars($s) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<button onclick="resetAllFilters()" title="Herstel alle filters" class="p-2 rounded-xl text-slate-400 hover:text-slate-700 dark:hover:text-slate-200 bg-slate-50 hover:bg-slate-100 dark:bg-slate-900 dark:hover:bg-slate-800 border border-slate-200 dark:border-slate-800 transition cursor-pointer flex-shrink-0">
|
||||
</div>
|
||||
|
||||
<div class="flex items-end">
|
||||
<button type="button" onclick="resetAllFilters()" class="w-full flex items-center justify-center space-x-1.5 px-3 py-1.5 rounded-xl text-xs font-semibold text-slate-600 dark:text-slate-300 hover:text-slate-900 dark:hover:text-white bg-white hover:bg-slate-100 dark:bg-slate-800 dark:hover:bg-slate-700 border border-slate-200 dark:border-slate-700 transition cursor-pointer">
|
||||
<i data-lucide="rotate-ccw" class="w-3.5 h-3.5"></i>
|
||||
<span>Herstel Filters</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tabs Weergave -->
|
||||
<div class="flex items-center justify-between border-b border-slate-200 dark:border-slate-800 overflow-x-auto">
|
||||
<div class="flex space-x-1 sm:space-x-2 py-1">
|
||||
<button onclick="switchTab('assigned')" id="tabBtn_assigned" class="flex items-center space-x-2 px-4 py-2.5 text-xs font-bold rounded-xl transition cursor-pointer bg-indigo-50 dark:bg-indigo-950/50 text-indigo-600 dark:text-indigo-400 border-b-2 border-indigo-600 dark:border-indigo-400">
|
||||
<i data-lucide="user-check" class="w-4 h-4"></i>
|
||||
<!-- Compacte Werkbalk: Tabs & Zoekveld direct boven de tickets -->
|
||||
<div class="fociz-card p-3 sm:p-4 flex flex-col md:flex-row md:items-center justify-between gap-3 shadow-xs">
|
||||
<!-- Tabs Navigatie -->
|
||||
<div class="flex items-center space-x-1 sm:space-x-1.5 overflow-x-auto pb-1 md:pb-0">
|
||||
<button onclick="switchTab('assigned')" id="tabBtn_assigned" class="flex items-center space-x-1.5 px-3.5 py-2 text-xs font-bold rounded-xl transition cursor-pointer bg-indigo-50 dark:bg-indigo-950/50 text-indigo-600 dark:text-indigo-400 border border-indigo-200 dark:border-indigo-800/60 flex-shrink-0">
|
||||
<i data-lucide="user-check" class="w-3.5 h-3.5"></i>
|
||||
<span>Aan mij toegewezen</span>
|
||||
<span id="tabCount_assigned" class="px-2 py-0.5 rounded-full text-[10px] font-bold bg-indigo-200/70 dark:bg-indigo-800/60 text-indigo-800 dark:text-indigo-200">
|
||||
<span id="tabCount_assigned" class="px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-indigo-200/70 dark:bg-indigo-800/60 text-indigo-800 dark:text-indigo-200">
|
||||
<?= count($assignedIssues) ?>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button onclick="switchTab('team')" id="tabBtn_team" class="flex items-center space-x-2 px-4 py-2.5 text-xs font-bold rounded-xl transition cursor-pointer text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white hover:bg-slate-100 dark:hover:bg-slate-800/60">
|
||||
<i data-lucide="users" class="w-4 h-4"></i>
|
||||
<span>Mijn Teams & Projecten</span>
|
||||
<span id="tabCount_team" class="px-2 py-0.5 rounded-full text-[10px] font-bold bg-slate-200/80 dark:bg-slate-800 text-slate-700 dark:text-slate-300">
|
||||
<button onclick="switchTab('team')" id="tabBtn_team" class="flex items-center space-x-1.5 px-3.5 py-2 text-xs font-bold rounded-xl transition cursor-pointer text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white hover:bg-slate-100 dark:hover:bg-slate-800/60 border border-transparent flex-shrink-0">
|
||||
<i data-lucide="users" class="w-3.5 h-3.5"></i>
|
||||
<span>Teams & Projecten</span>
|
||||
<span id="tabCount_team" class="px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-slate-200/80 dark:bg-slate-800 text-slate-700 dark:text-slate-300">
|
||||
<?= count($teamIssues) ?>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button onclick="switchTab('in_progress')" id="tabBtn_in_progress" class="flex items-center space-x-2 px-4 py-2.5 text-xs font-bold rounded-xl transition cursor-pointer text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white hover:bg-slate-100 dark:hover:bg-slate-800/60">
|
||||
<i data-lucide="clock" class="w-4 h-4"></i>
|
||||
<button onclick="switchTab('in_progress')" id="tabBtn_in_progress" class="flex items-center space-x-1.5 px-3.5 py-2 text-xs font-bold rounded-xl transition cursor-pointer text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white hover:bg-slate-100 dark:hover:bg-slate-800/60 border border-transparent flex-shrink-0">
|
||||
<i data-lucide="clock" class="w-3.5 h-3.5"></i>
|
||||
<span>In Uitvoering</span>
|
||||
<span id="tabCount_in_progress" class="px-2 py-0.5 rounded-full text-[10px] font-bold bg-slate-200/80 dark:bg-slate-800 text-slate-700 dark:text-slate-300">
|
||||
<span id="tabCount_in_progress" class="px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-slate-200/80 dark:bg-slate-800 text-slate-700 dark:text-slate-300">
|
||||
0
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button onclick="switchTab('done')" id="tabBtn_done" class="flex items-center space-x-2 px-4 py-2.5 text-xs font-bold rounded-xl transition cursor-pointer text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white hover:bg-slate-100 dark:hover:bg-slate-800/60">
|
||||
<i data-lucide="check-circle" class="w-4 h-4"></i>
|
||||
<button onclick="switchTab('done')" id="tabBtn_done" class="flex items-center space-x-1.5 px-3.5 py-2 text-xs font-bold rounded-xl transition cursor-pointer text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white hover:bg-slate-100 dark:hover:bg-slate-800/60 border border-transparent flex-shrink-0">
|
||||
<i data-lucide="check-circle" class="w-3.5 h-3.5"></i>
|
||||
<span>Recent Afgerond</span>
|
||||
<span id="tabCount_done" class="px-2 py-0.5 rounded-full text-[10px] font-bold bg-slate-200/80 dark:bg-slate-800 text-slate-700 dark:text-slate-300">
|
||||
<span id="tabCount_done" class="px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-slate-200/80 dark:bg-slate-800 text-slate-700 dark:text-slate-300">
|
||||
0
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="text-[11px] text-slate-400 whitespace-nowrap pl-4 hidden sm:block">
|
||||
<span id="renderedCount">0</span> tickets getoond
|
||||
<!-- Rechterkant: Zoekveld & Tickets Tellen -->
|
||||
<div class="flex items-center space-x-2.5 w-full md:w-auto">
|
||||
<div class="relative flex-1 md:w-72">
|
||||
<i data-lucide="search" class="w-3.5 h-3.5 text-slate-400 absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none"></i>
|
||||
<input
|
||||
type="text"
|
||||
id="jiraSearchInput"
|
||||
placeholder="Zoek ticket (FOC-101) of titel..."
|
||||
oninput="applyFilters()"
|
||||
class="w-full bg-slate-50 dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-xl pl-8 pr-7 py-1.5 text-xs text-slate-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/40 transition placeholder-slate-400"
|
||||
>
|
||||
<button onclick="clearSearch()" id="clearSearchBtn" class="hidden absolute right-2 top-1/2 -translate-y-1/2 text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 cursor-pointer">
|
||||
<i data-lucide="x" class="w-3.5 h-3.5"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="text-[11px] text-slate-400 whitespace-nowrap hidden sm:block">
|
||||
<span id="renderedCount" class="font-bold text-slate-700 dark:text-slate-200">0</span> tickets
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -727,6 +723,44 @@ function calculateKpis() {
|
||||
document.getElementById('tabCount_done').innerText = doneCount;
|
||||
}
|
||||
|
||||
// Uitklappen en inklappen van de filters & statistieken drawer
|
||||
function toggleJiraFiltersDrawer(forceOpen) {
|
||||
const drawer = document.getElementById('jiraFiltersDrawer');
|
||||
const chevron = document.getElementById('filtersDrawerChevron');
|
||||
if (!drawer) return;
|
||||
|
||||
const willOpen = (typeof forceOpen === 'boolean') ? forceOpen : drawer.classList.contains('hidden');
|
||||
if (willOpen) {
|
||||
drawer.classList.remove('hidden');
|
||||
if (chevron) chevron.classList.add('rotate-180');
|
||||
localStorage.setItem('fociz_jira_filters_open', '1');
|
||||
} else {
|
||||
drawer.classList.add('hidden');
|
||||
if (chevron) chevron.classList.remove('rotate-180');
|
||||
localStorage.setItem('fociz_jira_filters_open', '0');
|
||||
}
|
||||
}
|
||||
|
||||
// Bepaal aantal actieve filters voor de badge in de rechter onderhoek
|
||||
function updateActiveFilterBadge() {
|
||||
const badge = document.getElementById('activeFilterBadge');
|
||||
if (!badge) return;
|
||||
|
||||
let activeCount = 0;
|
||||
if (currentProject) activeCount++;
|
||||
if (currentQueue) activeCount++;
|
||||
if (document.getElementById('filterType')?.value) activeCount++;
|
||||
if (document.getElementById('filterPriority')?.value) activeCount++;
|
||||
if (document.getElementById('filterStatus')?.value) activeCount++;
|
||||
|
||||
if (activeCount > 0) {
|
||||
badge.innerText = activeCount;
|
||||
badge.classList.remove('hidden');
|
||||
} else {
|
||||
badge.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
// Wissel tussen tabs
|
||||
function switchTab(tab) {
|
||||
currentTab = tab;
|
||||
@@ -738,9 +772,9 @@ function switchTab(tab) {
|
||||
const btn = document.getElementById(`tabBtn_${t}`);
|
||||
if (!btn) return;
|
||||
if (t === tab) {
|
||||
btn.className = "flex items-center space-x-2 px-4 py-2.5 text-xs font-bold rounded-xl transition cursor-pointer bg-indigo-50 dark:bg-indigo-950/50 text-indigo-600 dark:text-indigo-400 border-b-2 border-indigo-600 dark:border-indigo-400";
|
||||
btn.className = "flex items-center space-x-1.5 px-3.5 py-2 text-xs font-bold rounded-xl transition cursor-pointer bg-indigo-50 dark:bg-indigo-950/50 text-indigo-600 dark:text-indigo-400 border border-indigo-200 dark:border-indigo-800/60 flex-shrink-0";
|
||||
} else {
|
||||
btn.className = "flex items-center space-x-2 px-4 py-2.5 text-xs font-bold rounded-xl transition cursor-pointer text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white hover:bg-slate-100 dark:hover:bg-slate-800/60";
|
||||
btn.className = "flex items-center space-x-1.5 px-3.5 py-2 text-xs font-bold rounded-xl transition cursor-pointer text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white hover:bg-slate-100 dark:hover:bg-slate-800/60 border border-transparent flex-shrink-0";
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1027,6 +1061,7 @@ function applyFilters() {
|
||||
return true;
|
||||
});
|
||||
|
||||
updateActiveFilterBadge();
|
||||
renderTickets(filtered);
|
||||
}
|
||||
|
||||
@@ -1623,6 +1658,11 @@ document.addEventListener('keydown', function(e) {
|
||||
|
||||
// Initiële opstart
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Herstel filters drawer open/dicht status
|
||||
if (localStorage.getItem('fociz_jira_filters_open') === '1') {
|
||||
toggleJiraFiltersDrawer(true);
|
||||
}
|
||||
|
||||
calculateKpis();
|
||||
updateProjectPills();
|
||||
updateQueueCounts();
|
||||
|
||||
Reference in New Issue
Block a user