diff --git a/api/planner.php b/api/planner.php index 24a2108..74489c3 100644 --- a/api/planner.php +++ b/api/planner.php @@ -4,6 +4,7 @@ */ require_once __DIR__ . '/../includes/auth.php'; +require_once __DIR__ . '/../includes/integrations/microsoft.php'; $user = require_auth(); $db = get_db_connection(); @@ -36,8 +37,11 @@ try { $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; + $timeBlockStart = !empty($data['time_block_start']) ? trim($data['time_block_start']) : null; + $durationMinutes = (int)($data['duration_minutes'] ?? 30); + if ($durationMinutes <= 0) $durationMinutes = 30; + $date = !empty($data['date']) ? trim($data['date']) : $today; + $syncOutlook = !empty($data['sync_to_outlook']); if (empty($title)) { echo json_encode(['error' => 'Titel is verplicht']); @@ -54,14 +58,44 @@ try { $planId = $db->lastInsertId(); $source = !empty($data['source']) ? substr(trim($data['source']), 0, 50) : 'FOCIZ'; - $externalId = !empty($data['external_id']) ? substr(trim($data['external_id']), 0, 100) : null; + $externalId = !empty($data['external_id']) ? substr(trim($data['external_id']), 0, 255) : null; $externalUrl = !empty($data['external_url']) ? trim($data['external_url']) : null; + $timeBlockEnd = null; + + // Als er een tijdblok is en de gebruiker heeft synchronisatie naar Outlook gekozen (of source is OUTLOOK) + if (($syncOutlook || $source === 'OUTLOOK') && !empty($timeBlockStart) && empty($externalId)) { + $msResult = microsoft_create_event($user['id'], [ + 'subject' => $title, + 'description' => "Gepland via Fociz Dagplanning ({$priority})", + 'date' => $date, + 'start_time' => $timeBlockStart, + 'duration_minutes' => $durationMinutes, + ]); + + if (!empty($msResult['success']) && !empty($msResult['event_id'])) { + $source = 'OUTLOOK'; + $externalId = $msResult['event_id']; + $externalUrl = $msResult['web_link'] ?? 'https://outlook.office.com'; + $timeBlockEnd = $msResult['end_time'] ?? null; + } + } + + // Bereken timeBlockEnd indien nog niet gezet maar wel starttijd bekend + if (!empty($timeBlockStart) && empty($timeBlockEnd)) { + try { + $dtEnd = new DateTime("{$date} {$timeBlockStart}:00", new DateTimeZone('Europe/Amsterdam')); + $dtEnd->modify("+{$durationMinutes} minutes"); + $timeBlockEnd = $dtEnd->format('H:i'); + } catch (Throwable $e) { + // negeer + } + } $stmt = $db->prepare(" - INSERT INTO tasks (user_id, daily_plan_id, title, priority, time_block_start, status, source, external_id, external_url) - VALUES (?, ?, ?, ?, ?, 'TODO', ?, ?, ?) + 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', ?, ?, ?) "); - $stmt->execute([$user['id'], $planId, $title, $priority, $timeBlockStart, $source, $externalId, $externalUrl]); + $stmt->execute([$user['id'], $planId, $title, $priority, $timeBlockStart, $timeBlockEnd, $durationMinutes, $source, $externalId, $externalUrl]); $taskId = (int)$db->lastInsertId(); echo json_encode([ @@ -71,14 +105,102 @@ try { 'title' => $title, 'priority' => $priority, 'time_block_start' => $timeBlockStart, + 'time_block_end' => $timeBlockEnd, + 'duration_minutes' => $durationMinutes, 'is_completed' => 0, - 'status' => 'TODO' - ] + 'status' => 'TODO', + 'source' => $source, + 'external_id' => $externalId, + 'external_url' => $externalUrl, + ], + 'outlook_synced' => ($source === 'OUTLOOK' && !empty($externalId)), ]); exit; } - // 3. Taak status toggelen (voltooid / open) + // 3. Bestaande taak handmatig naar Microsoft Outlook synchroniseren + if ($action === 'sync_task_to_outlook') { + $data = json_decode(file_get_contents('php://input'), true); + $taskId = (int)($data['task_id'] ?? 0); + + if (!$taskId) { + echo json_encode(['error' => 'Geen taak-ID opgegeven']); + exit; + } + + // Haal taak inclusief plan datum op + $stmtTask = $db->prepare(" + SELECT t.*, dp.plan_date + FROM tasks t + LEFT JOIN daily_plans dp ON t.daily_plan_id = dp.id + WHERE t.id = ? AND t.user_id = ? + "); + $stmtTask->execute([$taskId, $user['id']]); + $task = $stmtTask->fetch(); + + if (!$task) { + echo json_encode(['error' => 'Taak niet gevonden']); + exit; + } + + // Als al gesynchroniseerd + if (!empty($task['external_id']) && $task['source'] === 'OUTLOOK') { + echo json_encode([ + 'success' => true, + 'already_synced' => true, + 'external_id' => $task['external_id'], + 'external_url' => $task['external_url'] + ]); + exit; + } + + $planDate = $task['plan_date'] ?: $today; + $startTime = !empty($task['time_block_start']) ? $task['time_block_start'] : ($data['time_block_start'] ?? '09:00'); + $duration = (int)($task['duration_minutes'] ?: 30); + + $msResult = microsoft_create_event($user['id'], [ + 'subject' => $task['title'], + 'description' => "Gepland via Fociz Dagplanning (" . $task['priority'] . ")", + 'date' => $planDate, + 'start_time' => $startTime, + 'duration_minutes' => $duration, + ]); + + if (empty($msResult['success']) || empty($msResult['event_id'])) { + echo json_encode(['error' => $msResult['error'] ?? 'Kon afspraak niet aanmaken in Microsoft Outlook']); + exit; + } + + // Sla Outlook ID en bron op in de taak + $stmtUp = $db->prepare(" + UPDATE tasks + SET source = 'OUTLOOK', + external_id = ?, + external_url = ?, + time_block_start = COALESCE(time_block_start, ?), + time_block_end = ? + WHERE id = ? AND user_id = ? + "); + $stmtUp->execute([ + $msResult['event_id'], + $msResult['web_link'] ?? 'https://outlook.office.com', + $msResult['start_time'], + $msResult['end_time'], + $taskId, + $user['id'] + ]); + + echo json_encode([ + 'success' => true, + 'external_id' => $msResult['event_id'], + 'external_url' => $msResult['web_link'] ?? 'https://outlook.office.com', + 'start_time' => $msResult['start_time'], + 'end_time' => $msResult['end_time'], + ]); + exit; + } + + // 4. Taak status toggelen (voltooid / open) if ($action === 'toggle_task') { $data = json_decode(file_get_contents('php://input'), true); $taskId = (int)($data['task_id'] ?? 0); @@ -95,11 +217,24 @@ try { exit; } - // 4. Taak verwijderen + // 5. Taak verwijderen (verwijder ook eventueel gekoppelde Outlook afspraak) if ($action === 'delete_task') { $data = json_decode(file_get_contents('php://input'), true); $taskId = (int)($data['task_id'] ?? 0); + // Haal eerst op of deze taak aan Outlook was gekoppeld + $stmtCheck = $db->prepare("SELECT external_id, source FROM tasks WHERE id = ? AND user_id = ?"); + $stmtCheck->execute([$taskId, $user['id']]); + $taskToDelete = $stmtCheck->fetch(); + + if ($taskToDelete && !empty($taskToDelete['external_id']) && $taskToDelete['source'] === 'OUTLOOK') { + try { + microsoft_delete_event($user['id'], $taskToDelete['external_id']); + } catch (Throwable $t) { + error_log("Fout bij verwijderen Outlook afspraak voor taak {$taskId}: " . $t->getMessage()); + } + } + $stmt = $db->prepare("DELETE FROM tasks WHERE id = ? AND user_id = ?"); $stmt->execute([$taskId, $user['id']]); diff --git a/config/database.php b/config/database.php index e4caf0a..4469844 100644 --- a/config/database.php +++ b/config/database.php @@ -118,7 +118,12 @@ function ensure_tables_exist(PDO $pdo): void { // Controleer of de hoofdtabel 'users' al bestaat $result = $pdo->query("SHOW TABLES LIKE 'users'"); if ($result && $result->rowCount() > 0) { - // Tabellen bestaan al! Geen actie nodig. + // Tabellen bestaan al. Voer eventuele niet-destructieve kolom-upgrades uit indien nodig + try { + $pdo->exec("ALTER TABLE tasks MODIFY external_id VARCHAR(255) NULL"); + } catch (Throwable $t) { + // Kolom bestaat wellicht al of heeft al de juiste lengte + } return; } diff --git a/config/schema.sql b/config/schema.sql index 6bbb337..eb6bf11 100644 --- a/config/schema.sql +++ b/config/schema.sql @@ -57,7 +57,7 @@ CREATE TABLE IF NOT EXISTS `tasks` ( `duration_minutes` INT NULL DEFAULT 30, `is_completed` TINYINT(1) NOT NULL DEFAULT 0, `source` VARCHAR(50) NOT NULL DEFAULT 'FOCIZ', - `external_id` VARCHAR(100) NULL, + `external_id` VARCHAR(255) NULL, `external_url` TEXT NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, diff --git a/includes/header.php b/includes/header.php index b230bb9..5505b19 100644 --- a/includes/header.php +++ b/includes/header.php @@ -132,39 +132,28 @@ require_once __DIR__ . '/env_badge.php'; - -