Add roadmap management feature with database schema and user management
- Implemented roadmap.php for displaying and managing roadmap items with filters for quarter and status. - Created schema.sql to define the database structure for users, invites, daily plans, tasks, brainstorm sessions, brainstorm cards, roadmap items, and integrations. - Developed users.php for admin panel to manage team members and invitations, including functionality to create and revoke invites.
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
<?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
|
||||
if ($action === 'vote_card') {
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$cardId = (int)($data['card_id'] ?? 0);
|
||||
|
||||
$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
|
||||
if ($action === 'delete_card') {
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$cardId = (int)($data['card_id'] ?? 0);
|
||||
|
||||
$stmt = $db->prepare("DELETE FROM brainstorm_cards WHERE id = ?");
|
||||
$stmt->execute([$cardId]);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 4. Omzetten naar Roadmap!
|
||||
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()]);
|
||||
}
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* AJAX API voor Dagplanning & Taken
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../includes/auth.php';
|
||||
$user = require_auth();
|
||||
$db = get_db_connection();
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$action = $_GET['action'] ?? ($_POST['action'] ?? '');
|
||||
$today = date('Y-m-d');
|
||||
|
||||
try {
|
||||
// 1. Dagdoel of notities opslaan
|
||||
if ($action === 'save_goal') {
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$date = $data['date'] ?? $today;
|
||||
$focusGoal = $data['focus_goal'] ?? '';
|
||||
$notes = $data['notes'] ?? '';
|
||||
|
||||
$stmt = $db->prepare("
|
||||
INSERT INTO daily_plans (user_id, plan_date, focus_goal, notes)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE focus_goal = VALUES(focus_goal), notes = VALUES(notes)
|
||||
");
|
||||
$stmt->execute([$user['id'], $date, $focusGoal, $notes]);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 2. Taak toevoegen
|
||||
if ($action === 'add_task') {
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$title = trim($data['title'] ?? '');
|
||||
$priority = in_array($data['priority'] ?? '', ['P1', 'P2', 'P3']) ? $data['priority'] : 'P2';
|
||||
$timeBlockStart = $data['time_block_start'] ?? null;
|
||||
$date = $data['date'] ?? $today;
|
||||
|
||||
if (empty($title)) {
|
||||
echo json_encode(['error' => 'Titel is verplicht']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Haal of maak daily plan op
|
||||
$stmtPlan = $db->prepare("
|
||||
INSERT INTO daily_plans (user_id, plan_date)
|
||||
VALUES (?, ?)
|
||||
ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id)
|
||||
");
|
||||
$stmtPlan->execute([$user['id'], $date]);
|
||||
$planId = $db->lastInsertId();
|
||||
|
||||
$stmt = $db->prepare("
|
||||
INSERT INTO tasks (user_id, daily_plan_id, title, priority, time_block_start, status)
|
||||
VALUES (?, ?, ?, ?, ?, 'TODO')
|
||||
");
|
||||
$stmt->execute([$user['id'], $planId, $title, $priority, $timeBlockStart]);
|
||||
$taskId = (int)$db->lastInsertId();
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'task' => [
|
||||
'id' => $taskId,
|
||||
'title' => $title,
|
||||
'priority' => $priority,
|
||||
'time_block_start' => $timeBlockStart,
|
||||
'is_completed' => 0,
|
||||
'status' => 'TODO'
|
||||
]
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 3. Taak status toggelen (voltooid / open)
|
||||
if ($action === 'toggle_task') {
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$taskId = (int)($data['task_id'] ?? 0);
|
||||
$isCompleted = !empty($data['is_completed']) ? 1 : 0;
|
||||
$status = $isCompleted ? 'DONE' : 'TODO';
|
||||
|
||||
$stmt = $db->prepare("
|
||||
UPDATE tasks SET is_completed = ?, status = ?
|
||||
WHERE id = ? AND user_id = ?
|
||||
");
|
||||
$stmt->execute([$isCompleted, $status, $taskId, $user['id']]);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 4. Taak verwijderen
|
||||
if ($action === 'delete_task') {
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$taskId = (int)($data['task_id'] ?? 0);
|
||||
|
||||
$stmt = $db->prepare("DELETE FROM tasks WHERE id = ? AND user_id = ?");
|
||||
$stmt->execute([$taskId, $user['id']]);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode(['error' => 'Onbekende actie']);
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/**
|
||||
* AJAX API voor Roadmap Beheer
|
||||
*/
|
||||
|
||||
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. Roadmap item toevoegen
|
||||
if ($action === 'add_item') {
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$title = trim($data['title'] ?? '');
|
||||
$description = trim($data['description'] ?? '');
|
||||
$quarter = $data['quarter'] ?? 'Q3';
|
||||
$type = $data['type'] ?? 'FEATURE';
|
||||
$priority = $data['priority'] ?? 'MEDIUM';
|
||||
$dueDate = !empty($data['due_date']) ? $data['due_date'] : null;
|
||||
$jiraKey = !empty($data['jira_key']) ? trim($data['jira_key']) : null;
|
||||
|
||||
if (empty($title)) {
|
||||
echo json_encode(['error' => 'Titel is verplicht']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("
|
||||
INSERT INTO roadmap_items (title, description, quarter, type, priority, status, progress, due_date, jira_issue_key, created_by_id)
|
||||
VALUES (?, ?, ?, ?, ?, 'PLANNED', 0, ?, ?, ?)
|
||||
");
|
||||
$stmt->execute([$title, $description, $quarter, $type, $priority, $dueDate, $jiraKey, $user['id']]);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 2. Status of voortgang bijwerken
|
||||
if ($action === 'update_item') {
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$id = (int)($data['id'] ?? 0);
|
||||
$status = $data['status'] ?? null;
|
||||
$progress = isset($data['progress']) ? (int)$data['progress'] : null;
|
||||
$jiraKey = isset($data['jira_key']) ? trim($data['jira_key']) : null;
|
||||
|
||||
$fields = [];
|
||||
$params = [];
|
||||
|
||||
if ($status !== null) {
|
||||
$fields[] = "status = ?";
|
||||
$params[] = $status;
|
||||
}
|
||||
if ($progress !== null) {
|
||||
$fields[] = "progress = ?";
|
||||
$params[] = max(0, min(100, $progress));
|
||||
}
|
||||
if ($jiraKey !== null) {
|
||||
$fields[] = "jira_issue_key = ?";
|
||||
$params[] = $jiraKey;
|
||||
}
|
||||
|
||||
if (!empty($fields)) {
|
||||
$params[] = $id;
|
||||
$sql = "UPDATE roadmap_items SET " . implode(", ", $fields) . " WHERE id = ?";
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
}
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 3. Item verwijderen
|
||||
if ($action === 'delete_item') {
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$id = (int)($data['id'] ?? 0);
|
||||
|
||||
$stmt = $db->prepare("DELETE FROM roadmap_items WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode(['error' => 'Onbekende actie']);
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user