378 lines
14 KiB
PHP
378 lines
14 KiB
PHP
<?php
|
|
/**
|
|
* AJAX API voor Brainstorm Sessies, Kaarten & Omzetten naar Roadmap
|
|
*/
|
|
|
|
require_once __DIR__ . '/../includes/auth.php';
|
|
$user = require_auth();
|
|
$db = get_db_connection();
|
|
|
|
header('Content-Type: application/json');
|
|
|
|
$action = $_GET['action'] ?? ($_POST['action'] ?? '');
|
|
|
|
try {
|
|
// 1. Brainstormkaart toevoegen
|
|
if ($action === 'add_card') {
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
$sessionId = (int)($data['session_id'] ?? 0);
|
|
$content = trim($data['content'] ?? '');
|
|
$category = $data['category'] ?? 'Ideeën';
|
|
$color = $data['color'] ?? 'amber';
|
|
|
|
if (empty($content)) {
|
|
echo json_encode(['error' => '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;
|
|
}
|
|
|
|
echo json_encode(['error' => 'Onbekende actie']);
|
|
} catch (Exception $e) {
|
|
if ($db->inTransaction()) $db->rollBack();
|
|
http_response_code(500);
|
|
echo json_encode(['error' => $e->getMessage()]);
|
|
}
|
|
|