diff --git a/.vscode/settings.json b/.vscode/settings.json index c3c81b8b..56461683 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,4 @@ { - "editor.fontSize": 42, - "terminal.integrated.fontSize": 62 + "editor.fontSize": 14, + "terminal.integrated.fontSize": 14 } \ No newline at end of file diff --git a/public/js/main.js b/public/js/main.js index ff0eac39..96d3ce65 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,72 +1,116 @@ +// Selects all delete buttons on the page const deleteBtn = document.querySelectorAll('.fa-trash') + +// Selects all to-do items const item = document.querySelectorAll('.item span') + +// Selects all completed to-do items const itemCompleted = document.querySelectorAll('.item span.completed') -Array.from(deleteBtn).forEach((element)=>{ +// Adds a click event to each delete button +// When clicked, it runs the deleteItem function +Array.from(deleteBtn).forEach((element) => { element.addEventListener('click', deleteItem) }) -Array.from(item).forEach((element)=>{ +// Adds a click event to each incomplete to-do item +// When clicked, it runs the markComplete function +Array.from(item).forEach((element) => { element.addEventListener('click', markComplete) }) -Array.from(itemCompleted).forEach((element)=>{ +// Adds a click event to each completed to-do item +// When clicked, it runs the markUnComplete function +Array.from(itemCompleted).forEach((element) => { element.addEventListener('click', markUnComplete) }) -async function deleteItem(){ +// Deletes a to-do item +async function deleteItem() { + // Gets the text of the selected to-do item const itemText = this.parentNode.childNodes[1].innerText - try{ + + try { + // Sends a DELETE request to the server const response = await fetch('deleteItem', { method: 'delete', - headers: {'Content-Type': 'application/json'}, + headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ - 'itemFromJS': itemText + 'itemFromJS': itemText }) - }) + }) + + // Converts the server response to JSON const data = await response.json() + + // Displays the response in the console console.log(data) + + // Reloads the page so the deleted item disappears location.reload() - }catch(err){ + } catch (err) { + // Logs any errors to the console console.log(err) } } -async function markComplete(){ +// Marks a to-do item as complete +async function markComplete() { + // Gets the text of the selected to-do item const itemText = this.parentNode.childNodes[1].innerText - try{ + + try { + // Sends a PUT request to the server to mark the item complete const response = await fetch('markComplete', { method: 'put', - headers: {'Content-Type': 'application/json'}, + headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ 'itemFromJS': itemText }) - }) + }) + + // Converts the server response to JSON const data = await response.json() + + // Displays the response in the console console.log(data) + + // Reloads the page to show the item as completed location.reload() - }catch(err){ + } catch (err) { + // Logs any errors to the console console.log(err) } } -async function markUnComplete(){ +// Marks a completed to-do item as incomplete +async function markUnComplete() { + // Gets the text of the selected completed item const itemText = this.parentNode.childNodes[1].innerText - try{ + + try { + // Sends a PUT request to the server to mark the item as incomplete const response = await fetch('markUnComplete', { method: 'put', - headers: {'Content-Type': 'application/json'}, + headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ 'itemFromJS': itemText }) - }) + }) + + // Converts the server response to JSON const data = await response.json() + + // Displays the response in the console console.log(data) + + // Reloads the page to show the item as incomplete location.reload() - }catch(err){ + } catch (err) { + // Logs any errors to the console console.log(err) } } \ No newline at end of file diff --git a/server.js b/server.js index 58b53e2f..20ec8941 100644 --- a/server.js +++ b/server.js @@ -1,30 +1,59 @@ + +// Imports the Express framework const express = require('express') + +// Creates an Express application const app = express() + +// Imports the MongoDB client const MongoClient = require('mongodb').MongoClient + +// Sets the default port for the server const PORT = 2121 -require('dotenv').config() +// Loads environment variables from the .env file +require('dotenv').config() +// Creates variables for the database connection and database name let db, dbConnectionStr = process.env.DB_STRING, dbName = 'todo' +// Connects the application to MongoDB using the connection string MongoClient.connect(dbConnectionStr, { useUnifiedTopology: true }) .then(client => { + // Displays a message when the database connection is successful console.log(`Connected to ${dbName} Database`) + + // Selects the todo database db = client.db(dbName) }) - + +// Sets EJS as the view engine for rendering HTML pages app.set('view engine', 'ejs') + +// Serves static files such as CSS and JavaScript from the public folder app.use(express.static('public')) + +// Allows the server to receive data from HTML forms app.use(express.urlencoded({ extended: true })) + +// Allows the server to receive JSON data app.use(express.json()) +// GET route for the home page +app.get('/', async (request, response) => { -app.get('/',async (request, response)=>{ + // Gets all to-do items from the todos collection const todoItems = await db.collection('todos').find().toArray() - const itemsLeft = await db.collection('todos').countDocuments({completed: false}) + + // Counts how many to-do items are not completed + const itemsLeft = await db.collection('todos').countDocuments({ completed: false }) + + // Renders the index.ejs page and sends the to-do items and count to it response.render('index.ejs', { items: todoItems, left: itemsLeft }) + + // Older version of the code that used promises instead of async/await // db.collection('todos').find().toArray() // .then(data => { // db.collection('todos').countDocuments({completed: false}) @@ -35,59 +64,105 @@ app.get('/',async (request, response)=>{ // .catch(error => console.error(error)) }) +// POST route for adding a new to-do item app.post('/addTodo', (request, response) => { - db.collection('todos').insertOne({thing: request.body.todoItem, completed: false}) + + // Adds the new to-do item to the todos collection + // New items start with completed set to false + db.collection('todos').insertOne({ + thing: request.body.todoItem, + completed: false + }) + .then(result => { + // Displays a message when the to-do item is added console.log('Todo Added') + + // Redirects the user back to the home page response.redirect('/') }) + .catch(error => console.error(error)) }) +// PUT route for marking a to-do item as complete app.put('/markComplete', (request, response) => { - db.collection('todos').updateOne({thing: request.body.itemFromJS},{ - $set: { - completed: true - } - },{ - sort: {_id: -1}, - upsert: false - }) + + // Finds the selected to-do item and changes completed to true + db.collection('todos').updateOne( + { thing: request.body.itemFromJS }, + { + $set: { + completed: true + } + }, + { + sort: { _id: -1 }, + upsert: false + } + ) + .then(result => { + // Displays a message when the item is marked complete console.log('Marked Complete') + + // Sends a response back to the JavaScript in the browser response.json('Marked Complete') }) - .catch(error => console.error(error)) + .catch(error => console.error(error)) }) +// PUT route for marking a completed to-do item as incomplete app.put('/markUnComplete', (request, response) => { - db.collection('todos').updateOne({thing: request.body.itemFromJS},{ - $set: { - completed: false - } - },{ - sort: {_id: -1}, - upsert: false - }) + + // Finds the selected to-do item and changes completed back to false + db.collection('todos').updateOne( + { thing: request.body.itemFromJS }, + { + $set: { + completed: false + } + }, + { + sort: { _id: -1 }, + upsert: false + } + ) + .then(result => { + // Displays a message when the item is marked incomplete console.log('Marked Complete') + + // Sends a response back to the JavaScript in the browser response.json('Marked Complete') }) - .catch(error => console.error(error)) + .catch(error => console.error(error)) }) +// DELETE route for deleting a to-do item app.delete('/deleteItem', (request, response) => { - db.collection('todos').deleteOne({thing: request.body.itemFromJS}) + + // Finds and deletes the selected to-do item + db.collection('todos').deleteOne({ + thing: request.body.itemFromJS + }) + .then(result => { + // Displays a message when the item is deleted console.log('Todo Deleted') + + // Sends a response back to the JavaScript in the browser response.json('Todo Deleted') }) - .catch(error => console.error(error)) + .catch(error => console.error(error)) }) -app.listen(process.env.PORT || PORT, ()=>{ +// Starts the Express server +app.listen(process.env.PORT || PORT, () => { + + // Displays the port where the server is running console.log(`Server running on port ${PORT}`) -}) \ No newline at end of file +}) diff --git a/views/index.ejs b/views/index.ejs index a26617ae..f27d9004 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -32,14 +32,25 @@ <% } %> +