- Added stats cards to display active, completed, overdue, and due-today tasks on the dashboard. - Implemented search functionality to filter tasks in real-time based on user input. - Introduced quick-pick date buttons for easier task date selection. - Updated task rendering logic to handle empty states for task lists. - Improved overall user interface with new CSS styles for stat cards and buttons. chore: Update environment variables and backend error handling - Fixed formatting in the .env file for consistency. - Enhanced error handling in the backend API for better debugging. feat: Revamp frontend pages with new features and pricing sections - Redesigned the index.html page to include a hero section and feature highlights. - Created a new features page with dynamic loading of features from JSON. - Implemented a pricing page that loads plans from JSON and highlights the featured plan. - Added support and FAQ sections with dynamic content loading and contact form functionality. - Introduced JSON files for FAQs, features, and pricing to allow easy updates without code changes.
168 lines
4.4 KiB
JavaScript
168 lines
4.4 KiB
JavaScript
require("dotenv").config();
|
|
const express = require('express');
|
|
const mongoose = require("mongoose")
|
|
const cors = require('cors');
|
|
|
|
const port = 3001;
|
|
const app = express();
|
|
|
|
app.use(express.json());
|
|
app.use(cors());
|
|
|
|
(async () => {
|
|
try {
|
|
mongoose.set("autoIndex", false);
|
|
|
|
await mongoose.connect(process.env.MONGO_URI);
|
|
console.log("✅ MongoDB Connected");
|
|
|
|
await Task.syncIndexes();
|
|
console.log("✅ Indexes created");
|
|
|
|
app.listen(port, () => {
|
|
console.log(`✅ To Do App listening on port ${port}`);
|
|
});
|
|
} catch (error) {
|
|
console.error(`Startup Error! ${error}`);
|
|
}
|
|
})();
|
|
|
|
// Task Schema
|
|
const taskSchema = new mongoose.Schema({
|
|
title: { type: String, required: true },
|
|
completed: { type: Boolean, required: true, default: false },
|
|
description: { type: String, required: true },
|
|
dueDate: { type: Date, required: true },
|
|
dateCreated: { type: Date, required: true, default: new Date() }
|
|
})
|
|
|
|
taskSchema.index({ dueDate: 1 })
|
|
taskSchema.index({ dateCreated: 1 })
|
|
|
|
const Task = mongoose.model("Task", taskSchema);
|
|
|
|
app.get('/api/tasks', async (req, res) => {
|
|
|
|
try {
|
|
const { sortBy } = req.query; // ?sortBy=dueDate or ?sortBy=dateCreated
|
|
let sortOption = {};
|
|
|
|
if (sortBy === 'dueDate') {
|
|
sortOption = { dueDate: 1 }; // Ascending
|
|
} else if (sortBy === 'dateCreated') {
|
|
sortOption = { dateCreated: 1 };
|
|
}
|
|
|
|
const tasks = await Task.find({}).sort(sortOption);
|
|
|
|
if (!tasks) {
|
|
return res.status(404).json({ message: "Tasks not found!" });
|
|
}
|
|
|
|
res.json(tasks);
|
|
} catch (error) {
|
|
console.error("Error:", error);
|
|
res.status(500).json({ message: "Error grabbing tasks!" });
|
|
|
|
}
|
|
});
|
|
|
|
|
|
app.post('/api/tasks/todo', async (req, res) => {
|
|
try {
|
|
const { title, description, dueDate } = req.body;
|
|
const taskData = { title, description, dueDate };
|
|
const createTask = new Task(taskData);
|
|
const newTask = await createTask.save();
|
|
|
|
res.json({ task: newTask, message: "New task created successfully!" });
|
|
|
|
} catch (error) {
|
|
console.error("Error:", error);
|
|
res.status(500).json({ message: "Error creating the task!" });
|
|
}
|
|
|
|
});
|
|
|
|
// To 'complete' the task and move columns ↓
|
|
|
|
app.patch('/api/tasks/complete/:id', async (req, res) => {
|
|
try {
|
|
const { completed } = req.body;
|
|
const taskId = req.params.id;
|
|
const completedTask = await Task.findByIdAndUpdate(taskId, { completed }, { new: true });
|
|
|
|
if (!completedTask) {
|
|
return res.status(404).json({ message: "Task not found!" });
|
|
|
|
}
|
|
res.json({ task: completedTask, message: "Task set to 'Complete'" });
|
|
|
|
} catch (error) {
|
|
console.error("Error:", error);
|
|
res.status(500).json({ message: "Error completing the task!" });
|
|
|
|
}
|
|
});
|
|
|
|
// To make the task 'not complete' and move columns ↓
|
|
|
|
app.patch('/api/tasks/notComplete/:id', async (req, res) => {
|
|
|
|
try {
|
|
const { completed } = req.body;
|
|
const taskId = req.params.id;
|
|
const taskNotComplete = await Task.findByIdAndUpdate(taskId, { completed }, { new: true });
|
|
|
|
if (!taskNotComplete) {
|
|
return res.status(404).json({ message: "Task not found!" });
|
|
}
|
|
res.json({ task: taskNotComplete, message: "Task set to 'Not Complete'" });
|
|
} catch (error) {
|
|
console.error("Error:", error);
|
|
res.status(500).json({ message: "Error making the task NOT complete!" });
|
|
}
|
|
});
|
|
|
|
app.delete('/api/tasks/delete/:id', async (req, res) => {
|
|
try {
|
|
const taskId = req.params.id;
|
|
const deletedTask = await Task.findByIdAndDelete(taskId);
|
|
|
|
if (!deletedTask) {
|
|
return res.status(404).json({ message: "Task not found!" });
|
|
}
|
|
|
|
res.json({ task: deletedTask, message: "Task deleted successfully!" });
|
|
|
|
} catch (error) {
|
|
console.error("Error:", error);
|
|
res.status(500).json({ message: "Error deleting the task!" });
|
|
|
|
}
|
|
});
|
|
|
|
// To edit exisiting task and update
|
|
|
|
app.put('/api/tasks/update/:id', async (req, res) => {
|
|
|
|
try {
|
|
const taskId = req.params.id;
|
|
const { title, description, dueDate } = req.body; // Extract data from front end request
|
|
const taskData = { title, description, dueDate };
|
|
const updatedTask = await Task.findByIdAndUpdate(taskId, taskData, { new: true });
|
|
|
|
if (!updatedTask) {
|
|
return res.status(404).json({ message: "Task not found!" });
|
|
}
|
|
|
|
res.json({ task: updatedTask, message: "Task updated successfully!" });
|
|
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
res.status(500).json({ message: "Error updating the task!" });
|
|
|
|
}
|
|
|
|
});
|