diff --git a/package.json b/package.json index 2327747..b28e34f 100644 --- a/package.json +++ b/package.json @@ -19,12 +19,12 @@ "author": "Duraan", "license": "MIT", "dependencies": { - "express": "^4.18.2", - "cors": "^2.8.5", "body-parser": "^1.20.2", + "cors": "^2.8.5", + "express": "^4.18.2", "node-fetch": "^3.3.2" }, "devDependencies": { - "nodemon": "^3.0.1" + "nodemon": "^3.1.11" } } diff --git a/routes/app.js b/routes/app.js new file mode 100644 index 0000000..6d88640 --- /dev/null +++ b/routes/app.js @@ -0,0 +1,11 @@ +import express from "express"; +import tasksRouter from "./routes/tasks.js"; + +const app = express(); +app.use(express.json()); + +app.use("/api", tasksRouter); + +app.listen(3000, () => { + console.log("Server running at http://localhost:3000"); +}); diff --git a/routes/tasks.js b/routes/tasks.js index b2bcfcb..98725d3 100644 --- a/routes/tasks.js +++ b/routes/tasks.js @@ -99,6 +99,7 @@ router.get("/tasks", async (req, res) => { // Filter by assignedTo if provided if (req.query.assignedTo) { filteredTasks = filteredTasks.filter((task) => + task.assignedTo && task.assignedTo .toLowerCase() .includes(req.query.assignedTo.toLowerCase()) @@ -151,21 +152,56 @@ router.get("/tasks/:id", async (req, res) => { // req.body contains the data sent in the request body router.post("/tasks", async (req, res) => { try { - // TODO: Implement task creation // 1. Extract data from req.body (title, description, status, priority, etc.) + const taskData = req.body; + // 2. Validate the data using validateTaskData function + const validation = validateTaskData(taskData); + if (!validation.isValid) { + return res.status(400).json({ + success: false, + error: validation.error, + }); + } + // 3. Get all existing tasks using getAllTasks() + const tasks = await getAllTasks(); + // 4. Generate a new ID for the task + // Find the highest numeric ID and increment it + const numericIds = tasks + .map((task) => parseInt(task.id)) + .filter((id) => !isNaN(id)); + const newId = numericIds.length > 0 + ? (Math.max(...numericIds) + 1).toString() + : "1"; + // 5. Create a new task object with all required fields + const now = new Date().toISOString(); + const newTask = { + id: newId, + title: taskData.title, + description: taskData.description, + status: taskData.status, + priority: taskData.priority, + dueDate: taskData.dueDate || null, + assignedTo: taskData.assignedTo || null, + subtasks: taskData.subtasks || [], + createdAt: now, + updatedAt: now, + }; + // 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({ + success: true, + message: "Task created successfully", + data: newTask, }); } catch (error) { res.status(500).json({ @@ -180,20 +216,54 @@ router.post("/tasks", async (req, res) => { // 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 updateData = req.body; + // 3. Validate the data if status or priority is being updated + // Create a temporary object with existing task data merged with update data for validation + const validation = validateTaskData(updateData); + if (!validation.isValid) { + return res.status(400).json({ + success: false, + error: validation.error, + }); + } + // 4. Get all tasks and find the task by ID + const tasks = await getAllTasks(); + const taskIndex = tasks.findIndex((task) => task.id === 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", + }); + } + // 6. Update the task with new data + // Preserve the ID and timestamps, but update updatedAt + const updatedTask = { + ...tasks[taskIndex], + ...updateData, + id: id, // Ensure ID cannot be changed + createdAt: tasks[taskIndex].createdAt, // Preserve original creation time + updatedAt: new Date().toISOString(), // Update the updatedAt timestamp + }; + + 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 + res.json({ + success: true, + message: "Task updated successfully", + data: updatedTask, }); } catch (error) { res.status(500).json({ @@ -207,20 +277,35 @@ 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(); + const taskIndex = tasks.findIndex((task) => task.id === id); + // 3. Check if task exists, return 404 if not found + if (taskIndex === -1) { + return res.status(404).json({ + success: false, + error: "Task not found", + }); + } + // 4. Store the task before deletion (for response) + const deletedTask = tasks[taskIndex]; + // 5. Remove the task from the array + tasks.splice(taskIndex, 1); + // 6. Save to file using writeTasks() - // 7. Send success response with the deleted task + await writeTasks(tasks); - // 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({ + success: true, + message: "Task deleted successfully", + data: deletedTask, }); } catch (error) { res.status(500).json({