5ce08443cc
- Enhanced JIRA integration to fetch story points from multiple custom fields. - Updated task display to show story points and their estimated duration. - Introduced AI daily briefing banner with dynamic content loading. - Implemented subtasks functionality with add, toggle, and delete capabilities. - Improved task management UI with better accessibility and interaction.
306 lines
11 KiB
PHP
306 lines
11 KiB
PHP
<?php
|
|
/**
|
|
* AJAX API voor AI Co-Pilot (Release v1.5)
|
|
*/
|
|
|
|
require_once __DIR__ . '/../includes/auth.php';
|
|
require_once __DIR__ . '/../includes/ai.php';
|
|
require_once __DIR__ . '/../includes/settings.php';
|
|
|
|
$user = require_auth();
|
|
$db = get_db_connection();
|
|
|
|
header('Content-Type: application/json');
|
|
|
|
$action = $_GET['action'] ?? ($_POST['action'] ?? '');
|
|
|
|
try {
|
|
// 1. Auto-categoriseer kaartjes in een brainstormsessie
|
|
if ($action === 'categorize_cards') {
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
$sessionId = (int)($data['session_id'] ?? 0);
|
|
|
|
if (!$sessionId) {
|
|
echo json_encode(['error' => 'Sessie ID ontbreekt']);
|
|
exit;
|
|
}
|
|
|
|
$stmtSession = $db->prepare("SELECT * FROM brainstorm_sessions WHERE id = ?");
|
|
$stmtSession->execute([$sessionId]);
|
|
$session = $stmtSession->fetch();
|
|
|
|
if (!$session) {
|
|
echo json_encode(['error' => 'Sessie niet gevonden']);
|
|
exit;
|
|
}
|
|
|
|
$stmtCards = $db->prepare("SELECT id, content, category FROM brainstorm_cards WHERE session_id = ?");
|
|
$stmtCards->execute([$sessionId]);
|
|
$cards = $stmtCards->fetchAll();
|
|
|
|
if (empty($cards)) {
|
|
echo json_encode(['error' => 'Er zijn nog geen kaartjes op het canvas om te categoriseren']);
|
|
exit;
|
|
}
|
|
|
|
$aiRes = fociz_ai_categorize_cards($session['title'], $session['theme'] ?? 'Algemeen', $cards);
|
|
|
|
if (!$aiRes['success']) {
|
|
echo json_encode(['error' => $aiRes['error']]);
|
|
exit;
|
|
}
|
|
|
|
$validCategories = ['Ideeën', 'Knelpunten', 'Oplossingen', 'Quick Wins'];
|
|
$updateStmt = $db->prepare("UPDATE brainstorm_cards SET category = ? WHERE id = ? AND session_id = ?");
|
|
$updatedCount = 0;
|
|
|
|
foreach ($aiRes['categorized'] as $item) {
|
|
$cardId = (int)($item['id'] ?? 0);
|
|
$newCat = trim($item['category'] ?? '');
|
|
if ($cardId > 0 && in_array($newCat, $validCategories)) {
|
|
$updateStmt->execute([$newCat, $cardId, $sessionId]);
|
|
$updatedCount++;
|
|
}
|
|
}
|
|
|
|
echo json_encode(['success' => true, 'updated' => $updatedCount]);
|
|
exit;
|
|
}
|
|
|
|
// 2. Automatisch ideeën genereren voor een sessie
|
|
if ($action === 'generate_ideas') {
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
$sessionId = (int)($data['session_id'] ?? 0);
|
|
$count = min(6, max(2, (int)($data['count'] ?? 4)));
|
|
|
|
if (!$sessionId) {
|
|
echo json_encode(['error' => 'Sessie ID ontbreekt']);
|
|
exit;
|
|
}
|
|
|
|
$stmtSession = $db->prepare("SELECT * FROM brainstorm_sessions WHERE id = ?");
|
|
$stmtSession->execute([$sessionId]);
|
|
$session = $stmtSession->fetch();
|
|
|
|
if (!$session) {
|
|
echo json_encode(['error' => 'Sessie niet gevonden']);
|
|
exit;
|
|
}
|
|
|
|
$aiRes = fociz_ai_generate_ideas($session['title'], $session['theme'] ?? 'Algemeen', $count);
|
|
|
|
if (!$aiRes['success']) {
|
|
echo json_encode(['error' => $aiRes['error']]);
|
|
exit;
|
|
}
|
|
|
|
$insertStmt = $db->prepare("
|
|
INSERT INTO brainstorm_cards (session_id, content, category, color, author_name, votes)
|
|
VALUES (?, ?, 'Ideeën', 'amber', ?, 1)
|
|
");
|
|
|
|
$createdCards = [];
|
|
$authorName = 'AI Co-Pilot';
|
|
|
|
foreach ($aiRes['ideas'] as $ideaText) {
|
|
$ideaText = trim($ideaText);
|
|
if (!empty($ideaText)) {
|
|
$insertStmt->execute([$sessionId, $ideaText, $authorName]);
|
|
$createdCards[] = [
|
|
'id' => (int)$db->lastInsertId(),
|
|
'content' => $ideaText,
|
|
'category' => 'Ideeën',
|
|
'color' => 'amber',
|
|
'author_name' => $authorName,
|
|
'votes' => 1,
|
|
];
|
|
}
|
|
}
|
|
|
|
echo json_encode(['success' => true, 'cards' => $createdCards]);
|
|
exit;
|
|
}
|
|
|
|
// 3. Brainstorm notitie omzetten naar Roadmap Item
|
|
if ($action === 'summarize_to_roadmap') {
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
$content = trim($data['content'] ?? '');
|
|
$sessionTitle = trim($data['session_title'] ?? '');
|
|
|
|
if (empty($content)) {
|
|
echo json_encode(['error' => 'Geen inhoud opgegeven om samen te vatten']);
|
|
exit;
|
|
}
|
|
|
|
$aiRes = fociz_ai_summarize_to_roadmap($content, $sessionTitle);
|
|
|
|
if (!$aiRes['success']) {
|
|
echo json_encode(['error' => $aiRes['error']]);
|
|
exit;
|
|
}
|
|
|
|
echo json_encode(['success' => true, 'item' => $aiRes['item']]);
|
|
exit;
|
|
}
|
|
|
|
// 4. Slimme dagindeling berekenen voor taken rondom Outlook afspraken
|
|
if ($action === 'smart_schedule') {
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
$date = !empty($data['date']) ? trim($data['date']) : date('Y-m-d');
|
|
|
|
// Haal daily plan op
|
|
$stmtPlan = $db->prepare("SELECT id FROM daily_plans WHERE user_id = ? AND plan_date = ?");
|
|
$stmtPlan->execute([$user['id'], $date]);
|
|
$plan = $stmtPlan->fetch();
|
|
$planId = $plan['id'] ?? 0;
|
|
|
|
// Haal openstaande taken op voor de dag (inclusief fallback voor ongebonden taken op de huidige dag)
|
|
$isToday = ($date === date('Y-m-d'));
|
|
$stmtTasks = $db->prepare("
|
|
SELECT t.id, t.title, t.priority, t.duration_minutes
|
|
FROM tasks t
|
|
WHERE t.user_id = ? AND (t.daily_plan_id = ? " . ($isToday ? "OR t.daily_plan_id IS NULL" : "") . ") AND t.is_completed = 0
|
|
ORDER BY t.priority ASC, t.created_at ASC
|
|
");
|
|
$stmtTasks->execute([$user['id'], $planId]);
|
|
$tasks = $stmtTasks->fetchAll();
|
|
|
|
if (empty($tasks)) {
|
|
echo json_encode(['error' => 'Geen openstaande taken gevonden om in te delen']);
|
|
exit;
|
|
}
|
|
|
|
require_once __DIR__ . '/../includes/integrations/microsoft.php';
|
|
$events = microsoft_fetch_today_events($user['id'], $date);
|
|
$workdaySettings = get_workday_settings();
|
|
|
|
$aiRes = fociz_ai_smart_schedule($tasks, $events, $workdaySettings);
|
|
|
|
if (!$aiRes['success']) {
|
|
echo json_encode(['error' => $aiRes['error']]);
|
|
exit;
|
|
}
|
|
|
|
// Werk de tijdsblokken bij in MariaDB
|
|
$updateStmt = $db->prepare("
|
|
UPDATE tasks
|
|
SET time_block_start = ?,
|
|
duration_minutes = COALESCE(?, duration_minutes)
|
|
WHERE id = ? AND user_id = ?
|
|
");
|
|
|
|
$scheduledCount = 0;
|
|
foreach ($aiRes['scheduled'] as $s) {
|
|
$taskId = (int)($s['id'] ?? 0);
|
|
$startTime = trim($s['time_block_start'] ?? '');
|
|
$duration = !empty($s['duration_minutes']) ? (int)$s['duration_minutes'] : null;
|
|
|
|
if ($taskId > 0 && preg_match('/^\d{1,2}:\d{2}$/', $startTime)) {
|
|
$updateStmt->execute([$startTime, $duration, $taskId, $user['id']]);
|
|
$scheduledCount++;
|
|
}
|
|
}
|
|
|
|
echo json_encode(['success' => true, 'scheduled_count' => $scheduledCount]);
|
|
exit;
|
|
}
|
|
|
|
// 5. Persoonlijke AI Dagbriefing genereren
|
|
if ($action === 'daily_briefing') {
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
$date = !empty($data['date']) ? trim($data['date']) : date('Y-m-d');
|
|
$today = date('Y-m-d');
|
|
|
|
// Haal openstaande taken van vandaag op
|
|
$stmtPlan = $db->prepare("SELECT id FROM daily_plans WHERE user_id = ? AND plan_date = ?");
|
|
$stmtPlan->execute([$user['id'], $date]);
|
|
$planId = $stmtPlan->fetchColumn();
|
|
|
|
$isToday = ($date === $today);
|
|
$taskFilter = $planId
|
|
? "t.daily_plan_id = " . (int)$planId . ($isToday ? " OR t.daily_plan_id IS NULL" : "")
|
|
: ($isToday ? "t.daily_plan_id IS NULL" : "1=0");
|
|
|
|
$tasks = $db->query("
|
|
SELECT id, title, priority, time_block_start, duration_minutes
|
|
FROM tasks
|
|
WHERE user_id = {$user['id']} AND is_completed = 0 AND ({$taskFilter})
|
|
ORDER BY priority ASC, time_block_start ASC
|
|
LIMIT 15
|
|
")->fetchAll();
|
|
|
|
// Haal gisteren niet-voltooide taken op
|
|
$yesterday = date('Y-m-d', strtotime('-1 day', strtotime($date)));
|
|
$stmtYest = $db->prepare("SELECT id FROM daily_plans WHERE user_id = ? AND plan_date = ?");
|
|
$stmtYest->execute([$user['id'], $yesterday]);
|
|
$yesterdayPlanId = $stmtYest->fetchColumn();
|
|
$unfinishedYest = [];
|
|
if ($yesterdayPlanId) {
|
|
$stmtUnf = $db->prepare("
|
|
SELECT title FROM tasks
|
|
WHERE user_id = ? AND daily_plan_id = ? AND is_completed = 0
|
|
LIMIT 5
|
|
");
|
|
$stmtUnf->execute([$user['id'], $yesterdayPlanId]);
|
|
$unfinishedYest = $stmtUnf->fetchAll();
|
|
}
|
|
|
|
// Haal Outlook meetings op als beschikbaar
|
|
$meetings = [];
|
|
try {
|
|
require_once __DIR__ . '/../includes/integrations/microsoft.php';
|
|
$meetings = microsoft_fetch_today_events($user['id'], $date);
|
|
} catch (Throwable $e) {
|
|
// meetings niet beschikbaar, geen probleem
|
|
}
|
|
|
|
// Haal urgente Jira tickets op als beschikbaar
|
|
$jiraIssues = [];
|
|
try {
|
|
require_once __DIR__ . '/../includes/integrations/jira.php';
|
|
$jiraData = jira_get_dashboard_data($user['id'], false);
|
|
$jiraIssues = array_merge(
|
|
$jiraData['assigned_issues'] ?? [],
|
|
$jiraData['team_issues'] ?? []
|
|
);
|
|
} catch (Throwable $e) {
|
|
// Jira niet beschikbaar, geen probleem
|
|
}
|
|
|
|
$aiSettings = get_ai_settings();
|
|
if (empty($aiSettings['ai_enabled']) || empty($aiSettings['has_key'])) {
|
|
echo json_encode(['error' => 'AI Co-Pilot is niet geconfigureerd']);
|
|
exit;
|
|
}
|
|
|
|
$aiRes = fociz_ai_daily_briefing(
|
|
$user['name'] ?? 'Jij',
|
|
$date,
|
|
$tasks,
|
|
$meetings,
|
|
$jiraIssues,
|
|
$unfinishedYest
|
|
);
|
|
|
|
if (!$aiRes['success']) {
|
|
echo json_encode(['error' => $aiRes['error']]);
|
|
exit;
|
|
}
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'greeting' => $aiRes['greeting'],
|
|
'focus_task' => $aiRes['focus_task'],
|
|
'tip' => $aiRes['tip'],
|
|
'warnings' => $aiRes['warnings'],
|
|
'date' => $date,
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
echo json_encode(['error' => 'Onbekende actie']);
|
|
} catch (Exception $e) {
|
|
http_response_code(500);
|
|
echo json_encode(['error' => $e->getMessage()]);
|
|
}
|