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:
@@ -195,3 +195,86 @@ function fociz_ai_smart_schedule(array $tasks, array $events, array $workdaySett
|
||||
return ['success' => true, 'scheduled' => $aiRes['json']['scheduled']];
|
||||
}
|
||||
|
||||
/**
|
||||
* Genereert een persoonlijke AI dagbriefing op basis van taken, afspraken en Jira tickets
|
||||
*
|
||||
* @param string $userName Naam van de gebruiker
|
||||
* @param string $date Datum (Y-m-d)
|
||||
* @param array $tasks Openstaande taken van vandaag
|
||||
* @param array $meetings Outlook meetings van vandaag
|
||||
* @param array $jiraIssues Jira tickets (P1/blokkades)
|
||||
* @param array $unfinishedYest Gisteren niet voltooide taken
|
||||
* @return array ['success' => bool, 'briefing' => string, 'focus_tip' => string, 'warnings' => array]
|
||||
*/
|
||||
function fociz_ai_daily_briefing(
|
||||
string $userName,
|
||||
string $date,
|
||||
array $tasks,
|
||||
array $meetings,
|
||||
array $jiraIssues = [],
|
||||
array $unfinishedYest = []
|
||||
): array {
|
||||
$dutchDays = ['', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag', 'zondag'];
|
||||
$dayName = $dutchDays[(int)date('N', strtotime($date))] ?? 'vandaag';
|
||||
$dateLabel = $dayName . ' ' . date('j', strtotime($date)) . ' ' . date('F', strtotime($date));
|
||||
|
||||
$taskSummary = array_map(fn($t) => [
|
||||
'title' => $t['title'],
|
||||
'priority' => $t['priority'] ?? 'P2',
|
||||
'time' => $t['time_block_start'] ?? null,
|
||||
'duration' => (int)($t['duration_minutes'] ?? 30),
|
||||
], array_slice($tasks, 0, 10));
|
||||
|
||||
$meetingSummary = array_map(fn($e) => [
|
||||
'subject' => $e['subject'] ?? 'Afspraak',
|
||||
'start' => $e['start'] ?? null,
|
||||
'end' => $e['end'] ?? null,
|
||||
], array_slice($meetings, 0, 8));
|
||||
|
||||
$jiraSummary = array_map(fn($j) => [
|
||||
'key' => $j['key'] ?? '',
|
||||
'title' => $j['summary'] ?? '',
|
||||
'priority' => $j['priority'] ?? 'Medium',
|
||||
'status' => $j['status'] ?? 'Open',
|
||||
], array_slice(array_filter($jiraIssues, fn($j) => in_array($j['priority'] ?? '', ['Highest', 'High'])), 0, 5));
|
||||
|
||||
$yesterdaySummary = array_map(fn($t) => $t['title'], array_slice($unfinishedYest, 0, 5));
|
||||
|
||||
$systemPrompt = "Je bent de persoonlijke AI Co-Pilot van {$userName} in Fociz. "
|
||||
. "Schrijf een korte, energieke en persoonlijke dagbriefing in het Nederlands voor {$dateLabel}. "
|
||||
. "Wees direct, concreet en vriendelijk. Gebruik geen markdown headers, geen bullet symbolen zoals *, -, •. "
|
||||
. "Geef 1-2 zinnen dagopening + 1 zin over de grootste prioriteit + 1 praktisch focustip. "
|
||||
. "Maximaal 60 woorden totaal. "
|
||||
. "Retourneer een JSON-object met:\n"
|
||||
. "- 'greeting': openingszin (max 20 woorden)\n"
|
||||
. "- 'focus_task': de meest urgente taak of meeting vandaag (max 15 woorden)\n"
|
||||
. "- 'tip': één concrete focustip voor vandaag (max 20 woorden)\n"
|
||||
. "- 'warnings': array van strings, max 2 items — alleen als er iets opvalt (gisteren niet afgerond, urgent Jira, overvolle dag)";
|
||||
|
||||
$userPrompt = json_encode([
|
||||
'date' => $dateLabel,
|
||||
'tasks_today' => $taskSummary,
|
||||
'meetings_today' => $meetingSummary,
|
||||
'urgent_jira' => $jiraSummary,
|
||||
'unfinished_yesterday' => $yesterdaySummary,
|
||||
'total_tasks' => count($tasks),
|
||||
'total_meetings' => count($meetings),
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
|
||||
$aiRes = fociz_ai_chat([
|
||||
['role' => 'system', 'content' => $systemPrompt],
|
||||
['role' => 'user', 'content' => $userPrompt],
|
||||
], ['json_mode' => true, 'temperature' => 0.6, 'max_tokens' => 300]);
|
||||
|
||||
if (!$aiRes['success'] || empty($aiRes['json'])) {
|
||||
return ['success' => false, 'error' => $aiRes['error'] ?? 'Kon geen dagbriefing genereren'];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'greeting' => $aiRes['json']['greeting'] ?? "Goedemorgen {$userName}, een nieuwe dag!",
|
||||
'focus_task'=> $aiRes['json']['focus_task'] ?? '',
|
||||
'tip' => $aiRes['json']['tip'] ?? '',
|
||||
'warnings' => $aiRes['json']['warnings'] ?? [],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -236,6 +236,9 @@ function jira_fetch_issues(string $domain, string $email, string $apiToken, stri
|
||||
'description',
|
||||
'labels',
|
||||
'components',
|
||||
'story_points',
|
||||
'customfield_10016', // Story Points (Jira Cloud standaard)
|
||||
'customfield_10028', // Story Points (alternatief veld sommige instanties)
|
||||
];
|
||||
|
||||
// 1. Moderne Atlassian Jira Cloud endpoint (/rest/api/3/search/jql) conform CHANGE-2046 via POST
|
||||
@@ -389,6 +392,16 @@ function jira_fetch_issues(string $domain, string $email, string $apiToken, stri
|
||||
elseif (str_contains($sumLower, 'koppeling')) $onderwerpLogging = 'Koppelingen';
|
||||
}
|
||||
|
||||
// Detectie van story points (customfield_10016 is Jira Cloud standaard, met fallback naar alternatieven)
|
||||
$storyPoints = null;
|
||||
if (isset($fields['customfield_10016']) && is_numeric($fields['customfield_10016'])) {
|
||||
$storyPoints = (float)$fields['customfield_10016'];
|
||||
} elseif (isset($fields['customfield_10028']) && is_numeric($fields['customfield_10028'])) {
|
||||
$storyPoints = (float)$fields['customfield_10028'];
|
||||
} elseif (isset($fields['story_points']) && is_numeric($fields['story_points'])) {
|
||||
$storyPoints = (float)$fields['story_points'];
|
||||
}
|
||||
|
||||
$issues[] = [
|
||||
'key' => $key,
|
||||
'summary' => $summary,
|
||||
@@ -409,6 +422,7 @@ function jira_fetch_issues(string $domain, string $email, string $apiToken, stri
|
||||
'created' => $created,
|
||||
'updated' => $updated,
|
||||
'url' => "{$cleanDomain}/browse/{$key}",
|
||||
'story_points' => $storyPoints,
|
||||
'source' => 'JIRA_LIVE',
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user