@@ -376,8 +396,18 @@
`;
}
@@ -426,7 +456,6 @@
}
}
- // Kalender Klick Logik
function openDayView(dateStr) {
let dayTasks = cachedTasks.filter(t => t.deadline === dateStr);
document.getElementById('dayViewTitle').innerText = `Aufgaben: ${dateStr}`;
@@ -445,6 +474,36 @@
document.getElementById('dayViewContent').innerHTML = html;
document.getElementById('dayViewModal').classList.remove('hidden');
}
+
+ // --- COMMENTS (Notizen) ---
+ function openComments(taskId, title) {
+ document.getElementById('commentTaskId').value = taskId;
+ document.getElementById('commentsTaskTitle').innerText = 'Notizen: ' + title;
+ document.getElementById('commentsModal').classList.remove('hidden');
+ loadComments(taskId);
+ }
+ function loadComments(taskId) {
+ fetch('/api/tasks/comments?task_id=' + taskId).then(res=>res.json()).then(data=>{
+ let html = '';
+ if(data.success) {
+ if(data.data.length === 0) html = '
Noch keine Notizen vorhanden.
';
+ data.data.forEach(c => {
+ html += `
🙋 ${c.username}${c.created_at}
${c.comment}
`;
+ });
+ }
+ const cl = document.getElementById('commentsList');
+ cl.innerHTML = html; cl.scrollTop = cl.scrollHeight;
+ });
+ }
+ document.getElementById('commentAddForm').addEventListener('submit', function(e) {
+ e.preventDefault();
+ let taskId = document.getElementById('commentTaskId').value;
+ let comment = document.getElementById('newCommentText').value;
+ let fd = new FormData(); fd.append('task_id', taskId); fd.append('comment', comment);
+ fetch('/api/tasks/comment', {method:'POST', body:fd}).then(res=>res.json()).then(data=>{
+ if(data.success) { document.getElementById('newCommentText').value = ''; loadComments(taskId); }
+ });
+ });
function toggleTaskGlobal(taskId, projectId, state) { let comment = prompt("Kurzer Kommentar zur Erledigung:", ""); if (comment === null) return; const formData = new FormData(); formData.append('task_id', taskId); formData.append('project_id', projectId); formData.append('comment', comment); fetch('/api/tasks/toggle', { method: 'POST', body: formData }).then(res=>res.json()).then(data=>{ if(data.success) loadMyArea(); }); }
@@ -507,7 +566,7 @@
if (isDone && t.completion_comment) completedText += `
💬 "${t.completion_comment}"
`;
let assignHtml = t.assigned_username ? `
🙋 Zuweisung: ${t.assigned_username}` : '';
const safeTitle = t.title.replace(/'/g, "\\'").replace(/"/g, '"'); const safePhase = t.phase.replace(/'/g, "\\'").replace(/"/g, '"');
- let actionsHtml = !isClosed ? `
` : '';
+ let actionsHtml = !isClosed ? `
` : '';
list.innerHTML += `
${t.title}${prioHtml}
${tTimelineHtml} ${assignHtml}
${completedText}
${actionsHtml}
`;
});
}
diff --git a/src/database.php b/src/database.php
index a9691a3..b77cb5d 100644
--- a/src/database.php
+++ b/src/database.php
@@ -30,6 +30,9 @@ try {
try { $pdo->exec("ALTER TABLE tasks ADD COLUMN phase TEXT DEFAULT 'Standard'"); } catch (PDOException $e) {}
try { $pdo->exec("ALTER TABLE tasks ADD COLUMN completion_comment TEXT"); } catch (PDOException $e) {}
try { $pdo->exec("ALTER TABLE tasks ADD COLUMN assigned_to INTEGER"); } catch (PDOException $e) {}
+
+ // NEU: Auto-Migration für Task Notizen
+ $pdo->exec("CREATE TABLE IF NOT EXISTS task_comments (id INTEGER PRIMARY KEY AUTOINCREMENT, task_id INTEGER NOT NULL, username TEXT, comment TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP)");
$stmt = $pdo->query("SELECT COUNT(*) FROM users");
if ($stmt->fetchColumn() == 0) {
diff --git a/src/projects.php b/src/projects.php
index 959ce8c..f219f36 100644
--- a/src/projects.php
+++ b/src/projects.php
@@ -188,4 +188,33 @@ function handleGetMyArea() {
echo json_encode(['success' => true, 'projects' => $myProjects, 'tasks' => $myTasks]); exit;
}
+
+// NEU: Task Notizen laden
+function handleGetTaskComments() {
+ global $pdo; @session_start();
+ if (!isset($_SESSION['user_id'])) { http_response_code(401); exit; }
+ $taskId = $_GET['task_id'] ?? 0;
+ $stmt = $pdo->prepare("SELECT * FROM task_comments WHERE task_id = ? ORDER BY created_at ASC");
+ $stmt->execute([$taskId]);
+ echo json_encode(['success' => true, 'data' => $stmt->fetchAll()]); exit;
+}
+
+// NEU: Task Notiz hinzufügen
+function handleAddTaskComment() {
+ global $pdo; @session_start();
+ if (!isset($_SESSION['user_id'])) { http_response_code(401); exit; }
+ $taskId = $_POST['task_id'] ?? 0;
+ $comment = trim($_POST['comment'] ?? '');
+
+ if ($comment !== '') {
+ $pdo->prepare("INSERT INTO task_comments (task_id, username, comment) VALUES (?, ?, ?)")->execute([$taskId, $_SESSION['username'], $comment]);
+
+ $stmt = $pdo->prepare("SELECT project_id FROM tasks WHERE id = ?");
+ $stmt->execute([$taskId]);
+ if ($t = $stmt->fetch()) {
+ $pdo->prepare("UPDATE projects SET last_activity = CURRENT_TIMESTAMP WHERE id = ?")->execute([$t['project_id']]);
+ }
+ }
+ echo json_encode(['success' => true]); exit;
+}
?>
\ No newline at end of file
diff --git a/src/router.php b/src/router.php
index 13839b4..0ae8036 100644
--- a/src/router.php
+++ b/src/router.php
@@ -28,6 +28,8 @@ if ($path === '/' || $path === '') { header('Content-Type: text/html'); readfile
} elseif ($path === '/api/tasks/toggle' && $method === 'POST') { handleToggleTask();
} elseif ($path === '/api/tasks/edit' && $method === 'POST') { handleEditTask();
} elseif ($path === '/api/tasks/delete' && $method === 'POST') { handleDeleteTask();
+} elseif ($path === '/api/tasks/comments' && $method === 'GET') { handleGetTaskComments(); // NEU
+} elseif ($path === '/api/tasks/comment' && $method === 'POST') { handleAddTaskComment(); // NEU
} elseif ($path === '/api/myarea' && $method === 'GET') { handleGetMyArea();
} elseif ($path === '/api/me' && $method === 'GET') {
@session_start(); if (isset($_SESSION['user_id'])) { echo json_encode(['success' => true, 'username' => $_SESSION['username'], 'role' => $_SESSION['role'], 'user_id' => $_SESSION['user_id']]); } else { http_response_code(401); echo json_encode(['success' => false, 'error' => 'Not authenticated']); } exit;
Notizen