316 lines
17 KiB
PHP
316 lines
17 KiB
PHP
<?php
|
|
/**
|
|
* Fociz Brainstorm Sessies Overzicht
|
|
*/
|
|
|
|
require_once __DIR__ . '/includes/auth.php';
|
|
require_once __DIR__ . '/includes/settings.php';
|
|
$currentUser = require_auth();
|
|
$db = get_db_connection();
|
|
$brainstormCategories = get_brainstorm_categories();
|
|
|
|
// Verwerk nieuwe sessie aanmaken
|
|
$error = null;
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'create_session') {
|
|
$title = trim($_POST['title'] ?? '');
|
|
$theme = trim($_POST['category'] ?? ($_POST['theme'] ?? ''));
|
|
if (empty($theme) && !empty($brainstormCategories)) {
|
|
$firstActive = array_values(array_filter($brainstormCategories, fn($c) => !empty($c['is_active'])))[0] ?? null;
|
|
$theme = $firstActive ? $firstActive['name'] : 'Product & Strategie';
|
|
}
|
|
$description = trim($_POST['description'] ?? '');
|
|
|
|
|
|
if (!empty($title)) {
|
|
$stmt = $db->prepare("
|
|
INSERT INTO brainstorm_sessions (title, theme, description, created_by_id)
|
|
VALUES (?, ?, ?, ?)
|
|
");
|
|
$stmt->execute([$title, $theme, $description, $currentUser['id']]);
|
|
$newId = $db->lastInsertId();
|
|
header("Location: /brainstorm_canvas.php?id={$newId}");
|
|
exit;
|
|
} else {
|
|
$error = "Titel van de brainstormsessie is verplicht.";
|
|
}
|
|
}
|
|
|
|
// Haal alle sessies op
|
|
$sessions = [];
|
|
try {
|
|
$stmtSessions = $db->query("
|
|
SELECT s.*, u.name as creator_name,
|
|
(SELECT COUNT(*) FROM brainstorm_cards WHERE session_id = s.id) as cards_count
|
|
FROM brainstorm_sessions s
|
|
JOIN users u ON s.created_by_id = u.id
|
|
ORDER BY s.created_at DESC
|
|
");
|
|
$sessions = $stmtSessions->fetchAll() ?: [];
|
|
} catch (Throwable $e) {
|
|
error_log("Fout bij ophalen brainstorm sessies: " . $e->getMessage());
|
|
ensure_tables_exist($db);
|
|
}
|
|
require_once __DIR__ . '/includes/header.php';
|
|
?>
|
|
|
|
<div class="space-y-6 max-w-7xl mx-auto">
|
|
<!-- Header -->
|
|
<div class="fociz-card p-6 sm:p-7 flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
|
<div>
|
|
<div class="flex items-center space-x-2 text-indigo-600 dark:text-indigo-400 text-xs font-bold uppercase tracking-wider mb-1">
|
|
<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-slate-900 dark:text-white tracking-tight">
|
|
Brainstorm Sessies
|
|
</h1>
|
|
<p class="text-slate-500 dark:text-slate-400 text-xs sm:text-sm mt-1 max-w-2xl">
|
|
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-indigo-600 hover:bg-indigo-500 text-white text-xs font-bold transition shadow-xs 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-rose-50 dark:bg-rose-500/10 border border-rose-200 dark:border-rose-500/30 text-rose-700 dark:text-rose-400 text-sm">
|
|
<?= htmlspecialchars($error) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- 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 fociz-card p-12 text-center shadow-xs">
|
|
<i data-lucide="lightbulb" class="w-12 h-12 text-slate-300 dark:text-slate-700 mx-auto mb-3"></i>
|
|
<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-indigo-600 hover:bg-indigo-500 text-white font-bold rounded-xl text-xs transition cursor-pointer shadow-xs">
|
|
Sessie Starten
|
|
</button>
|
|
</div>
|
|
<?php else: ?>
|
|
<?php foreach ($sessions as $sess):
|
|
$canDelete = ($currentUser['role'] === 'ADMIN' || (int)$sess['created_by_id'] === (int)$currentUser['id']);
|
|
?>
|
|
<div class="group fociz-card-interactive p-5 flex flex-col justify-between hover:border-indigo-400 dark:hover:border-indigo-500/60 relative">
|
|
<a href="/brainstorm_canvas.php?id=<?= $sess['id'] ?>" class="block flex-1">
|
|
<div class="flex items-center justify-between mb-3">
|
|
<span class="px-2.5 py-0.5 rounded-lg bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 text-indigo-700 dark:text-indigo-400 font-semibold text-[11px]">
|
|
<?= htmlspecialchars($sess['theme']) ?>
|
|
</span>
|
|
<span class="flex items-center space-x-1 text-slate-400 dark:text-slate-500 text-xs font-medium">
|
|
<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-slate-900 dark:text-white group-hover:text-indigo-600 dark:group-hover:text-indigo-400 transition leading-snug">
|
|
<?= htmlspecialchars($sess['title']) ?>
|
|
</h3>
|
|
|
|
<?php if (!empty($sess['description'])): ?>
|
|
<p class="text-slate-600 dark:text-slate-400 text-xs mt-2 line-clamp-2 leading-relaxed">
|
|
<?= htmlspecialchars($sess['description']) ?>
|
|
</p>
|
|
<?php endif; ?>
|
|
</a>
|
|
|
|
<div class="mt-5 pt-4 border-t border-slate-100 dark:border-slate-800/80 flex items-center justify-between text-xs text-slate-500 dark:text-slate-400">
|
|
<span class="truncate">Door <?= htmlspecialchars($sess['creator_name']) ?></span>
|
|
<div class="flex items-center space-x-2 flex-shrink-0 ml-2">
|
|
<?php if ($canDelete): ?>
|
|
<button
|
|
type="button"
|
|
onclick="promptDeleteSession(event, <?= (int)$sess['id'] ?>, '<?= htmlspecialchars(addslashes($sess['title']), ENT_QUOTES) ?>', <?= (int)$sess['cards_count'] ?>)"
|
|
class="p-1.5 rounded-lg text-slate-400 hover:text-rose-600 dark:hover:text-rose-400 hover:bg-rose-50 dark:hover:bg-rose-500/10 transition cursor-pointer"
|
|
title="Sessie verwijderen"
|
|
>
|
|
<i data-lucide="trash-2" class="w-4 h-4"></i>
|
|
</button>
|
|
<?php endif; ?>
|
|
<a href="/brainstorm_canvas.php?id=<?= $sess['id'] ?>" class="flex items-center space-x-1 text-indigo-600 dark:text-indigo-400 group-hover:translate-x-1 transition font-bold">
|
|
<span>Open canvas</span>
|
|
<i data-lucide="arrow-right" class="w-3.5 h-3.5"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal: Nieuwe sessie -->
|
|
<div id="newSessionModal" onclick="if(event.target === this) this.classList.add('hidden')" class="hidden fixed inset-0 z-50 bg-slate-950/70 backdrop-blur-sm flex items-center justify-center p-4">
|
|
<div class="fociz-card p-6 sm:p-7 shadow-2xl max-w-lg w-full space-y-4">
|
|
<div class="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 flex items-center space-x-2">
|
|
<i data-lucide="sparkles" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
|
|
<span>Nieuwe Brainstormsessie</span>
|
|
</h3>
|
|
<button onclick="document.getElementById('newSessionModal').classList.add('hidden')" class="p-1.5 text-slate-400 hover:text-slate-600 dark:hover:text-white rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition cursor-pointer">
|
|
<i data-lucide="x" class="w-4 h-4"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<form method="POST" action="/brainstorm.php" class="space-y-4">
|
|
<input type="hidden" name="action" value="create_session">
|
|
|
|
<div>
|
|
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Onderwerp / Titel</label>
|
|
<input type="text" name="title" required placeholder="Bijv. Q4 Automatisering & Klantreis" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3.5 py-2.5 text-slate-900 dark:text-white text-xs placeholder-slate-400 dark:placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs">
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
|
<div>
|
|
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Categorie</label>
|
|
<select name="category" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-2 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs">
|
|
<?php
|
|
$hasActiveCategory = false;
|
|
foreach ($brainstormCategories as $bCat):
|
|
if (isset($bCat['is_active']) && empty($bCat['is_active'])) continue;
|
|
$hasActiveCategory = true;
|
|
?>
|
|
<option value="<?= htmlspecialchars($bCat['name']) ?>"><?= htmlspecialchars($bCat['name']) ?></option>
|
|
<?php endforeach; ?>
|
|
<?php if (!$hasActiveCategory): ?>
|
|
<option value="Product & Strategie">Product & Strategie</option>
|
|
<option value="Procesverbetering">Procesverbetering</option>
|
|
<option value="Klant & Service">Klant & Service</option>
|
|
<option value="Technologie & IT">Technologie & IT</option>
|
|
<option value="Marketing & Groei">Marketing & Groei</option>
|
|
<?php endif; ?>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Doel / Beschrijving</label>
|
|
<input type="text" name="description" placeholder="Doel van deze sessie..." class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3.5 py-2.5 text-slate-900 dark:text-white text-xs placeholder-slate-400 dark:placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex space-x-2 pt-2 border-t border-slate-100 dark:border-slate-800/80">
|
|
<button type="submit" class="flex-1 bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-2.5 px-4 rounded-xl text-xs transition cursor-pointer shadow-xs">
|
|
Sessie Aanmaken & Canvas Openen
|
|
</button>
|
|
<button type="button" onclick="document.getElementById('newSessionModal').classList.add('hidden')" class="px-4 py-2.5 bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-xl text-xs font-semibold transition cursor-pointer">
|
|
Annuleren
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal: Sessie Verwijderen Bevestiging -->
|
|
<div id="deleteSessionModal" onclick="if(event.target === this) closeDeleteSessionModal()" class="hidden fixed inset-0 z-50 bg-slate-950/70 backdrop-blur-sm flex items-center justify-center p-4">
|
|
<div class="fociz-card p-6 sm:p-7 shadow-2xl max-w-md w-full space-y-4">
|
|
<div class="flex items-start space-x-3.5 pb-2">
|
|
<div class="w-10 h-10 rounded-xl bg-rose-50 dark:bg-rose-500/10 border border-rose-200 dark:border-rose-500/20 text-rose-600 dark:text-rose-400 flex items-center justify-center flex-shrink-0">
|
|
<i data-lucide="alert-triangle" class="w-5 h-5"></i>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-base font-bold text-slate-900 dark:text-white">Brainstormsessie verwijderen</h3>
|
|
<p class="text-xs text-slate-500 dark:text-slate-400 mt-1">
|
|
Weet u zeker dat u deze sessie wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="p-3.5 rounded-xl bg-rose-50/60 dark:bg-rose-950/20 border border-rose-200/80 dark:border-rose-900/40 text-xs text-rose-800 dark:text-rose-300 space-y-1">
|
|
<p class="font-bold text-slate-900 dark:text-white" id="deleteSessionTitle">—</p>
|
|
<p id="deleteSessionWarning" class="text-[11px] text-rose-700 dark:text-rose-400">
|
|
Alle bijbehorende ideeën, knelpunten en kaarten worden definitief gewist.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="flex space-x-2 pt-2 border-t border-slate-100 dark:border-slate-800/80">
|
|
<button type="button" onclick="closeDeleteSessionModal()" class="flex-1 px-4 py-2.5 bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-xl text-xs font-semibold transition cursor-pointer">
|
|
Annuleren
|
|
</button>
|
|
<button type="button" id="btnConfirmDeleteSession" onclick="executeDeleteSession()" class="flex-1 px-4 py-2.5 bg-rose-600 hover:bg-rose-500 text-white font-bold rounded-xl text-xs transition cursor-pointer shadow-xs flex items-center justify-center space-x-1.5">
|
|
<i data-lucide="trash-2" class="w-4 h-4"></i>
|
|
<span>Verwijderen</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let sessionToDeleteId = null;
|
|
|
|
function promptDeleteSession(e, sessionId, sessionTitle, cardsCount) {
|
|
if (e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
sessionToDeleteId = sessionId;
|
|
document.getElementById('deleteSessionTitle').textContent = sessionTitle || 'Brainstormsessie';
|
|
const warningEl = document.getElementById('deleteSessionWarning');
|
|
if (cardsCount > 0) {
|
|
warningEl.textContent = `Let op: Deze sessie bevat ${cardsCount} brainstormkaart(en). Alle kaarten worden definitief verwijderd.`;
|
|
} else {
|
|
warningEl.textContent = 'Alle inhoud van deze sessie wordt definitief gewist.';
|
|
}
|
|
const modal = document.getElementById('deleteSessionModal');
|
|
modal.classList.remove('hidden');
|
|
modal.classList.add('flex');
|
|
if (window.lucide) lucide.createIcons();
|
|
}
|
|
|
|
function closeDeleteSessionModal() {
|
|
sessionToDeleteId = null;
|
|
const modal = document.getElementById('deleteSessionModal');
|
|
modal.classList.add('hidden');
|
|
modal.classList.remove('flex');
|
|
}
|
|
|
|
async function executeDeleteSession() {
|
|
if (!sessionToDeleteId) return;
|
|
|
|
const btn = document.getElementById('btnConfirmDeleteSession');
|
|
const origHtml = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<i data-lucide="loader-2" class="w-4 h-4 animate-spin"></i><span>Verwijderen...</span>';
|
|
if (window.lucide) lucide.createIcons();
|
|
|
|
try {
|
|
const res = await fetch('/api/brainstorm.php?action=delete_session', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ session_id: sessionToDeleteId })
|
|
});
|
|
const data = await res.json();
|
|
|
|
if (data.success) {
|
|
closeDeleteSessionModal();
|
|
window.location.reload();
|
|
} else {
|
|
alert('Fout bij verwijderen: ' + (data.error || 'Onbekende fout'));
|
|
btn.disabled = false;
|
|
btn.innerHTML = origHtml;
|
|
if (window.lucide) lucide.createIcons();
|
|
}
|
|
} catch (err) {
|
|
alert('Netwerkfout bij verwijderen: ' + err.message);
|
|
btn.disabled = false;
|
|
btn.innerHTML = origHtml;
|
|
if (window.lucide) lucide.createIcons();
|
|
}
|
|
}
|
|
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') {
|
|
const modal = document.getElementById('newSessionModal');
|
|
if (modal) modal.classList.add('hidden');
|
|
closeDeleteSessionModal();
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|