566 lines
29 KiB
PHP
566 lines
29 KiB
PHP
<?php
|
|
/**
|
|
* Fociz Interactief Brainstorm Canvas & Roadmap Converter
|
|
*/
|
|
|
|
require_once __DIR__ . '/includes/header.php';
|
|
require_once __DIR__ . '/includes/settings.php';
|
|
$db = get_db_connection();
|
|
$aiSettings = get_ai_settings();
|
|
|
|
$sessionId = (int)($_GET['id'] ?? 0);
|
|
$stmtSession = $db->prepare("
|
|
SELECT s.*, u.name as creator_name
|
|
FROM brainstorm_sessions s
|
|
JOIN users u ON s.created_by_id = u.id
|
|
WHERE s.id = ?
|
|
");
|
|
$stmtSession->execute([$sessionId]);
|
|
$session = $stmtSession->fetch();
|
|
|
|
if (!$session) {
|
|
echo "<div class='p-8 text-center text-red-500'>Brainstormsessie niet gevonden. <a href='/brainstorm.php' class='underline'>Terug</a></div>";
|
|
require_once __DIR__ . '/includes/footer.php';
|
|
exit;
|
|
}
|
|
|
|
// Haal alle kaarten op van deze sessie
|
|
$stmtCards = $db->prepare("
|
|
SELECT * FROM brainstorm_cards
|
|
WHERE session_id = ?
|
|
ORDER BY votes DESC, created_at ASC
|
|
");
|
|
$stmtCards->execute([$sessionId]);
|
|
$cards = $stmtCards->fetchAll();
|
|
|
|
$categories = [
|
|
'Ideeën' => [
|
|
'title' => 'Ideeën & Concepten',
|
|
'icon' => 'lightbulb',
|
|
'color' => 'amber',
|
|
'border' => 'border-amber-200/80 dark:border-amber-800/40',
|
|
'bg' => 'bg-amber-50/60 dark:bg-amber-950/20',
|
|
'badge' => 'bg-amber-500/15 text-amber-800 dark:text-amber-300'
|
|
],
|
|
'Knelpunten' => [
|
|
'title' => 'Knelpunten & Uitdagingen',
|
|
'icon' => 'alert-triangle',
|
|
'color' => 'rose',
|
|
'border' => 'border-rose-200/80 dark:border-rose-800/40',
|
|
'bg' => 'bg-rose-50/60 dark:bg-rose-950/20',
|
|
'badge' => 'bg-rose-500/15 text-rose-800 dark:text-rose-300'
|
|
],
|
|
'Oplossingen' => [
|
|
'title' => 'Oplossingen & Features',
|
|
'icon' => 'rocket',
|
|
'color' => 'teal',
|
|
'border' => 'border-teal-200/80 dark:border-teal-800/40',
|
|
'bg' => 'bg-teal-50/60 dark:bg-teal-950/20',
|
|
'badge' => 'bg-teal-500/15 text-teal-800 dark:text-teal-300'
|
|
],
|
|
'Quick Wins' => [
|
|
'title' => 'Quick Wins (Direct)',
|
|
'icon' => 'zap',
|
|
'color' => 'indigo',
|
|
'border' => 'border-indigo-200/80 dark:border-indigo-800/40',
|
|
'bg' => 'bg-indigo-50/60 dark:bg-indigo-950/20',
|
|
'badge' => 'bg-indigo-500/15 text-indigo-800 dark:text-indigo-300'
|
|
],
|
|
];
|
|
?>
|
|
|
|
<div class="space-y-6 max-w-7xl mx-auto">
|
|
<!-- Top Bar -->
|
|
<div class="fociz-card p-5 flex flex-col lg:flex-row lg:items-center justify-between gap-4">
|
|
<div class="flex items-center space-x-4">
|
|
<a href="/brainstorm.php" class="p-2.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white transition cursor-pointer">
|
|
<i data-lucide="arrow-left" class="w-5 h-5"></i>
|
|
</a>
|
|
<div>
|
|
<div class="flex items-center space-x-2 text-xs">
|
|
<span class="px-2.5 py-0.5 rounded-lg bg-indigo-50 dark:bg-indigo-500/10 text-indigo-700 dark:text-indigo-400 font-bold border border-indigo-200 dark:border-indigo-500/20">
|
|
<?= htmlspecialchars($session['theme']) ?>
|
|
</span>
|
|
<span class="text-slate-400 dark:text-slate-500">Gestart door <?= htmlspecialchars($session['creator_name']) ?></span>
|
|
</div>
|
|
<h1 class="text-xl sm:text-2xl font-black text-slate-900 dark:text-white tracking-tight mt-0.5">
|
|
<?= htmlspecialchars($session['title']) ?>
|
|
</h1>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-wrap items-center gap-2.5">
|
|
<?php if ($aiSettings['ai_enabled'] && $aiSettings['has_key']): ?>
|
|
<button onclick="aiGenerateIdeas(this)" class="flex items-center space-x-1.5 px-3 py-2 rounded-xl bg-violet-50 hover:bg-violet-100 dark:bg-violet-950/50 dark:hover:bg-violet-900/50 text-violet-700 dark:text-violet-300 border border-violet-200 dark:border-violet-800/60 text-xs font-bold transition cursor-pointer shadow-xs" title="Genereer 4 innovatieve ideeën via AI Co-Pilot">
|
|
<i data-lucide="sparkles" class="w-4 h-4 text-violet-500"></i>
|
|
<span>💡 AI Ideeën</span>
|
|
</button>
|
|
|
|
<button onclick="aiCategorizeCards(this)" class="flex items-center space-x-1.5 px-3 py-2 rounded-xl bg-indigo-50 hover:bg-indigo-100 dark:bg-indigo-950/50 dark:hover:bg-indigo-900/50 text-indigo-700 dark:text-indigo-300 border border-indigo-200 dark:border-indigo-800/60 text-xs font-bold transition cursor-pointer shadow-xs" title="Sorteer alle kaartjes automatisch in Ideeën, Knelpunten, Oplossingen of Quick Wins">
|
|
<i data-lucide="wand-2" class="w-4 h-4 text-indigo-500"></i>
|
|
<span>✨ Auto-Categoriseer</span>
|
|
</button>
|
|
<?php endif; ?>
|
|
|
|
<button onclick="openAddCardModal()" class="flex items-center space-x-1.5 px-3.5 py-2 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-200 text-xs font-bold border border-slate-200 dark:border-slate-700 transition cursor-pointer shadow-xs">
|
|
<i data-lucide="plus" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
|
|
<span>Nieuwe Kaart</span>
|
|
</button>
|
|
|
|
<!-- De Kernfeature: Zet om naar Roadmap! -->
|
|
<button onclick="openConvertModal()" class="flex items-center space-x-2 px-4 py-2 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-bold transition shadow-xs cursor-pointer">
|
|
<i data-lucide="map" class="w-4 h-4"></i>
|
|
<span>Zet om naar Roadmap</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Whiteboard Categorie Kolommen -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-5">
|
|
<?php foreach ($categories as $catKey => $catConfig):
|
|
$catCards = array_filter($cards, fn($c) => $c['category'] === $catKey);
|
|
?>
|
|
<div class="fociz-card p-4 flex flex-col min-h-[500px]">
|
|
<!-- Column Header -->
|
|
<div class="flex items-center justify-between pb-3 mb-3 border-b border-slate-100 dark:border-slate-800">
|
|
<div class="flex items-center space-x-2">
|
|
<i data-lucide="<?= $catConfig['icon'] ?>" class="w-4 h-4 text-<?= $catConfig['color'] ?>-500"></i>
|
|
<h3 class="text-xs font-bold text-slate-900 dark:text-white uppercase tracking-wider"><?= $catConfig['title'] ?></h3>
|
|
</div>
|
|
<span class="text-xs font-mono font-bold px-2 py-0.5 rounded-full bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400 border border-slate-200 dark:border-slate-700">
|
|
<?= count($catCards) ?>
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Cards Container -->
|
|
<div class="flex-1 space-y-3">
|
|
<?php if (empty($catCards)): ?>
|
|
<div class="py-8 text-center text-slate-400 dark:text-slate-600 text-xs font-medium">
|
|
Nog geen kaarten in deze categorie.
|
|
</div>
|
|
<?php else: ?>
|
|
<?php foreach ($catCards as $card): ?>
|
|
<div class="group relative rounded-xl p-4 border <?= $catConfig['border'] ?> <?= $catConfig['bg'] ?> backdrop-blur-sm shadow-2xs transition hover:-translate-y-0.5" id="card-<?= $card['id'] ?>">
|
|
|
|
<!-- Top: Checkbox voor selectie + Roadmap badge -->
|
|
<div class="flex items-center justify-between mb-2">
|
|
<label class="flex items-center space-x-2 cursor-pointer">
|
|
<input type="checkbox" value="<?= $card['id'] ?>" data-content="<?= htmlspecialchars($card['content'], ENT_QUOTES) ?>" class="card-checkbox w-4 h-4 rounded bg-white dark:bg-slate-900 border-slate-300 dark:border-slate-700 text-indigo-600 focus:ring-0">
|
|
<span class="text-[10px] text-slate-500 dark:text-slate-400 font-medium">Selecteer</span>
|
|
</label>
|
|
|
|
<?php if (!empty($card['converted_to_roadmap_item_id'])): ?>
|
|
<span class="px-2 py-0.5 rounded-md bg-teal-50 dark:bg-teal-500/15 text-teal-700 dark:text-teal-400 font-bold text-[10px] flex items-center space-x-1 border border-teal-200 dark:border-teal-500/20">
|
|
<i data-lucide="check" class="w-3 h-3"></i>
|
|
<span>Op Roadmap</span>
|
|
</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Inhoud -->
|
|
<p class="text-xs text-slate-800 dark:text-slate-200 leading-relaxed whitespace-pre-wrap font-medium">
|
|
<?= htmlspecialchars($card['content']) ?>
|
|
</p>
|
|
|
|
<!-- Footer van kaart -->
|
|
<div class="mt-3 pt-2.5 border-t border-slate-200/60 dark:border-slate-800/60 flex items-center justify-between text-[10px] text-slate-500 dark:text-slate-400">
|
|
<span><?= htmlspecialchars($card['author_name'] ?? 'Collega') ?></span>
|
|
|
|
<div class="flex items-center space-x-2">
|
|
<!-- Upvote button -->
|
|
<button onclick="voteCard(<?= $card['id'] ?>)" class="flex items-center space-x-1 px-2 py-1 rounded-lg bg-white/80 hover:bg-white dark:bg-slate-800/80 dark:hover:bg-slate-700 text-slate-600 dark:text-slate-300 hover:text-amber-500 dark:hover:text-amber-400 border border-slate-200/80 dark:border-transparent transition shadow-xs cursor-pointer">
|
|
<i data-lucide="thumbs-up" class="w-3 h-3"></i>
|
|
<span id="votes-<?= $card['id'] ?>" class="font-bold"><?= $card['votes'] ?></span>
|
|
</button>
|
|
|
|
<!-- Delete button -->
|
|
<button onclick="deleteCard(<?= $card['id'] ?>)" class="p-1 rounded text-slate-400 hover:text-rose-600 dark:text-slate-500 dark:hover:text-rose-400 transition opacity-0 group-hover:opacity-100 cursor-pointer">
|
|
<i data-lucide="trash-2" class="w-3.5 h-3.5"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Quick add button at column bottom -->
|
|
<button onclick="openAddCardModal('<?= $catKey ?>')" class="mt-3 w-full py-2 rounded-xl border border-dashed border-slate-200 dark:border-slate-800 hover:border-indigo-300 dark:hover:border-indigo-700/60 text-slate-400 hover:text-indigo-600 dark:hover:text-indigo-400 text-xs font-semibold transition flex items-center justify-center space-x-1 cursor-pointer">
|
|
<i data-lucide="plus" class="w-3.5 h-3.5"></i>
|
|
<span>Kaart toevoegen</span>
|
|
</button>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal: Nieuwe Kaart Toevoegen -->
|
|
<div id="addCardModal" onclick="if(event.target === this) closeAddCardModal()" 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 shadow-2xl max-w-md 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="sticky-note" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
|
|
<span>Brainstormkaart Toevoegen</span>
|
|
</h3>
|
|
<button onclick="closeAddCardModal()" class="p-1.5 text-slate-400 hover:text-slate-600 dark:hover:text-white rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition cursor-pointer">
|
|
<i data-lucide="x" class="w-4 h-4"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="space-y-4">
|
|
<div>
|
|
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Categorie</label>
|
|
<select id="modalCardCategory" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-2 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs">
|
|
<option value="Ideeën">💡 Ideeën & Concepten</option>
|
|
<option value="Knelpunten">⚠️ Knelpunten & Uitdagingen</option>
|
|
<option value="Oplossingen">🚀 Oplossingen & Features</option>
|
|
<option value="Quick Wins">⚡ Quick Wins</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Idee / Beschrijving</label>
|
|
<textarea id="modalCardContent" rows="4" placeholder="Schrijf hier uw inzicht, idee of knelpunt..." class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl p-3 text-slate-900 dark:text-white text-xs placeholder-slate-400 dark:placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 resize-none shadow-2xs"></textarea>
|
|
</div>
|
|
|
|
<div class="flex space-x-2 pt-2 border-t border-slate-100 dark:border-slate-800/80">
|
|
<button onclick="submitNewCard()" class="flex-1 bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-2.5 px-4 rounded-xl text-xs transition cursor-pointer shadow-xs">
|
|
Plaats op Canvas
|
|
</button>
|
|
<button onclick="closeAddCardModal()" class="px-4 py-2.5 bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-xl text-xs font-semibold transition cursor-pointer">
|
|
Annuleren
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal: Zet om naar Roadmap -->
|
|
<div id="convertModal" onclick="if(event.target === this) closeConvertModal()" 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 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="map" class="w-4 h-4 text-indigo-600 dark:text-indigo-400"></i>
|
|
<span>Zet Brainstorm om naar Roadmap</span>
|
|
</h3>
|
|
<button onclick="closeConvertModal()" class="p-1.5 text-slate-400 hover:text-slate-600 dark:hover:text-white rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition cursor-pointer">
|
|
<i data-lucide="x" class="w-4 h-4"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="space-y-4">
|
|
<div class="bg-indigo-50 dark:bg-indigo-500/10 border border-indigo-200 dark:border-indigo-500/20 rounded-xl p-3 text-xs text-indigo-800 dark:text-indigo-300 font-semibold">
|
|
<span id="selectedCountText" class="font-bold">0</span> kaarten geselecteerd om om te zetten naar planbare roadmap items.
|
|
</div>
|
|
|
|
<?php if ($aiSettings['ai_enabled'] && $aiSettings['has_key']): ?>
|
|
<div class="p-3 rounded-xl bg-violet-50 dark:bg-violet-950/40 border border-violet-200 dark:border-violet-800/60 flex items-center justify-between">
|
|
<div class="flex items-center space-x-2 text-xs text-violet-900 dark:text-violet-200">
|
|
<i data-lucide="sparkles" class="w-4 h-4 text-violet-500 flex-shrink-0"></i>
|
|
<span class="text-[11px] font-medium leading-tight">Laat AI Co-Pilot kwartaal, type & prioriteit adviseren</span>
|
|
</div>
|
|
<button type="button" onclick="aiSuggestRoadmapMeta(this)" id="aiSuggestBtn" class="px-2.5 py-1 bg-violet-600 hover:bg-violet-700 text-white rounded-lg text-xs font-bold transition flex items-center space-x-1 cursor-pointer flex-shrink-0 shadow-xs">
|
|
<span>✨ AI Advies</span>
|
|
</button>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="grid grid-cols-2 gap-3">
|
|
<div>
|
|
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Doel Kwartaal</label>
|
|
<select id="roadmapQuarter" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-2 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs">
|
|
<option value="Q1">Q1 (Jan - Mrt)</option>
|
|
<option value="Q2">Q2 (Apr - Jun)</option>
|
|
<option value="Q3" selected>Q3 (Jul - Sep)</option>
|
|
<option value="Q4">Q4 (Okt - Dec)</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Item Type</label>
|
|
<select id="roadmapType" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-2 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs">
|
|
<option value="FEATURE" selected>Feature / Functionaliteit</option>
|
|
<option value="EPIC">Epic (Groot project)</option>
|
|
<option value="MILESTONE">Mijlpaal</option>
|
|
<option value="TASK">Oplos-Taak</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 gap-3">
|
|
<div>
|
|
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Prioriteit</label>
|
|
<select id="roadmapPriority" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-2 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs">
|
|
<option value="HIGH" selected>Hoog (Belangrijke milestone)</option>
|
|
<option value="CRITICAL">Kritiek (Must-have)</option>
|
|
<option value="MEDIUM">Normaal</option>
|
|
<option value="LOW">Laag / Backlog</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1">Streefdatum (Deadline)</label>
|
|
<input type="date" id="roadmapDueDate" class="w-full bg-slate-50/70 dark:bg-[#0c0f17]/60 border border-slate-300 dark:border-slate-800 rounded-xl px-3 py-1.5 text-slate-900 dark:text-white text-xs focus:outline-none focus:ring-1 focus:ring-indigo-500 shadow-2xs">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex space-x-2 pt-2 border-t border-slate-100 dark:border-slate-800/80">
|
|
<button onclick="submitConvertToRoadmap()" class="flex-1 bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-2.5 px-4 rounded-xl text-xs transition shadow-xs flex items-center justify-center space-x-2 cursor-pointer">
|
|
<i data-lucide="check-circle" class="w-4 h-4"></i>
|
|
<span>Definitief Toevoegen aan Roadmap</span>
|
|
</button>
|
|
<button onclick="closeConvertModal()" class="px-4 py-2.5 bg-slate-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>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const sessionId = <?= $sessionId ?>;
|
|
|
|
function openAddCardModal(defaultCategory = null) {
|
|
if (defaultCategory) {
|
|
document.getElementById('modalCardCategory').value = defaultCategory;
|
|
}
|
|
document.getElementById('addCardModal').classList.remove('hidden');
|
|
document.getElementById('modalCardContent').focus();
|
|
}
|
|
|
|
function closeAddCardModal() {
|
|
document.getElementById('addCardModal').classList.add('hidden');
|
|
document.getElementById('modalCardContent').value = '';
|
|
}
|
|
|
|
async function submitNewCard() {
|
|
const category = document.getElementById('modalCardCategory').value;
|
|
const content = document.getElementById('modalCardContent').value.trim();
|
|
|
|
if (!content) return;
|
|
|
|
const res = await fetch('/api/brainstorm.php?action=add_card', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({ session_id: sessionId, category, content })
|
|
});
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
location.reload();
|
|
}
|
|
}
|
|
|
|
async function voteCard(cardId) {
|
|
const res = await fetch('/api/brainstorm.php?action=vote_card', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({ card_id: cardId })
|
|
});
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
document.getElementById(`votes-${cardId}`).innerText = data.votes;
|
|
}
|
|
}
|
|
|
|
async function deleteCard(cardId) {
|
|
if (!confirm('Kaart verwijderen?')) return;
|
|
await fetch('/api/brainstorm.php?action=delete_card', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({ card_id: cardId })
|
|
});
|
|
document.getElementById(`card-${cardId}`)?.remove();
|
|
}
|
|
|
|
// --- Roadmap Conversie Logica ---
|
|
function getSelectedCardIds() {
|
|
const checkboxes = document.querySelectorAll('.card-checkbox:checked');
|
|
return Array.from(checkboxes).map(cb => cb.value);
|
|
}
|
|
|
|
function openConvertModal() {
|
|
const selectedIds = getSelectedCardIds();
|
|
if (selectedIds.length === 0) {
|
|
alert('Vink eerst minimaal één kaart aan om om te zetten naar de roadmap.');
|
|
return;
|
|
}
|
|
document.getElementById('selectedCountText').innerText = selectedIds.length;
|
|
document.getElementById('convertModal').classList.remove('hidden');
|
|
}
|
|
|
|
function closeConvertModal() {
|
|
document.getElementById('convertModal').classList.add('hidden');
|
|
}
|
|
|
|
async function submitConvertToRoadmap() {
|
|
const cardIds = getSelectedCardIds();
|
|
const quarter = document.getElementById('roadmapQuarter').value;
|
|
const type = document.getElementById('roadmapType').value;
|
|
const priority = document.getElementById('roadmapPriority').value;
|
|
const dueDate = document.getElementById('roadmapDueDate').value;
|
|
|
|
const res = await fetch('/api/brainstorm.php?action=convert_to_roadmap', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({
|
|
card_ids: cardIds,
|
|
quarter,
|
|
type,
|
|
priority,
|
|
due_date: dueDate
|
|
})
|
|
});
|
|
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
alert(data.message);
|
|
window.location.href = '/roadmap.php';
|
|
} else {
|
|
alert(data.error || 'Er is een fout opgetreden.');
|
|
}
|
|
}
|
|
|
|
// --- AI Co-Pilot Canvas Assistentie (Release v1.5) ---
|
|
async function aiGenerateIdeas(btn) {
|
|
if (!confirm('Wil je AI Co-Pilot 4 innovatieve ideeën laten genereren en direct op het canvas plaatsen?')) return;
|
|
|
|
const origHtml = btn ? btn.innerHTML : '';
|
|
if (btn) {
|
|
btn.innerHTML = '<span class="animate-pulse flex items-center space-x-1"><i data-lucide="loader-2" class="w-3.5 h-3.5 animate-spin"></i><span>Genereren...</span></span>';
|
|
btn.disabled = true;
|
|
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
}
|
|
|
|
try {
|
|
const res = await fetch('/api/ai.php?action=generate_ideas', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({ session_id: sessionId, count: 4 })
|
|
});
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
location.reload();
|
|
} else {
|
|
alert(data.error || 'Kon geen ideeën genereren via AI');
|
|
if (btn) {
|
|
btn.innerHTML = origHtml;
|
|
btn.disabled = false;
|
|
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
}
|
|
}
|
|
} catch(err) {
|
|
alert('Netwerkfout bij aanroepen van AI');
|
|
if (btn) {
|
|
btn.innerHTML = origHtml;
|
|
btn.disabled = false;
|
|
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
}
|
|
}
|
|
}
|
|
|
|
async function aiCategorizeCards(btn) {
|
|
if (!confirm('Wil je dat AI Co-Pilot alle kaartjes automatisch classificeert in de juiste kolom (Ideeën, Knelpunten, Oplossingen of Quick Wins)?')) return;
|
|
|
|
const origHtml = btn ? btn.innerHTML : '';
|
|
if (btn) {
|
|
btn.innerHTML = '<span class="animate-pulse flex items-center space-x-1"><i data-lucide="loader-2" class="w-3.5 h-3.5 animate-spin"></i><span>Indelen...</span></span>';
|
|
btn.disabled = true;
|
|
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
}
|
|
|
|
try {
|
|
const res = await fetch('/api/ai.php?action=categorize_cards', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({ session_id: sessionId })
|
|
});
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
alert(`Succes! ${data.updated} kaartjes zijn door AI Co-Pilot opnieuw gecategoriseerd.`);
|
|
location.reload();
|
|
} else {
|
|
alert(data.error || 'Kon kaartjes niet categoriseren');
|
|
if (btn) {
|
|
btn.innerHTML = origHtml;
|
|
btn.disabled = false;
|
|
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
}
|
|
}
|
|
} catch(err) {
|
|
alert('Netwerkfout bij aanroepen van AI');
|
|
if (btn) {
|
|
btn.innerHTML = origHtml;
|
|
btn.disabled = false;
|
|
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
}
|
|
}
|
|
}
|
|
|
|
async function aiSuggestRoadmapMeta(btn) {
|
|
const checkboxes = document.querySelectorAll('.card-checkbox:checked');
|
|
if (checkboxes.length === 0) return;
|
|
const firstContent = checkboxes[0].dataset.content || '';
|
|
if (!firstContent) return;
|
|
|
|
const origHtml = btn ? btn.innerHTML : '';
|
|
if (btn) {
|
|
btn.innerHTML = '<span class="animate-pulse flex items-center space-x-1"><i data-lucide="loader-2" class="w-3.5 h-3.5 animate-spin"></i><span>Analyseren...</span></span>';
|
|
btn.disabled = true;
|
|
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
}
|
|
|
|
try {
|
|
const res = await fetch('/api/ai.php?action=summarize_to_roadmap', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({
|
|
content: firstContent,
|
|
session_title: '<?= htmlspecialchars(addslashes($session['title'])) ?>'
|
|
})
|
|
});
|
|
const data = await res.json();
|
|
if (data.success && data.item) {
|
|
if (data.item.quarter && document.getElementById('roadmapQuarter')) {
|
|
document.getElementById('roadmapQuarter').value = data.item.quarter;
|
|
}
|
|
if (data.item.type && document.getElementById('roadmapType')) {
|
|
document.getElementById('roadmapType').value = data.item.type;
|
|
}
|
|
if (data.item.priority && document.getElementById('roadmapPriority')) {
|
|
document.getElementById('roadmapPriority').value = data.item.priority;
|
|
}
|
|
if (btn) {
|
|
btn.innerHTML = '<i data-lucide="check" class="w-3.5 h-3.5"></i><span>Ingevuld!</span>';
|
|
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
setTimeout(() => {
|
|
btn.innerHTML = origHtml;
|
|
btn.disabled = false;
|
|
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
}, 1800);
|
|
}
|
|
} else {
|
|
alert(data.error || 'Kon geen AI advies ophalen');
|
|
if (btn) {
|
|
btn.innerHTML = origHtml;
|
|
btn.disabled = false;
|
|
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
}
|
|
}
|
|
} catch(err) {
|
|
alert('Netwerkfout bij ophalen van AI advies');
|
|
if (btn) {
|
|
btn.innerHTML = origHtml;
|
|
btn.disabled = false;
|
|
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
}
|
|
}
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') {
|
|
closeAddCardModal();
|
|
closeConvertModal();
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|