Compare commits
5 Commits
63070fd90c
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| abd3458606 | |||
| 8841b571c9 | |||
| cf2df504b1 | |||
| 584ef9cbb7 | |||
| 597df4e886 |
BIN
Documentation.docx
Normal file
BIN
Documentation.docx
Normal file
Binary file not shown.
BIN
Documentation.pdf
Normal file
BIN
Documentation.pdf
Normal file
Binary file not shown.
@@ -41,124 +41,141 @@ taskSchema.index({ dateCreated: 1 })
|
|||||||
|
|
||||||
const Task = mongoose.model("Task", taskSchema);
|
const Task = mongoose.model("Task", taskSchema);
|
||||||
|
|
||||||
|
// this api route gets all the tasks from our database.
|
||||||
|
// if the request included a query string, use that for our sorting.
|
||||||
app.get('/api/tasks', async (req, res) => {
|
app.get('/api/tasks', async (req, res) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { sortBy } = req.query; // ?sortBy=dueDate or ?sortBy=dateCreated
|
const { sortBy } = req.query; // destructs the sortBy from the query string. e.g. ?sortBy=dueDate or ?sortBy=dateCreated
|
||||||
let sortOption = {};
|
let sortOption = {}; // create an empty sort object for the database query
|
||||||
|
|
||||||
if (sortBy === 'dueDate') {
|
if (sortBy === 'dueDate') {
|
||||||
sortOption = { dueDate: 1 }; // Ascending
|
sortOption = { dueDate: 1 }; // if the sortBy query string is dueDate, set the sortOption to dueDate and set the order to ascending (1)
|
||||||
} else if (sortBy === 'dateCreated') {
|
} else if (sortBy === 'dateCreated') {
|
||||||
sortOption = { dateCreated: 1 };
|
sortOption = { dateCreated: 1 }; // if the sortBy query string is dateCreated, set the sortOption to dateCreated and set the order to ascending (1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const tasks = await Task.find({}).sort(sortOption);
|
const tasks = await Task.find({}).sort(sortOption); // fetch all task documents and sort them using sortOption
|
||||||
|
|
||||||
if (!tasks) {
|
if (!tasks) {
|
||||||
|
// return the following if the query failed to return a value
|
||||||
return res.status(404).json({ message: "Tasks not found!" });
|
return res.status(404).json({ message: "Tasks not found!" });
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json(tasks);
|
res.json(tasks); // send a json response with the task objects
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// if there are any errors, do the following
|
||||||
console.error("Error:", error);
|
console.error("Error:", error);
|
||||||
res.status(500).json({ message: "Error grabbing tasks!" });
|
res.status(500).json({ message: "Error grabbing tasks!" });
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// this api route takes post requests to save a new MongoDB document, aka, our task
|
||||||
app.post('/api/tasks/todo', async (req, res) => {
|
app.post('/api/tasks/todo', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { title, description, dueDate } = req.body;
|
const { title, description, dueDate } = req.body; //destructures the request body
|
||||||
const taskData = { title, description, dueDate };
|
const taskData = { title, description, dueDate }; // creating the object to be used for creating the task
|
||||||
const createTask = new Task(taskData);
|
const createTask = new Task(taskData); // instantiates a new Task document/model instance using the taskData object values
|
||||||
const newTask = await createTask.save();
|
const newTask = await createTask.save(); // this saves the new document to MongoDB using the Task model/schema.
|
||||||
|
|
||||||
res.json({ task: newTask, message: "New task created successfully!" });
|
res.json({ task: newTask, message: "New task created successfully!" }); // if there were no error above, send a response where the body is an JSON object.
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// if there are any errors, do the following
|
||||||
console.error("Error:", error);
|
console.error("Error:", error);
|
||||||
res.status(500).json({ message: "Error creating the task!" });
|
res.status(500).json({ message: "Error creating the task!" });
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// To 'complete' the task and move columns ↓
|
// this api route marks a task as complete using its id.
|
||||||
|
|
||||||
app.patch('/api/tasks/complete/:id', async (req, res) => {
|
app.patch('/api/tasks/complete/:id', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { completed } = req.body;
|
const { completed } = req.body; // expected boolean value coming from the frontend
|
||||||
const taskId = req.params.id;
|
const taskId = req.params.id; // grab the task id from the URL params
|
||||||
const completedTask = await Task.findByIdAndUpdate(taskId, { completed }, { new: true });
|
const completedTask = await Task.findByIdAndUpdate(taskId, { completed }, { new: true }); // update completed status and return updated document
|
||||||
|
|
||||||
if (!completedTask) {
|
if (!completedTask) {
|
||||||
|
// return 404 if no task matches the provided id
|
||||||
return res.status(404).json({ message: "Task not found!" });
|
return res.status(404).json({ message: "Task not found!" });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// return updated task document and confirmation message
|
||||||
res.json({ task: completedTask, message: "Task set to 'Complete'" });
|
res.json({ task: completedTask, message: "Task set to 'Complete'" });
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// return 500 if database update fails
|
||||||
console.error("Error:", error);
|
console.error("Error:", error);
|
||||||
res.status(500).json({ message: "Error completing the task!" });
|
res.status(500).json({ message: "Error completing the task!" });
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// To make the task 'not complete' and move columns ↓
|
// this api route marks a task as not complete using its id.
|
||||||
|
|
||||||
app.patch('/api/tasks/notComplete/:id', async (req, res) => {
|
app.patch('/api/tasks/notComplete/:id', async (req, res) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { completed } = req.body;
|
const { completed } = req.body; // expected boolean value coming from the frontend
|
||||||
const taskId = req.params.id;
|
const taskId = req.params.id; // grab the task id from the URL params
|
||||||
const taskNotComplete = await Task.findByIdAndUpdate(taskId, { completed }, { new: true });
|
const taskNotComplete = await Task.findByIdAndUpdate(taskId, { completed }, { new: true }); // update completed status and return updated document
|
||||||
|
|
||||||
if (!taskNotComplete) {
|
if (!taskNotComplete) {
|
||||||
|
// return 404 if no task matches the provided id
|
||||||
return res.status(404).json({ message: "Task not found!" });
|
return res.status(404).json({ message: "Task not found!" });
|
||||||
}
|
}
|
||||||
|
// return updated task document and confirmation message
|
||||||
res.json({ task: taskNotComplete, message: "Task set to 'Not Complete'" });
|
res.json({ task: taskNotComplete, message: "Task set to 'Not Complete'" });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// return 500 if database update fails
|
||||||
console.error("Error:", error);
|
console.error("Error:", error);
|
||||||
res.status(500).json({ message: "Error making the task NOT complete!" });
|
res.status(500).json({ message: "Error making the task NOT complete!" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// this api route deletes a task by id.
|
||||||
app.delete('/api/tasks/delete/:id', async (req, res) => {
|
app.delete('/api/tasks/delete/:id', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const taskId = req.params.id;
|
const taskId = req.params.id; // grab the task id from the URL params
|
||||||
const deletedTask = await Task.findByIdAndDelete(taskId);
|
const deletedTask = await Task.findByIdAndDelete(taskId); // delete the matching task document
|
||||||
|
|
||||||
if (!deletedTask) {
|
if (!deletedTask) {
|
||||||
|
// return 404 if no task matches the provided id
|
||||||
return res.status(404).json({ message: "Task not found!" });
|
return res.status(404).json({ message: "Task not found!" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return deleted task document and confirmation message
|
||||||
res.json({ task: deletedTask, message: "Task deleted successfully!" });
|
res.json({ task: deletedTask, message: "Task deleted successfully!" });
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// return 500 if deletion fails
|
||||||
console.error("Error:", error);
|
console.error("Error:", error);
|
||||||
res.status(500).json({ message: "Error deleting the task!" });
|
res.status(500).json({ message: "Error deleting the task!" });
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// To edit exisiting task and update
|
// this api route updates a task's editable fields by id.
|
||||||
|
|
||||||
app.put('/api/tasks/update/:id', async (req, res) => {
|
app.put('/api/tasks/update/:id', async (req, res) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const taskId = req.params.id;
|
const taskId = req.params.id; // grab the task id from the URL params
|
||||||
const { title, description, dueDate } = req.body; // Extract data from front end request
|
const { title, description, dueDate } = req.body; // extract updated fields from request body
|
||||||
const taskData = { title, description, dueDate };
|
const taskData = { title, description, dueDate }; // build the update object
|
||||||
const updatedTask = await Task.findByIdAndUpdate(taskId, taskData, { new: true });
|
const updatedTask = await Task.findByIdAndUpdate(taskId, taskData, { new: true }); // apply update and return updated document
|
||||||
|
|
||||||
if (!updatedTask) {
|
if (!updatedTask) {
|
||||||
return res.status(404).json({ message: "Task not found!" });
|
// return 404 if no task matches the provided id
|
||||||
|
return res.status(404).json({ message: "Task not found!" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return updated task document and confirmation message
|
||||||
res.json({ task: updatedTask, message: "Task updated successfully!" });
|
res.json({ task: updatedTask, message: "Task updated successfully!" });
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// return 500 if update fails
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
res.status(500).json({ message: "Error updating the task!" });
|
res.status(500).json({ message: "Error updating the task!" });
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ footer {
|
|||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar-nav .nav-link.active {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar-toggler {
|
.navbar-toggler {
|
||||||
border: none !important;
|
border: none !important;
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>To Do App | Dashboard</title>
|
<title>BusketLisk • Dashboard</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
||||||
<link rel="stylesheet" href="./css/styles.css" />
|
<link rel="stylesheet" href="./css/styles.css" />
|
||||||
@@ -92,7 +92,8 @@
|
|||||||
<div class="d-flex gap-2 flex-wrap mb-3">
|
<div class="d-flex gap-2 flex-wrap mb-3">
|
||||||
<button type="button" class="btn btn-outline-light quick-date-btn" data-quick="today">Today</button>
|
<button type="button" class="btn btn-outline-light quick-date-btn" data-quick="today">Today</button>
|
||||||
<button type="button" class="btn btn-outline-light quick-date-btn" data-quick="tomorrow">Tomorrow</button>
|
<button type="button" class="btn btn-outline-light quick-date-btn" data-quick="tomorrow">Tomorrow</button>
|
||||||
<button type="button" class="btn btn-outline-light quick-date-btn" data-quick="nextWeek">Next week</button>
|
<button type="button" class="btn btn-outline-light quick-date-btn" data-quick="nextWeek">Next
|
||||||
|
week</button>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary shadow-sm px-5">
|
<button type="submit" class="btn btn-primary shadow-sm px-5">
|
||||||
Create Task
|
Create Task
|
||||||
@@ -156,26 +157,49 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
<!-- Modal -->
|
<!-- Toast-style alert container, populated by showAlert() in api.js -->
|
||||||
<div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="editTaskModalLabel" aria-hidden="true">
|
<div id="alertContainer" class="position-fixed top-0 end-0 p-3" style="z-index: 1080;"></div>
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
|
||||||
<div class="modal-content">
|
<!-- Delete confirmation modal -->
|
||||||
<div class="modal-header">
|
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteTaskModalLabel" aria-hidden="true">
|
||||||
<h1 class="modal-title fs-5" id="editTaskModalLabel">Edit Task</h1>
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<div class="modal-content">
|
||||||
</div>
|
<div class="modal-header">
|
||||||
<div class="modal-body">
|
<h1 class="modal-title fs-5" id="deleteTaskModalLabel">Delete Task</h1>
|
||||||
<form id="editTaskForm">
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
<input id="editTaskName" placeholder="Task Name" class="mb-2 form-control shadow-sm" type="text">
|
</div>
|
||||||
<textarea id="editTaskDescription" placeholder="Task Description" rows="7" class="form-control mb-2 shadow-sm"></textarea>
|
<div class="modal-body">
|
||||||
<input id="editDueDate" placeholder="Task Name" class="mb-3 form-control shadow-sm" type="date">
|
<p class="mb-0">Are you sure you want to delete this task? This action cannot be undone.</p>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
<div class="modal-footer">
|
||||||
<div class="modal-footer">
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
<button id="saveButton" type="submit" class="btn btn-primary">Save changes</button>
|
<button id="confirmDeleteButton" type="button" class="btn btn-danger">Delete</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal -->
|
||||||
|
<div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="editTaskModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h1 class="modal-title fs-5" id="editTaskModalLabel">Edit Task</h1>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="editTaskForm">
|
||||||
|
<input id="editTaskName" placeholder="Task Name" class="mb-2 form-control shadow-sm" type="text">
|
||||||
|
<textarea id="editTaskDescription" placeholder="Task Description" rows="7"
|
||||||
|
class="form-control mb-2 shadow-sm"></textarea>
|
||||||
|
<input id="editDueDate" placeholder="Task Name" class="mb-3 form-control shadow-sm" type="date">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button id="saveButton" type="submit" class="btn btn-primary">Save changes</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="./js/api.js"></script>
|
<script src="./js/api.js"></script>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>To Do App | Features</title>
|
<title>BusketLisk • Features</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
||||||
<link rel="stylesheet" href="./css/styles.css" />
|
<link rel="stylesheet" href="./css/styles.css" />
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>To Do App | Home</title>
|
<title>BusketLisk • Home</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
||||||
<link rel="stylesheet" href="./css/styles.css" />
|
<link rel="stylesheet" href="./css/styles.css" />
|
||||||
@@ -50,7 +50,8 @@
|
|||||||
<section class="d-flex justify-content-center flex-column align-items-center bg-img text-center px-3">
|
<section class="d-flex justify-content-center flex-column align-items-center bg-img text-center px-3">
|
||||||
<h1 class="display-2 text-white">Stay organised with BucketLisk</h1>
|
<h1 class="display-2 text-white">Stay organised with BucketLisk</h1>
|
||||||
<p class="lead text-white-50 col-12 col-md-8 col-lg-6 mt-3">
|
<p class="lead text-white-50 col-12 col-md-8 col-lg-6 mt-3">
|
||||||
The simple, no-nonsense to-do app that keeps your team on track, from morning stand-up to end-of-quarter shipping.
|
The simple, no-nonsense to-do app that keeps your team on track, from morning stand-up to end-of-quarter
|
||||||
|
shipping.
|
||||||
</p>
|
</p>
|
||||||
<div class="d-flex justify-content-center align-items-center gap-3 mt-4 flex-wrap">
|
<div class="d-flex justify-content-center align-items-center gap-3 mt-4 flex-wrap">
|
||||||
<a href="./dashboard.html" class="btn btn-primary btn-lg px-5">Try it for free</a>
|
<a href="./dashboard.html" class="btn btn-primary btn-lg px-5">Try it for free</a>
|
||||||
@@ -102,9 +103,11 @@
|
|||||||
When you're done, tick it off and move it to the completed column to keep the momentum going.
|
When you're done, tick it off and move it to the completed column to keep the momentum going.
|
||||||
</p>
|
</p>
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li class="mb-2"><img src="./images/Tick.svg" alt="" width="18" class="me-2">Sort by due date or created date</li>
|
<li class="mb-2"><img src="./images/Tick.svg" alt="" width="18" class="me-2">Sort by due date or created
|
||||||
|
date</li>
|
||||||
<li class="mb-2"><img src="./images/Tick.svg" alt="" width="18" class="me-2">Edit any task inline</li>
|
<li class="mb-2"><img src="./images/Tick.svg" alt="" width="18" class="me-2">Edit any task inline</li>
|
||||||
<li class="mb-2"><img src="./images/Tick.svg" alt="" width="18" class="me-2">Works on desktop, tablet and mobile</li>
|
<li class="mb-2"><img src="./images/Tick.svg" alt="" width="18" class="me-2">Works on desktop, tablet and
|
||||||
|
mobile</li>
|
||||||
</ul>
|
</ul>
|
||||||
<a href="./dashboard.html" class="btn btn-primary px-4 mt-3">Open the dashboard</a>
|
<a href="./dashboard.html" class="btn btn-primary px-4 mt-3">Open the dashboard</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -160,7 +163,8 @@
|
|||||||
<div class="container py-5">
|
<div class="container py-5">
|
||||||
<div class="rounded shadow bg-translucent p-4 p-lg-5 col-12 col-lg-8 mx-auto text-white text-center">
|
<div class="rounded shadow bg-translucent p-4 p-lg-5 col-12 col-lg-8 mx-auto text-white text-center">
|
||||||
<p class="fs-4 fst-italic mb-4">
|
<p class="fs-4 fst-italic mb-4">
|
||||||
"We switched our whole team over in a week. Everyone actually uses it, and that's the first time I've ever said that about a task tool."
|
"We switched our whole team over in a week. Everyone actually uses it, and that's the first time I've ever
|
||||||
|
said that about a task tool."
|
||||||
</p>
|
</p>
|
||||||
<p class="mb-0"><strong>Jamie L.</strong></p>
|
<p class="mb-0"><strong>Jamie L.</strong></p>
|
||||||
<p class="text-white-50 mb-0">Operations Lead, Greenfield Studio</p>
|
<p class="text-white-50 mb-0">Operations Lead, Greenfield Studio</p>
|
||||||
|
|||||||
@@ -42,6 +42,20 @@ function resetForm() {
|
|||||||
taskForm.reset();
|
taskForm.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showAlert(message, variant = 'success') {
|
||||||
|
const container = document.getElementById('alertContainer');
|
||||||
|
if (!container) return;
|
||||||
|
const alert = document.createElement('div');
|
||||||
|
alert.className = `alert alert-${variant} alert-dismissible fade show shadow-sm`;
|
||||||
|
alert.role = 'alert';
|
||||||
|
alert.innerHTML = `
|
||||||
|
${message}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
`;
|
||||||
|
container.appendChild(alert);
|
||||||
|
setTimeout(() => bootstrap.Alert.getOrCreateInstance(alert).close(), 3000);
|
||||||
|
}
|
||||||
|
|
||||||
const sortButton = document.getElementById("sortSelect");
|
const sortButton = document.getElementById("sortSelect");
|
||||||
window.addEventListener("DOMContentLoaded", () => {
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
sortButton.value = "default";
|
sortButton.value = "default";
|
||||||
@@ -93,7 +107,11 @@ taskForm.addEventListener("submit", (event) => {
|
|||||||
|
|
||||||
else if (event.target.classList.contains("delete")) {
|
else if (event.target.classList.contains("delete")) {
|
||||||
const taskId = event.target.getAttribute("data-id");
|
const taskId = event.target.getAttribute("data-id");
|
||||||
deleteTask(taskId);
|
const confirmButton = document.getElementById('confirmDeleteButton');
|
||||||
|
confirmButton.addEventListener('click', async () => {
|
||||||
|
await deleteTask(taskId);
|
||||||
|
bootstrap.Modal.getInstance(document.getElementById('deleteModal')).hide();
|
||||||
|
}, { once: true });
|
||||||
}
|
}
|
||||||
else if (event.target.classList.contains('edit')) {
|
else if (event.target.classList.contains('edit')) {
|
||||||
const task = {
|
const task = {
|
||||||
@@ -148,7 +166,7 @@ function formatTask(task) {
|
|||||||
li.innerHTML = `
|
li.innerHTML = `
|
||||||
<div class="d-flex justify-content-between align-items-start">
|
<div class="d-flex justify-content-between align-items-start">
|
||||||
<h4 class="${done} col-11">${task.title}</h4>
|
<h4 class="${done} col-11">${task.title}</h4>
|
||||||
<button data-id="${task._id}" type="button" class="btn-close delete" aria-label="Close"></button>
|
<button data-id="${task._id}" type="button" class="btn-close delete" data-bs-toggle="modal" data-bs-target="#deleteModal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<p class="${done}">${task.description}</p>
|
<p class="${done}">${task.description}</p>
|
||||||
<p class="${done}"><strong>Due: </strong>${new Date(task.dueDate).toLocaleDateString()}</p>
|
<p class="${done}"><strong>Due: </strong>${new Date(task.dueDate).toLocaleDateString()}</p>
|
||||||
@@ -328,6 +346,7 @@ async function deleteTask(taskId) {
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
console.log({ message: "Deleted Task:", Task: data });
|
console.log({ message: "Deleted Task:", Task: data });
|
||||||
displayTasks();
|
displayTasks();
|
||||||
|
showAlert('Task deleted successfully.');
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error:", error);
|
console.error("Error:", error);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>To Do App | Login</title>
|
<title>BusketLisk • Login</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
||||||
<link rel="stylesheet" href="./css/styles.css" />
|
<link rel="stylesheet" href="./css/styles.css" />
|
||||||
@@ -46,21 +46,21 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section class="d-flex justify-content-center flex-column align-items-center bg-img">
|
<section class="d-flex justify-content-center flex-column align-items-center bg-img">
|
||||||
<div class="rounded shadow bg-translucent p-4">
|
<div class="rounded shadow bg-translucent p-4">
|
||||||
<h2 class="mb-3 text-white">Login</h2>
|
<h2 class="mb-3 text-white">Login</h2>
|
||||||
<form id="loginForm">
|
<form id="loginForm">
|
||||||
<input id="email" placeholder="Email Address" required type="email" class="mb-3 form-control shadow-sm">
|
<input id="email" placeholder="Email Address" required type="email" class="mb-3 form-control shadow-sm">
|
||||||
<input id="password" placeholder="Password" required type="password" class="form-control shadow-sm">
|
<input id="password" placeholder="Password" required type="password" class="form-control shadow-sm">
|
||||||
<div class="d-flex justify-content-between align-items-center gap-3 mt-3">
|
<div class="d-flex justify-content-between align-items-center gap-3 mt-3">
|
||||||
<button type="submit" class="btn btn-primary shadow-sm">Login</button>
|
<button type="submit" class="btn btn-primary shadow-sm">Login</button>
|
||||||
<div class="text-end">
|
<div class="text-end">
|
||||||
<a href="./signup.html">Don't have an account yet?</a>
|
<a href="./signup.html">Don't have an account yet?</a>
|
||||||
<br>
|
<br>
|
||||||
<a href="#">Forgot Password?</a>
|
<a href="#">Forgot Password?</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- ↓ Footer ↓ -->
|
<!-- ↓ Footer ↓ -->
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>To Do App | Pricing</title>
|
<title>BusketLisk • Pricing</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
||||||
<link rel="stylesheet" href="./css/styles.css" />
|
<link rel="stylesheet" href="./css/styles.css" />
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>To Do App | Signup</title>
|
<title>BusketLisk • Signup</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
||||||
<link rel="stylesheet" href="./css/styles.css" />
|
<link rel="stylesheet" href="./css/styles.css" />
|
||||||
@@ -46,23 +46,23 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section class="d-flex justify-content-center flex-column align-items-center bg-img">
|
<section class="d-flex justify-content-center flex-column align-items-center bg-img">
|
||||||
<div class="rounded shadow bg-translucent p-4">
|
<div class="rounded shadow bg-translucent p-4">
|
||||||
<h2 class="mb-3 text-white">Create Account</h2>
|
<h2 class="mb-3 text-white">Create Account</h2>
|
||||||
<form id="signupForm">
|
<form id="signupForm">
|
||||||
<input id="firstName" placeholder="First Name" required type="text" class="mb-3 form-control shadow-sm">
|
<input id="firstName" placeholder="First Name" required type="text" class="mb-3 form-control shadow-sm">
|
||||||
<input id="lastName" placeholder="Last Name" required type="text" class="mb-3 form-control shadow-sm">
|
<input id="lastName" placeholder="Last Name" required type="text" class="mb-3 form-control shadow-sm">
|
||||||
<input id="email" placeholder="Email Address" required type="email" class="mb-3 form-control shadow-sm">
|
<input id="email" placeholder="Email Address" required type="email" class="mb-3 form-control shadow-sm">
|
||||||
<input id="password" placeholder="Password" required type="password" class="form-control shadow-sm">
|
<input id="password" placeholder="Password" required type="password" class="form-control shadow-sm">
|
||||||
<div class="d-flex justify-content-between align-items-center gap-3 mt-3">
|
<div class="d-flex justify-content-between align-items-center gap-3 mt-3">
|
||||||
<button type="submit" class="btn btn-primary shadow-sm">Sign Up</button>
|
<button type="submit" class="btn btn-primary shadow-sm">Sign Up</button>
|
||||||
<div class="text-end">
|
<div class="text-end">
|
||||||
<a href="./login.html">Already have an account?</a>
|
<a href="./login.html">Already have an account?</a>
|
||||||
<br>
|
<br>
|
||||||
<a href="./dashboard.html">Try without an account</a>
|
<a href="./dashboard.html">Try without an account</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- ↓ Footer ↓ -->
|
<!-- ↓ Footer ↓ -->
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>To Do App | Support</title>
|
<title>BusketLisk • Support</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous" />
|
||||||
<link rel="stylesheet" href="./css/styles.css" />
|
<link rel="stylesheet" href="./css/styles.css" />
|
||||||
@@ -69,7 +69,8 @@
|
|||||||
<form id="contactForm">
|
<form id="contactForm">
|
||||||
<input name="name" type="text" class="form-control mb-3 shadow-sm" placeholder="Your name" required>
|
<input name="name" type="text" class="form-control mb-3 shadow-sm" placeholder="Your name" required>
|
||||||
<input name="email" type="email" class="form-control mb-3 shadow-sm" placeholder="Your email" required>
|
<input name="email" type="email" class="form-control mb-3 shadow-sm" placeholder="Your email" required>
|
||||||
<textarea name="message" rows="5" class="form-control mb-3 shadow-sm" placeholder="How can we help?" required></textarea>
|
<textarea name="message" rows="5" class="form-control mb-3 shadow-sm" placeholder="How can we help?"
|
||||||
|
required></textarea>
|
||||||
<button type="submit" class="btn btn-primary px-4">Send message</button>
|
<button type="submit" class="btn btn-primary px-4">Send message</button>
|
||||||
</form>
|
</form>
|
||||||
<hr class="border-light my-4">
|
<hr class="border-light my-4">
|
||||||
|
|||||||
Reference in New Issue
Block a user