diff --git a/data/tasks.json b/data/tasks.json index 3747a16..185cda0 100644 --- a/data/tasks.json +++ b/data/tasks.json @@ -1,41 +1,4 @@ [ - { - "id": "1", - "title": "Learn Node.js Fundamentals", - "description": "Complete the Node.js basics course and build a simple server", - "status": "in-progress", - "priority": "high", - "dueDate": "2024-01-15", - "assignedTo": "John Doe", - "subtasks": [ - { - "id": "1.1", - "title": "Install Node.js", - "completed": true, - "description": "Download and install Node.js on your machine" - }, - { - "id": "1.2", - "title": "Create First Server", - "completed": false, - "description": "Build a simple HTTP server using Express.js" - }, - { - "id": "1.3", - "title": "Handle Routes", - "completed": false, - "description": "Learn how to create and handle different routes" - }, - { - "id": "1.4", - "title": "Test Subtask", - "description": "This is a test subtask", - "completed": false - } - ], - "createdAt": "2024-01-01T10:30:00.000Z", - "updatedAt": "2025-07-23T01:29:37.667Z" - }, { "id": "2", "title": "Build REST API", @@ -152,5 +115,363 @@ "subtasks": [], "createdAt": "2025-07-23T04:22:47.898Z", "updatedAt": "2025-07-23T04:22:47.899Z" + }, + { + "id": "6", + "title": "Frontend Development", + "description": "Build a React frontend to consume the API", + "status": "pending", + "priority": "medium", + "subtasks": [ + { + "title": "Setup React Project", + "completed": false, + "description": "Create new React application" + }, + { + "title": "Create Components", + "completed": false, + "description": "Build reusable UI components" + }, + { + "title": "Connect to API", + "completed": false, + "description": "Integrate frontend with backend API" + }, + { + "title": "Create Components", + "completed": false, + "description": "Build reusable UI components" + }, + { + "title": "Create Components", + "completed": false, + "description": "Build reusable UI components" + }, + { + "title": "Create Components", + "completed": false, + "description": "Build reusable UI components" + } + ] + }, + { + "id": "7", + "title": "Frontend Development", + "description": "Build a React frontend to consume the API", + "status": "pending", + "priority": "medium" + }, + { + "id": "8", + "title": "Frontend Development", + "description": "Build a React frontend to consume the API", + "status": "pending", + "priority": "medium", + "dueDate": null, + "assignedTo": null, + "subtasks": [], + "createdBy": null, + "assignedBy": null, + "createdAt": "2025-11-20T12:15:14.112Z", + "updatedAt": "2025-11-20T12:15:14.112Z" + }, + { + "id": "9", + "title": "Frontend Development", + "description": "Build a React frontend to consume the API", + "status": "pending", + "priority": "medium", + "dueDate": null, + "assignedTo": null, + "subtasks": [], + "createdBy": null, + "assignedBy": null, + "createdAt": "2025-11-20T12:16:10.881Z", + "updatedAt": "2025-11-20T12:16:10.883Z" + }, + { + "id": 10, + "title": "Frontend Development", + "description": "Build a React frontend to consume the API", + "status": "pending", + "priority": "medium", + "dueDate": null, + "assignedTo": null, + "subtasks": [ + { + "title": "Setup React Project", + "completed": false, + "description": "Create new React application" + }, + { + "title": "Setup React Project", + "completed": false, + "description": "Create new React application" + }, + { + "title": "Setup React Project", + "completed": false, + "description": "Create new React application" + } + ], + "createdBy": "Eng Abdinasir Bashir", + "assignedBy": null, + "createdAt": "2025-11-20T12:27:21.638Z", + "updatedAt": "2025-11-20T12:27:21.640Z" + }, + { + "id": 11, + "title": "Frontend Development", + "description": "Build a React frontend to consume the API", + "status": "pending", + "priority": "medium", + "dueDate": null, + "assignedTo": null, + "subtasks": [ + { + "title": "Setup React Project", + "completed": false, + "description": "Create new React application" + }, + { + "title": "Setup React Project", + "completed": false, + "description": "Create new React application" + }, + { + "title": "Setup React Project", + "completed": false, + "description": "Create new React application" + } + ], + "createdBy": "Eng Abdinasir Bashir", + "assignedBy": null, + "createdAt": "2025-11-20T12:33:41.353Z", + "updatedAt": "2025-11-20T12:33:41.356Z" + }, + { + "id": 12, + "title": "Frontend Development", + "description": "Build a React frontend to consume the API", + "status": "pending", + "priority": "medium", + "dueDate": null, + "assignedTo": null, + "subtasks": [ + { + "id": 1, + "title": "Setup React Project", + "status": "pending" + }, + { + "id": 2, + "title": "Setup React Project", + "status": "pending" + }, + { + "id": 3, + "title": "Setup React Project", + "status": "pending" + } + ], + "createdBy": "Eng Abdinasir Bashir", + "assignedBy": null, + "createdAt": "2025-11-20T12:35:38.030Z", + "updatedAt": "2025-11-20T12:35:38.032Z" + }, + { + "id": "13", + "title": "Development", + "description": " API", + "status": "pending", + "priority": "medium", + "dueDate": null, + "assignedTo": null, + "subtasks": [ + { + "id": 0.1, + "title": "Setup React Project", + "status": "pending" + }, + { + "id": 1.1, + "title": "Setup React Project", + "status": "pending" + }, + { + "id": 2.1, + "title": "Setup React Project", + "status": "pending" + } + ], + "createdBy": "Eng Abdinasir Bashir", + "assignedBy": null, + "createdAt": "2025-11-20T12:36:47.702Z", + "updatedAt": "2025-11-21T12:41:20.946Z" + }, + { + "id": "14", + "title": "Frontend Development", + "description": "Build a React frontend to consume the API", + "status": "pending", + "priority": "medium", + "dueDate": null, + "assignedTo": null, + "subtasks": [ + { + "id": 14.1, + "title": "Setup React Project", + "status": "pending" + }, + { + "id": 14.1, + "title": "Setup React Project", + "status": "pending" + }, + { + "id": 14.1, + "title": "Setup React Project", + "status": "pending" + } + ], + "createdBy": "Eng Abdinasir Bashir", + "assignedBy": null, + "createdAt": "2025-11-20T12:37:27.140Z", + "updatedAt": "2025-11-20T12:37:27.142Z" + }, + { + "id": "15", + "title": "Frontend ", + "description": " API", + "status": "completed", + "priority": "urgent", + "dueDate": null, + "assignedTo": null, + "subtasks": [ + { + "title": " Project", + "completed": true, + "description": "Create new React application" + }, + { + "title": "Setup React Project", + "completed": true, + "description": "Create new React application" + }, + { + "title": "Setup React Project", + "completed": true, + "description": "application" + } + ], + "createdBy": "Eng Abdinasir Bashir", + "assignedBy": null, + "createdAt": "2025-11-20T12:42:21.748Z", + "updatedAt": "2025-11-20T13:44:57.013Z" + }, + { + "id": 16, + "title": "Frontend Development", + "description": "Build a React frontend to consume the API", + "status": "pending", + "priority": "medium", + "dueDate": null, + "assignedTo": null, + "subtasks": [], + "createdBy": "Eng Abdinasir Bashir", + "assignedBy": null, + "createdAt": "2025-11-20T13:22:15.525Z", + "updatedAt": "2025-11-20T13:22:15.527Z" + }, + { + "id": 17, + "title": "Frontend ", + "description": " API", + "status": "completed", + "priority": "urgent", + "dueDate": null, + "assignedTo": null, + "subtasks": [ + { + "id": "17.1", + "title": " Project", + "status": "pending" + }, + { + "id": "17.2", + "title": "Setup React Project", + "status": "pending" + }, + { + "id": "17.3", + "title": "Setup React Project", + "status": "pending" + } + ], + "createdBy": "Eng Abdinasir Bashir", + "assignedBy": null, + "createdAt": "2025-11-20T13:47:09.446Z", + "updatedAt": "2025-11-20T13:47:09.446Z" + }, + { + "id": 18, + "title": "Frontend ", + "description": " API", + "status": "completed", + "priority": "urgent", + "dueDate": null, + "assignedTo": null, + "subtasks": [ + { + "id": "18.1", + "title": " Project", + "status": "pending" + }, + { + "id": "18.2", + "title": "Setup React Project", + "status": "pending" + }, + { + "id": "18.3", + "title": "Setup React Project", + "status": "pending" + } + ], + "createdBy": "Eng Abdinasir Bashir", + "assignedBy": null, + "createdAt": "2025-11-20T13:50:33.148Z", + "updatedAt": "2025-11-20T13:50:33.149Z" + }, + { + "id": "19", + "title": "Frontend ", + "description": " API", + "status": "completed", + "priority": "urgent", + "dueDate": null, + "assignedTo": null, + "subtasks": [ + { + "id": "19.1", + "title": " Project", + "status": "pending" + }, + { + "id": "19.2", + "title": "Setup React Project", + "status": "pending" + }, + { + "id": "19.3", + "title": "Setup React Project", + "status": "pending" + } + ], + "createdBy": "Eng Abdinasir Bashir", + "assignedBy": null, + "createdAt": "2025-11-20T13:51:57.216Z", + "updatedAt": "2025-11-20T13:51:57.218Z" } ] \ No newline at end of file diff --git a/routes/tasks.js b/routes/tasks.js index b2bcfcb..796efa0 100644 --- a/routes/tasks.js +++ b/routes/tasks.js @@ -1,3 +1,4 @@ + import express from "express"; import fs from "fs/promises"; import path from "path"; @@ -153,53 +154,163 @@ router.post("/tasks", async (req, res) => { try { // TODO: Implement task creation // 1. Extract data from req.body (title, description, status, priority, etc.) + + const { + title, + description, + status, + priority, + dueDate, + assignedTo, + subtasks, + createdBy, + assignedBy, + } = req.body; + // 2. Validate the data using validateTaskData function + + if (!title || !description || !status || !priority || !createdBy) { + return res.status(400).json({ error: "Missing required fields" }); + } + // 3. Get all existing tasks using getAllTasks() + const tasks = await getAllTasks(); + // 4. Generate a new ID for the task + + // const newId = tasks.length > 0 ? Math.max(...tasks.map((s) => parseInt(s.id))) + 1 : 1; // kan waxa uu ka dhiga id number , id : 1 + + + const newId = tasks.length > 0 ? String(Math.max(...tasks.map((s) => Number(s.id))) + 1) : "1"; // kan waxa uu ka dhigayaa id string , id : "1" + + let formattedSubtasks = []; + if (Array.isArray(subtasks)) { + formattedSubtasks = subtasks.map((st, index) => ({ + id: `${newId}.${index + 1}`, // note make newId + 1 : 3.1, 3.2, 3.3 + title: st.title || "", + status: st.status || "pending", + })); + } + // 5. Create a new task object with all required fields + + const newTask = { + id: newId, + title, + description, + status, + priority, + dueDate: dueDate || null, + assignedTo: assignedTo || null, + subtasks: formattedSubtasks, + createdBy, + assignedBy: assignedBy || null, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }; + // 6. Add the task to the tasks array + tasks.push(newTask); // 7. Save to file using writeTasks() - // 8. Send success response with status 201 + await writeTasks(tasks); - // Temporary response - remove this when you implement the above - res.status(501).json({ - success: false, - error: - "POST endpoint not implemented yet - implement task creation above", - }); + // 8. Send success response with status 201 + res + .status(201) + .json({ message: "tasks successfully created", tasks: newTask }); } catch (error) { res.status(500).json({ success: false, error: "Error creating task", - }); // 500 = Server Error + }); } }); // PUT /api/tasks/:id - Update task // PUT requests are used to update existing resources // The entire resource is replaced with the new data + router.put("/tasks/:id", async (req, res) => { try { - // TODO: Implement task update // 1. Extract the task ID from req.params + const { id } = req.params; + // 2. Get the update data from req.body + // const { title, description, status, priority, subtasks } = req.body; + const { + title, + description, + status, + priority, + dueDate, + assignedTo, + subtasks, + createdBy, + assignedBy, + } = req.body; + // 3. Validate the data if status or priority is being updated + const validStatuses = ["pending", "in-progress", "completed", "cancelled"]; + const validPriorities = ["low", "medium", "high", "urgent"]; + + if (status && !validStatuses.includes(status)) { + return res.status(400).json({ + success: false, + error: `Invalid status. Must be one of: ${validStatuses.join(", ")}`, + }); + } + + if (priority && !validPriorities.includes(priority)) { + return res.status(400).json({ + success: false, + error: `Invalid priority. Must be one of: ${validPriorities.join( + ", " + )}`, + }); + } + // 4. Get all tasks and find the task by ID + const tasks = await getAllTasks(); + const taskIndex = tasks.findIndex((t) => String(t.id) === String(id)); + // 5. Check if task exists, return 404 if not found + if (taskIndex === -1) { + return res.status(404).json({ success: false, error: "Task not found" }); + } + + const oldTask = tasks[taskIndex]; + // 6. Update the task with new data + const updatedTask = { + ...oldTask, + title: title || oldTask.title, + description: description || oldTask.description, + status: status ?? oldTask.status, + priority: priority ?? oldTask.priority, + subtasks: subtasks ?? oldTask.subtasks, + dueDate: dueDate || oldTask.dueDate, + assignedTo: assignedTo || oldTask.assignedTo, + createdBy: createdBy || oldTask.createdBy, + assignedBy: assignedBy || oldTask.assignedBy, + updatedAt: new Date().toISOString(), + }; + + tasks[taskIndex] = updatedTask; + // 7. Save to file using writeTasks() - // 8. Send success response with the updated task + await writeTasks(tasks); - // Temporary response - remove this when you implement the above - res.status(501).json({ - success: false, - error: "PUT endpoint not implemented yet - implement task update above", + // 8. Send success response with the updated task + return res.status(200).json({ + success: true, + message: "Task updated successfully", + data: updatedTask, }); } catch (error) { res.status(500).json({ success: false, - error: "Error updating task", - }); // 500 = Server Error + error: "Server error while updating task", + }); } }); @@ -207,27 +318,41 @@ router.put("/tasks/:id", async (req, res) => { // DELETE requests are used to remove resources router.delete("/tasks/:id", async (req, res) => { try { - // TODO: Implement task deletion // 1. Extract the task ID from req.params + const { id } = req.params; + // 2. Get all tasks and find the task by ID + const tasks = await getAllTasks(); + // 3. Check if task exists, return 404 if not found + const taskToDelete = tasks.find((task) => String(task.id) === String(id)); + if (!taskToDelete) { + return res.status(404).json({ error: "Task not found" }); + } + // 4. Store the task before deletion (for response) + const deletedTask = taskToDelete; + // 5. Remove the task from the array + const updatedTasks = tasks.filter( + (task) => String(task.id) !== String(id) + ); + // 6. Save to file using writeTasks() - // 7. Send success response with the deleted task + await writeTasks(updatedTasks); - // Temporary response - remove this when you implement the above - res.status(501).json({ - success: false, - error: - "DELETE endpoint not implemented yet - implement task deletion above", + // 7. Send success response with the deleted task + res.json({ + message: "Task deleted successfully", + deleted: deletedTask, }); } catch (error) { res.status(500).json({ success: false, error: "Error deleting task", - }); // 500 = Server Error + }); } }); + export default router;