feat: Add story points support and AI daily briefing feature
- 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.
This commit is contained in:
+93
@@ -205,6 +205,99 @@ try {
|
||||
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);
|
||||
|
||||
+114
@@ -486,6 +486,120 @@ try {
|
||||
exit;
|
||||
}
|
||||
|
||||
// --- V2.0: Subtaken & Checklists ---
|
||||
|
||||
// 7. Subtaak toevoegen aan een taak
|
||||
if ($action === 'add_subtask') {
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$taskId = (int)($data['task_id'] ?? 0);
|
||||
$title = trim($data['title'] ?? '');
|
||||
|
||||
if (!$taskId || empty($title)) {
|
||||
echo json_encode(['error' => 'Taak-ID en titel zijn verplicht']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Controleer of de taak van deze gebruiker is
|
||||
$stmtCheck = $db->prepare("SELECT id FROM tasks WHERE id = ? AND user_id = ?");
|
||||
$stmtCheck->execute([$taskId, $user['id']]);
|
||||
if (!$stmtCheck->fetchColumn()) {
|
||||
echo json_encode(['error' => 'Taak niet gevonden']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Bereken positie (achteraan)
|
||||
$stmtPos = $db->prepare("SELECT COALESCE(MAX(position), -1) + 1 FROM task_subtasks WHERE task_id = ?");
|
||||
$stmtPos->execute([$taskId]);
|
||||
$position = (int)$stmtPos->fetchColumn();
|
||||
|
||||
$stmt = $db->prepare("
|
||||
INSERT INTO task_subtasks (task_id, user_id, title, is_completed, position)
|
||||
VALUES (?, ?, ?, 0, ?)
|
||||
");
|
||||
$stmt->execute([$taskId, $user['id'], substr($title, 0, 255), $position]);
|
||||
$subtaskId = (int)$db->lastInsertId();
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'subtask' => [
|
||||
'id' => $subtaskId,
|
||||
'task_id' => $taskId,
|
||||
'title' => $title,
|
||||
'is_completed' => 0,
|
||||
'position' => $position,
|
||||
]
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 8. Subtaak afvinken / openzetten
|
||||
if ($action === 'toggle_subtask') {
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$subtaskId = (int)($data['subtask_id'] ?? 0);
|
||||
$isCompleted = !empty($data['is_completed']) ? 1 : 0;
|
||||
|
||||
if (!$subtaskId) {
|
||||
echo json_encode(['error' => 'Subtaak-ID ontbreekt']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("
|
||||
UPDATE task_subtasks SET is_completed = ?
|
||||
WHERE id = ? AND user_id = ?
|
||||
");
|
||||
$stmt->execute([$isCompleted, $subtaskId, $user['id']]);
|
||||
|
||||
echo json_encode(['success' => true, 'is_completed' => $isCompleted]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 9. Subtaak verwijderen
|
||||
if ($action === 'delete_subtask') {
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$subtaskId = (int)($data['subtask_id'] ?? 0);
|
||||
|
||||
if (!$subtaskId) {
|
||||
echo json_encode(['error' => 'Subtaak-ID ontbreekt']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("DELETE FROM task_subtasks WHERE id = ? AND user_id = ?");
|
||||
$stmt->execute([$subtaskId, $user['id']]);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 10. Subtaken ophalen voor een taak
|
||||
if ($action === 'get_subtasks') {
|
||||
$taskId = (int)($_GET['task_id'] ?? 0);
|
||||
|
||||
if (!$taskId) {
|
||||
echo json_encode(['error' => 'Taak-ID ontbreekt']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Controleer eigenaarschap
|
||||
$stmtCheck = $db->prepare("SELECT id FROM tasks WHERE id = ? AND user_id = ?");
|
||||
$stmtCheck->execute([$taskId, $user['id']]);
|
||||
if (!$stmtCheck->fetchColumn()) {
|
||||
echo json_encode(['error' => 'Taak niet gevonden']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("
|
||||
SELECT id, task_id, title, is_completed, position
|
||||
FROM task_subtasks
|
||||
WHERE task_id = ? AND user_id = ?
|
||||
ORDER BY position ASC, created_at ASC
|
||||
");
|
||||
$stmt->execute([$taskId, $user['id']]);
|
||||
$subtasks = $stmt->fetchAll();
|
||||
|
||||
echo json_encode(['success' => true, 'subtasks' => $subtasks]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode(['error' => 'Onbekende actie']);
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
|
||||
Reference in New Issue
Block a user