'Inhoud is verplicht']); exit; } $stmt = $db->prepare(" INSERT INTO brainstorm_cards (session_id, content, category, color, author_name, votes) VALUES (?, ?, ?, ?, ?, 0) "); $stmt->execute([$sessionId, $content, $category, $color, $user['name']]); $cardId = (int)$db->lastInsertId(); echo json_encode([ 'success' => true, 'card' => [ 'id' => $cardId, 'content' => $content, 'category' => $category, 'color' => $color, 'author_name' => $user['name'], 'votes' => 0, 'converted_to_roadmap_item_id' => null ] ]); exit; } // 2. Stemmen / Upvote op kaart (met bescherming tegen oneindig stemmen) if ($action === 'vote_card') { $data = json_decode(file_get_contents('php://input'), true); $cardId = (int)($data['card_id'] ?? 0); if (!isset($_SESSION['voted_cards'])) { $_SESSION['voted_cards'] = []; } if (in_array($cardId, $_SESSION['voted_cards'])) { $stmtVotes = $db->prepare("SELECT votes FROM brainstorm_cards WHERE id = ?"); $stmtVotes->execute([$cardId]); $votes = (int)$stmtVotes->fetchColumn(); echo json_encode(['success' => false, 'error' => 'U heeft al op deze kaart gestemd.', 'votes' => $votes]); exit; } $_SESSION['voted_cards'][] = $cardId; $stmt = $db->prepare("UPDATE brainstorm_cards SET votes = votes + 1 WHERE id = ?"); $stmt->execute([$cardId]); $stmtVotes = $db->prepare("SELECT votes FROM brainstorm_cards WHERE id = ?"); $stmtVotes->execute([$cardId]); $votes = (int)$stmtVotes->fetchColumn(); echo json_encode(['success' => true, 'votes' => $votes]); exit; } // 3. Kaart verwijderen (met autorisatiecontrole: auteur, sessie-eigenaar of beheerder) if ($action === 'delete_card') { $data = json_decode(file_get_contents('php://input'), true); $cardId = (int)($data['card_id'] ?? 0); $stmtCheck = $db->prepare(" SELECT c.*, s.created_by_id as session_owner_id FROM brainstorm_cards c JOIN brainstorm_sessions s ON c.session_id = s.id WHERE c.id = ? "); $stmtCheck->execute([$cardId]); $card = $stmtCheck->fetch(); if (!$card) { echo json_encode(['error' => 'Kaart niet gevonden']); exit; } $isAuthor = ($card['author_name'] === $user['name']); $isSessionOwner = ((int)$card['session_owner_id'] === (int)$user['id']); $isAdmin = ($user['role'] === 'ADMIN'); if (!$isAuthor && !$isSessionOwner && !$isAdmin) { http_response_code(403); echo json_encode(['error' => 'Geen toestemming om deze kaart te verwijderen.']); exit; } $stmt = $db->prepare("DELETE FROM brainstorm_cards WHERE id = ?"); $stmt->execute([$cardId]); echo json_encode(['success' => true]); exit; } // 3b. Kaart verplaatsen naar andere categorie/lane (Drag & Drop) if ($action === 'move_card') { $data = json_decode(file_get_contents('php://input'), true); $cardId = (int)($data['card_id'] ?? 0); $category = trim($data['category'] ?? ''); $validCategories = ['Ideeën', 'Knelpunten', 'Oplossingen', 'Quick Wins']; if (!$cardId || !in_array($category, $validCategories, true)) { echo json_encode(['error' => 'Ongeldige kaart of categorie']); exit; } // Bepaal kleur behorend bij de nieuwe categorie $colorMap = [ 'Ideeën' => 'amber', 'Knelpunten' => 'rose', 'Oplossingen' => 'teal', 'Quick Wins' => 'indigo' ]; $newColor = $colorMap[$category] ?? 'amber'; $stmt = $db->prepare("UPDATE brainstorm_cards SET category = ?, color = ? WHERE id = ?"); $stmt->execute([$category, $newColor, $cardId]); echo json_encode([ 'success' => true, 'card_id' => $cardId, 'category' => $category, 'color' => $newColor ]); exit; } // 3c. Kaart bewerken (Inhoud, Categorie en/of Kleur) if ($action === 'update_card') { $data = json_decode(file_get_contents('php://input'), true) ?: $_POST; $cardId = (int)($data['card_id'] ?? 0); $content = trim($data['content'] ?? ''); $category = trim($data['category'] ?? ''); if (!$cardId || empty($content)) { echo json_encode(['error' => 'Kaart ID en inhoud zijn verplicht']); exit; } $colorMap = [ 'Ideeën' => 'amber', 'Knelpunten' => 'rose', 'Oplossingen' => 'teal', 'Quick Wins' => 'indigo' ]; $color = $colorMap[$category] ?? 'amber'; if (!empty($category)) { $stmt = $db->prepare("UPDATE brainstorm_cards SET content = ?, category = ?, color = ? WHERE id = ?"); $stmt->execute([$content, $category, $color, $cardId]); } else { $stmt = $db->prepare("UPDATE brainstorm_cards SET content = ? WHERE id = ?"); $stmt->execute([$content, $cardId]); } echo json_encode(['success' => true, 'card_id' => $cardId, 'content' => $content, 'category' => $category, 'color' => $color]); exit; } // 3d. Kaart toewijzen aan collega en inplannen in agenda (Vrij blok) if ($action === 'assign_and_schedule') { $data = json_decode(file_get_contents('php://input'), true) ?: $_POST; $cardId = (int)($data['card_id'] ?? 0); $assigneeId = !empty($data['assignee_id']) ? (int)$data['assignee_id'] : null; $planDate = !empty($data['plan_date']) ? trim($data['plan_date']) : null; $startTime = !empty($data['start_time']) ? trim($data['start_time']) : null; $endTime = !empty($data['end_time']) ? trim($data['end_time']) : null; $durationMinutes = (int)($data['duration_minutes'] ?? 30); $syncOutlook = !empty($data['sync_outlook']); if (!$cardId) { echo json_encode(['error' => 'Kaart ID ontbreekt']); exit; } $stmtCard = $db->prepare("SELECT * FROM brainstorm_cards WHERE id = ?"); $stmtCard->execute([$cardId]); $card = $stmtCard->fetch(); if (!$card) { echo json_encode(['error' => 'Kaart niet gevonden']); exit; } // Bereken eindtijd indien nodig if ($startTime && !$endTime && $durationMinutes > 0) { $tParts = explode(':', $startTime); $startMins = ((int)$tParts[0] * 60) + (int)($tParts[1] ?? 0); $endMins = $startMins + $durationMinutes; $endTime = sprintf('%02d:%02d', floor($endMins / 60), $endMins % 60); } $createdTaskId = null; $outlookSyncMsg = null; // Als er een datum & tijd is gekozen én een collega (of huidige gebruiker) if ($assigneeId && $planDate && $startTime) { // Zoek of maak daily plan $stmtPlan = $db->prepare(" INSERT INTO daily_plans (user_id, plan_date) VALUES (?, ?) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id) "); $stmtPlan->execute([$assigneeId, $planDate]); $planId = (int)$db->lastInsertId(); $taskTitle = "Brainstorm taak: " . mb_substr($card['content'], 0, 75); $taskDesc = "Afkomstig van Brainstormsessie. Inhoud:\n" . $card['content']; $source = 'BRAINSTORM'; $externalId = null; $externalUrl = null; // Indien Outlook sync gewenst is if ($syncOutlook) { require_once __DIR__ . '/../includes/integrations/microsoft.php'; try { $msResult = microsoft_create_event($assigneeId, [ 'subject' => $taskTitle, 'description' => $taskDesc, 'date' => $planDate, 'start_time' => $startTime, 'end_time' => $endTime, 'duration_minutes' => $durationMinutes, ]); if (!empty($msResult['success']) && !empty($msResult['event_id'])) { $source = 'OUTLOOK'; $externalId = $msResult['event_id']; $externalUrl = $msResult['web_link'] ?? null; $outlookSyncMsg = 'Ingepland in Outlook 365 agenda.'; } } catch (Throwable $t) { // stil doorgaan } } // Maak of update taak if (!empty($card['scheduled_task_id'])) { $stmtUpdateTask = $db->prepare(" UPDATE tasks SET user_id = ?, daily_plan_id = ?, title = ?, description = ?, time_block_start = ?, time_block_end = ?, duration_minutes = ? WHERE id = ? "); $stmtUpdateTask->execute([$assigneeId, $planId, $taskTitle, $taskDesc, $startTime, $endTime, $durationMinutes, $card['scheduled_task_id']]); $createdTaskId = (int)$card['scheduled_task_id']; } else { $stmtInsertTask = $db->prepare(" INSERT INTO tasks (user_id, daily_plan_id, title, description, priority, time_block_start, time_block_end, duration_minutes, status, source, external_id, external_url) VALUES (?, ?, ?, ?, 'P2', ?, ?, ?, 'TODO', ?, ?, ?) "); $stmtInsertTask->execute([$assigneeId, $planId, $taskTitle, $taskDesc, $startTime, $endTime, $durationMinutes, $source, $externalId, $externalUrl]); $createdTaskId = (int)$db->lastInsertId(); } } // Update brainstorm kaart $stmtUpdateCard = $db->prepare(" UPDATE brainstorm_cards SET assignee_id = ?, scheduled_date = ?, scheduled_start_time = ?, scheduled_end_time = ?, scheduled_task_id = ? WHERE id = ? "); $stmtUpdateCard->execute([$assigneeId, $planDate, $startTime, $endTime, $createdTaskId, $cardId]); // Haal assignee naam & avatar op $assigneeName = null; $assigneeAvatar = null; if ($assigneeId) { $stmtUser = $db->prepare("SELECT name, avatar_url FROM users WHERE id = ?"); $stmtUser->execute([$assigneeId]); $usr = $stmtUser->fetch(); if ($usr) { $assigneeName = $usr['name']; $assigneeAvatar = $usr['avatar_url']; } } echo json_encode([ 'success' => true, 'card_id' => $cardId, 'assignee_id' => $assigneeId, 'assignee_name' => $assigneeName, 'assignee_avatar' => $assigneeAvatar, 'scheduled_date' => $planDate, 'scheduled_start_time' => $startTime, 'scheduled_end_time' => $endTime, 'scheduled_task_id' => $createdTaskId, 'outlook_message' => $outlookSyncMsg ]); exit; } if ($action === 'convert_to_roadmap') { $data = json_decode(file_get_contents('php://input'), true); $cardIds = $data['card_ids'] ?? []; $quarter = $data['quarter'] ?? 'Q3'; $type = $data['type'] ?? 'FEATURE'; $priority = $data['priority'] ?? 'MEDIUM'; $dueDate = !empty($data['due_date']) ? $data['due_date'] : null; if (empty($cardIds) || !is_array($cardIds)) { echo json_encode(['error' => 'Selecteer ten minste één kaart om om te zetten.']); exit; } $db->beginTransaction(); $convertedCount = 0; foreach ($cardIds as $cardId) { $cardId = (int)$cardId; $stmtCard = $db->prepare("SELECT * FROM brainstorm_cards WHERE id = ?"); $stmtCard->execute([$cardId]); $card = $stmtCard->fetch(); if ($card) { // Maak titel (eerste zin of max 80 tekens) $firstLine = explode("\n", trim($card['content']))[0]; $title = mb_substr($firstLine, 0, 80); $stmtRoadmap = $db->prepare(" INSERT INTO roadmap_items (title, description, type, status, quarter, priority, progress, due_date, origin_brainstorm_card_id, created_by_id) VALUES (?, ?, ?, 'PLANNED', ?, ?, 0, ?, ?, ?) "); $stmtRoadmap->execute([ $title, $card['content'], $type, $quarter, $priority, $dueDate, $cardId, $user['id'] ]); $roadmapId = (int)$db->lastInsertId(); // Koppel terug aan brainstorm kaart $stmtUpdateCard = $db->prepare("UPDATE brainstorm_cards SET converted_to_roadmap_item_id = ? WHERE id = ?"); $stmtUpdateCard->execute([$roadmapId, $cardId]); $convertedCount++; } } $db->commit(); echo json_encode([ 'success' => true, 'message' => "{$convertedCount} brainstorm items succesvol omgezet naar de Roadmap!", 'converted_count' => $convertedCount ]); exit; } // 5. Brainstormsessie verwijderen (inclusief bijbehorende kaarten) if ($action === 'delete_session') { $data = json_decode(file_get_contents('php://input'), true) ?: $_POST; $sessionId = (int)($data['session_id'] ?? 0); if (!$sessionId) { echo json_encode(['success' => false, 'error' => 'Geen geldig sessie ID opgegeven.']); exit; } $stmtCheck = $db->prepare("SELECT id, title, created_by_id FROM brainstorm_sessions WHERE id = ?"); $stmtCheck->execute([$sessionId]); $session = $stmtCheck->fetch(); if (!$session) { echo json_encode(['success' => false, 'error' => 'Brainstormsessie niet gevonden.']); exit; } $isCreator = ((int)$session['created_by_id'] === (int)$user['id']); $isAdmin = ($user['role'] === 'ADMIN'); if (!$isCreator && !$isAdmin) { http_response_code(403); echo json_encode(['success' => false, 'error' => 'Alleen de maker van deze sessie of een beheerder kan deze verwijderen.']); exit; } $db->beginTransaction(); try { // Verwijder kaarten behorend bij deze sessie $stmtDelCards = $db->prepare("DELETE FROM brainstorm_cards WHERE session_id = ?"); $stmtDelCards->execute([$sessionId]); // Verwijder de sessie zelf $stmtDelSession = $db->prepare("DELETE FROM brainstorm_sessions WHERE id = ?"); $stmtDelSession->execute([$sessionId]); $db->commit(); echo json_encode(['success' => true, 'message' => 'Brainstormsessie en alle bijbehorende kaarten zijn definitief verwijderd.']); exit; } catch (Throwable $t) { if ($db->inTransaction()) $db->rollBack(); throw $t; } } echo json_encode(['error' => 'Onbekende actie']); } catch (Exception $e) { if ($db->inTransaction()) $db->rollBack(); http_response_code(500); echo json_encode(['error' => $e->getMessage()]); }