Osatehtävät (subtaskit) TODO-tehtäviin

Uusi todo_subtasks-taulu + 3 API-endpointtia (add/toggle/delete).
Tehtävän lukunäkymässä checkbox-lista osatehtäville, lisäys
Enter-näppäimellä tai Lisää-napilla. Valmiit yliviivataan.
Tehtävälistassa näkyy edistyminen (esim. ☑ 2/5).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 14:45:47 +02:00
parent ad4c5605f6
commit 093f40ac09
5 changed files with 171 additions and 2 deletions

62
api.php
View File

@@ -2423,6 +2423,68 @@ switch ($action) {
}
break;
case 'todo_subtask_add':
requireAuth();
$companyId = requireCompany();
if ($method !== 'POST') { echo json_encode(['error' => 'POST required']); break; }
try {
$input = json_decode(file_get_contents('php://input'), true);
$todoId = $input['todo_id'] ?? '';
$title = trim($input['title'] ?? '');
if (!$todoId || !$title) { echo json_encode(['error' => 'todo_id ja title vaaditaan']); break; }
$rows = _dbFetchAll("SELECT company_id FROM todos WHERE id = ?", [$todoId]);
if (empty($rows) || $rows[0]['company_id'] !== $companyId) {
http_response_code(404);
echo json_encode(['error' => 'Tehtävää ei löytynyt']);
break;
}
$id = generateId();
dbAddTodoSubtask($todoId, ['id' => $id, 'title' => $title, 'created_by' => currentUser()]);
echo json_encode(['success' => true, 'id' => $id]);
} catch (\Throwable $e) {
http_response_code(500);
echo json_encode(['error' => 'Virhe: ' . $e->getMessage()]);
}
break;
case 'todo_subtask_toggle':
requireAuth();
requireCompany();
if ($method !== 'POST') { echo json_encode(['error' => 'POST required']); break; }
try {
$input = json_decode(file_get_contents('php://input'), true);
$subtaskId = $input['id'] ?? '';
if (!$subtaskId) { echo json_encode(['error' => 'id vaaditaan']); break; }
$completed = dbToggleTodoSubtask($subtaskId);
echo json_encode(['success' => true, 'completed' => $completed]);
} catch (\Throwable $e) {
http_response_code(500);
echo json_encode(['error' => 'Virhe: ' . $e->getMessage()]);
}
break;
case 'todo_subtask_delete':
requireAuth();
requireCompany();
if ($method !== 'POST') { echo json_encode(['error' => 'POST required']); break; }
try {
$input = json_decode(file_get_contents('php://input'), true);
$subtaskId = $input['id'] ?? '';
if (!$subtaskId) { echo json_encode(['error' => 'id vaaditaan']); break; }
$rows = _dbFetchAll("SELECT created_by FROM todo_subtasks WHERE id = ?", [$subtaskId]);
if (!empty($rows) && ($rows[0]['created_by'] === currentUser() || isCompanyAdmin())) {
dbDeleteTodoSubtask($subtaskId);
echo json_encode(['success' => true]);
} else {
http_response_code(403);
echo json_encode(['error' => 'Ei oikeutta']);
}
} catch (\Throwable $e) {
http_response_code(500);
echo json_encode(['error' => 'Virhe: ' . $e->getMessage()]);
}
break;
// ---------- ARCHIVE ----------
case 'archived_customers':
requireAuth();