diff --git a/api/integrations.php b/api/integrations.php index 57aa15e..dd96b69 100644 --- a/api/integrations.php +++ b/api/integrations.php @@ -72,6 +72,171 @@ try { exit; } + // 2b. Jira Dashboard Data Ophalen (Toegewezen + Team issues + Stats) + if ($action === 'get_jira_dashboard') { + $force = !empty($_GET['force']) || !empty($_POST['force']); + $res = jira_get_dashboard_data($user['id'], $force); + echo json_encode($res); + exit; + } + + // 2c. Jira Issue inplannen in Dagplanner + if ($action === 'plan_jira_task') { + $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; + $key = trim($input['key'] ?? ''); + $summary = trim($input['summary'] ?? ''); + $url = trim($input['url'] ?? ''); + $planDate = !empty($input['plan_date']) ? trim($input['plan_date']) : date('Y-m-d'); + $priority = in_array($input['priority'] ?? '', ['P1', 'P2', 'P3']) ? $input['priority'] : 'P2'; + $timeBlockStart = !empty($input['time_block_start']) ? trim($input['time_block_start']) : null; + $timeBlockEnd = !empty($input['time_block_end']) ? trim($input['time_block_end']) : null; + $durationMinutes = !empty($input['duration_minutes']) ? (int)$input['duration_minutes'] : 45; + + if (empty($key) || empty($summary)) { + echo json_encode(['error' => 'Ticket key en titel zijn verplicht']); + exit; + } + + $title = "[{$key}] {$summary}"; + + // Zoek of maak daily plan aan voor deze datum + $stmtPlan = $db->prepare("SELECT id FROM daily_plans WHERE user_id = ? AND plan_date = ?"); + $stmtPlan->execute([$user['id'], $planDate]); + $planId = $stmtPlan->fetchColumn(); + + if (!$planId) { + $stmtCreatePlan = $db->prepare("INSERT INTO daily_plans (user_id, plan_date) VALUES (?, ?)"); + $stmtCreatePlan->execute([$user['id'], $planDate]); + $planId = (int)$db->lastInsertId(); + } + + // Voeg taak toe + $stmt = $db->prepare(" + INSERT INTO tasks (user_id, daily_plan_id, title, priority, time_block_start, time_block_end, duration_minutes, status, source, external_id, external_url) + VALUES (?, ?, ?, ?, ?, ?, ?, 'TODO', 'JIRA', ?, ?) + "); + $stmt->execute([ + $user['id'], + $planId, + $title, + $priority, + $timeBlockStart, + $timeBlockEnd, + $durationMinutes, + $key, + $url + ]); + $taskId = (int)$db->lastInsertId(); + + echo json_encode([ + 'success' => true, + 'task_id' => $taskId, + 'message' => "Ticket {$key} is succesvol ingepland voor " . date('d-m-Y', strtotime($planDate)) . "!", + ]); + exit; + } + + // 2d. Jira Issue toevoegen aan een Kanban Bord kolom + if ($action === 'board_jira_card') { + $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; + $boardId = (int)($input['board_id'] ?? 0); + $laneId = (int)($input['lane_id'] ?? 0); + $key = trim($input['key'] ?? ''); + $summary = trim($input['summary'] ?? ''); + $description = trim($input['description'] ?? ''); + $url = trim($input['url'] ?? ''); + $priority = in_array($input['priority'] ?? '', ['P1', 'P2', 'P3']) ? $input['priority'] : 'P2'; + $color = in_array($input['color'] ?? '', ['yellow', 'blue', 'green', 'purple', 'red', 'pink', 'indigo', 'orange']) ? $input['color'] : 'blue'; + + if (empty($boardId) || empty($laneId) || empty($key) || empty($summary)) { + echo json_encode(['error' => 'Bord, kolom, ticket key en titel zijn verplicht']); + exit; + } + + // Controleer toegang tot bord + $isAdmin = ($user['role'] ?? '') === 'ADMIN'; + if (!$isAdmin) { + $stmtCheck = $db->prepare("SELECT role FROM board_members WHERE board_id = ? AND user_id = ?"); + $stmtCheck->execute([$boardId, $user['id']]); + if (!$stmtCheck->fetchColumn()) { + echo json_encode(['error' => 'Geen toegang tot dit bord']); + exit; + } + } + + // Controleer of lane bij bord hoort + $stmtLane = $db->prepare("SELECT id FROM board_lanes WHERE id = ? AND board_id = ?"); + $stmtLane->execute([$laneId, $boardId]); + if (!$stmtLane->fetchColumn()) { + echo json_encode(['error' => 'Kolom hoort niet bij dit bord']); + exit; + } + + $title = "[{$key}] {$summary}"; + $descFull = trim(($url ? "🔗 Jira: {$url}\n\n" : "") . $description); + + $maxPos = (int)$db->query("SELECT COALESCE(MAX(position), -1) FROM board_cards WHERE lane_id = {$laneId}")->fetchColumn(); + + $stmt = $db->prepare(" + INSERT INTO board_cards (board_id, lane_id, title, description, assignee_id, priority, color, position, created_by_id) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + "); + $stmt->execute([ + $boardId, + $laneId, + $title, + $descFull, + $user['id'], + $priority, + $color, + $maxPos + 1, + $user['id'] + ]); + $cardId = (int)$db->lastInsertId(); + + echo json_encode([ + 'success' => true, + 'card_id' => $cardId, + 'message' => "Ticket {$key} is succesvol als kaart op het bord geplaatst!", + ]); + exit; + } + + // 2e. Beschikbare borden en kolommen ophalen voor selectiedialoog + if ($action === 'get_boards_and_lanes') { + $isAdmin = ($user['role'] ?? '') === 'ADMIN'; + if ($isAdmin) { + $boards = $db->query("SELECT id, title FROM boards WHERE is_archived = 0 ORDER BY id ASC")->fetchAll(); + } else { + $stmt = $db->prepare(" + SELECT b.id, b.title + FROM boards b + JOIN board_members bm ON b.id = bm.board_id + WHERE bm.user_id = ? AND b.is_archived = 0 + ORDER BY b.id ASC + "); + $stmt->execute([$user['id']]); + $boards = $stmt->fetchAll(); + } + + $boardIds = array_column($boards, 'id'); + $lanesByBoard = []; + if (!empty($boardIds)) { + $inClause = implode(',', array_map('intval', $boardIds)); + $lanes = $db->query("SELECT id, board_id, title, color FROM board_lanes WHERE board_id IN ({$inClause}) ORDER BY position ASC")->fetchAll(); + foreach ($lanes as $lane) { + $lanesByBoard[$lane['board_id']][] = $lane; + } + } + + foreach ($boards as &$b) { + $b['lanes'] = $lanesByBoard[$b['id']] ?? []; + } + + echo json_encode(['success' => true, 'boards' => $boards]); + exit; + } + // 3. Outlook Agenda Afspraken Ophalen if ($action === 'get_outlook_events') { $date = $_GET['date'] ?? date('Y-m-d'); diff --git a/assets/avatars/avatar-01.svg b/assets/avatars/avatar-01.svg new file mode 100644 index 0000000..224692b --- /dev/null +++ b/assets/avatars/avatar-01.svg @@ -0,0 +1,18 @@ + diff --git a/assets/avatars/avatar-02.svg b/assets/avatars/avatar-02.svg new file mode 100644 index 0000000..d4b9bf2 --- /dev/null +++ b/assets/avatars/avatar-02.svg @@ -0,0 +1,22 @@ + diff --git a/assets/avatars/avatar-03.svg b/assets/avatars/avatar-03.svg new file mode 100644 index 0000000..684089b --- /dev/null +++ b/assets/avatars/avatar-03.svg @@ -0,0 +1,22 @@ + diff --git a/assets/avatars/avatar-04.svg b/assets/avatars/avatar-04.svg new file mode 100644 index 0000000..8fc7bf5 --- /dev/null +++ b/assets/avatars/avatar-04.svg @@ -0,0 +1,20 @@ + diff --git a/assets/avatars/avatar-05.svg b/assets/avatars/avatar-05.svg new file mode 100644 index 0000000..5acb03f --- /dev/null +++ b/assets/avatars/avatar-05.svg @@ -0,0 +1,18 @@ + diff --git a/assets/avatars/avatar-06.svg b/assets/avatars/avatar-06.svg new file mode 100644 index 0000000..66025a4 --- /dev/null +++ b/assets/avatars/avatar-06.svg @@ -0,0 +1,25 @@ + diff --git a/assets/avatars/avatar-07.svg b/assets/avatars/avatar-07.svg new file mode 100644 index 0000000..8ca3bcc --- /dev/null +++ b/assets/avatars/avatar-07.svg @@ -0,0 +1,24 @@ + diff --git a/assets/avatars/avatar-08.svg b/assets/avatars/avatar-08.svg new file mode 100644 index 0000000..8cd0bb9 --- /dev/null +++ b/assets/avatars/avatar-08.svg @@ -0,0 +1,20 @@ + diff --git a/assets/avatars/avatar-09.svg b/assets/avatars/avatar-09.svg new file mode 100644 index 0000000..8a4a163 --- /dev/null +++ b/assets/avatars/avatar-09.svg @@ -0,0 +1,21 @@ + diff --git a/assets/avatars/avatar-10.svg b/assets/avatars/avatar-10.svg new file mode 100644 index 0000000..81bb3b2 --- /dev/null +++ b/assets/avatars/avatar-10.svg @@ -0,0 +1,22 @@ + diff --git a/assets/avatars/avatar-11.svg b/assets/avatars/avatar-11.svg new file mode 100644 index 0000000..fe7cb1d --- /dev/null +++ b/assets/avatars/avatar-11.svg @@ -0,0 +1,19 @@ + diff --git a/assets/avatars/avatar-12.svg b/assets/avatars/avatar-12.svg new file mode 100644 index 0000000..5deec67 --- /dev/null +++ b/assets/avatars/avatar-12.svg @@ -0,0 +1,23 @@ + diff --git a/assets/avatars/avatar-13.svg b/assets/avatars/avatar-13.svg new file mode 100644 index 0000000..87ed632 --- /dev/null +++ b/assets/avatars/avatar-13.svg @@ -0,0 +1,18 @@ + diff --git a/assets/avatars/avatar-14.svg b/assets/avatars/avatar-14.svg new file mode 100644 index 0000000..e99eab5 --- /dev/null +++ b/assets/avatars/avatar-14.svg @@ -0,0 +1,27 @@ + diff --git a/assets/avatars/avatar-15.svg b/assets/avatars/avatar-15.svg new file mode 100644 index 0000000..2366585 --- /dev/null +++ b/assets/avatars/avatar-15.svg @@ -0,0 +1,22 @@ + diff --git a/assets/avatars/avatar-16.svg b/assets/avatars/avatar-16.svg new file mode 100644 index 0000000..60c5cc8 --- /dev/null +++ b/assets/avatars/avatar-16.svg @@ -0,0 +1,20 @@ + diff --git a/assets/avatars/avatar-17.svg b/assets/avatars/avatar-17.svg new file mode 100644 index 0000000..096d5a2 --- /dev/null +++ b/assets/avatars/avatar-17.svg @@ -0,0 +1,18 @@ + diff --git a/assets/avatars/avatar-18.svg b/assets/avatars/avatar-18.svg new file mode 100644 index 0000000..dc64b6d --- /dev/null +++ b/assets/avatars/avatar-18.svg @@ -0,0 +1,25 @@ + diff --git a/assets/avatars/avatar-19.svg b/assets/avatars/avatar-19.svg new file mode 100644 index 0000000..a4011a1 --- /dev/null +++ b/assets/avatars/avatar-19.svg @@ -0,0 +1,19 @@ + diff --git a/assets/avatars/avatar-20.svg b/assets/avatars/avatar-20.svg new file mode 100644 index 0000000..eb8b3df --- /dev/null +++ b/assets/avatars/avatar-20.svg @@ -0,0 +1,20 @@ + diff --git a/assets/avatars/avatar-21.svg b/assets/avatars/avatar-21.svg new file mode 100644 index 0000000..73d2cbd --- /dev/null +++ b/assets/avatars/avatar-21.svg @@ -0,0 +1,26 @@ + diff --git a/assets/avatars/avatar-22.svg b/assets/avatars/avatar-22.svg new file mode 100644 index 0000000..4760bb4 --- /dev/null +++ b/assets/avatars/avatar-22.svg @@ -0,0 +1,22 @@ + diff --git a/assets/avatars/avatar-23.svg b/assets/avatars/avatar-23.svg new file mode 100644 index 0000000..7fe9aac --- /dev/null +++ b/assets/avatars/avatar-23.svg @@ -0,0 +1,19 @@ + diff --git a/assets/avatars/avatar-24.svg b/assets/avatars/avatar-24.svg new file mode 100644 index 0000000..25bd777 --- /dev/null +++ b/assets/avatars/avatar-24.svg @@ -0,0 +1,23 @@ + diff --git a/assets/favicon.ico b/assets/favicon.ico new file mode 100644 index 0000000..3b05a9e --- /dev/null +++ b/assets/favicon.ico @@ -0,0 +1,20 @@ + diff --git a/assets/favicon.svg b/assets/favicon.svg new file mode 100644 index 0000000..8314b41 --- /dev/null +++ b/assets/favicon.svg @@ -0,0 +1,21 @@ + + diff --git a/auth/forgot-password.php b/auth/forgot-password.php index 335dbd9..23de8b3 100644 --- a/auth/forgot-password.php +++ b/auth/forgot-password.php @@ -75,6 +75,8 @@ $pageTitle = "Fociz — Wachtwoord Vergeten";
Kies een mini-avatar uit de 24 stijlvolle karakters of upload een eigen afbeelding.
+