diff --git a/.vscode/settings.json b/.vscode/settings.json index c3c81b8b..696d9a61 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,6 @@ { + // Sets the font size for the main editor in VS Code "editor.fontSize": 42, + // Sets the font size specifically for the integrated terminal "terminal.integrated.fontSize": 62 } \ No newline at end of file diff --git a/public/css/style.css b/public/css/style.css index 0475253a..78c11c4d 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -1,6 +1,9 @@ +/* All

headings will have red text */ h1{ color: red; } +/* Elements with the class "completed" will have gray text + and a line through them, typically used to show something is finished or crossed out */ .completed{ color: gray; text-decoration: line-through; diff --git a/public/js/main.js b/public/js/main.js index ff0eac39..9f179eb4 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,22 +1,33 @@ +// Select all delete buttons (trash icons) on the page const deleteBtn = document.querySelectorAll('.fa-trash') + +// Select all elements inside the li with class 'item' const item = document.querySelectorAll('.item span') + +// Select all elements that are already marked as completed const itemCompleted = document.querySelectorAll('.item span.completed') +// Add a click event listener to each delete button Array.from(deleteBtn).forEach((element)=>{ element.addEventListener('click', deleteItem) }) +// Add a click event listener to each incomplete item marking it as completed Array.from(item).forEach((element)=>{ element.addEventListener('click', markComplete) }) +// Add a click event listener to each completed item marking it as uncompleted Array.from(itemCompleted).forEach((element)=>{ element.addEventListener('click', markUnComplete) }) +// Function to delete an item async function deleteItem(){ + // Get the text content of the task to be deleted const itemText = this.parentNode.childNodes[1].innerText try{ + // Send a DELETE request to the server with the item text const response = await fetch('deleteItem', { method: 'delete', headers: {'Content-Type': 'application/json'}, @@ -24,18 +35,23 @@ async function deleteItem(){ 'itemFromJS': itemText }) }) + // Parse the JSON response from the server and store it in the variable `data` const data = await response.json() console.log(data) + // Reload the page to show updated list location.reload() - + // If an error occurs in the try block, catch it and log it to the console }catch(err){ console.log(err) } } +// Function to mark an item as complete async function markComplete(){ + // Get the text content of the task to be updated const itemText = this.parentNode.childNodes[1].innerText try{ + // Send a PUT request to mark item as complete const response = await fetch('markComplete', { method: 'put', headers: {'Content-Type': 'application/json'}, @@ -43,18 +59,23 @@ async function markComplete(){ 'itemFromJS': itemText }) }) + // Parse the JSON response from the server and store it in the variable `data` const data = await response.json() console.log(data) + // Reload the page to show the updated list location.reload() - + // If an error occurs in the try block, catch it and log it to the console }catch(err){ console.log(err) } } +// Function to mark an item as uncomplete (undo complete) async function markUnComplete(){ + // Get the text content of the task to be updated const itemText = this.parentNode.childNodes[1].innerText try{ + // Send a PUT request to the server to mark the item as incomplete const response = await fetch('markUnComplete', { method: 'put', headers: {'Content-Type': 'application/json'}, @@ -62,10 +83,12 @@ async function markUnComplete(){ 'itemFromJS': itemText }) }) + // Parse the JSON response from the server and store it in the variable `data` const data = await response.json() console.log(data) + // Reload the page to show the updated list location.reload() - + // If an error occurs in the try block, catch it and log it to the console }catch(err){ console.log(err) } diff --git a/server.js b/server.js index 58b53e2f..3f4f9fcb 100644 --- a/server.js +++ b/server.js @@ -1,30 +1,33 @@ -const express = require('express') -const app = express() -const MongoClient = require('mongodb').MongoClient -const PORT = 2121 -require('dotenv').config() +const express = require('express') // Import Express library +const app = express() // Initialize Express app +const MongoClient = require('mongodb').MongoClient // Import MongoClient for MongoDB +const PORT = 2121 // Default port for server +require('dotenv').config() // Load environment variables from .env file let db, - dbConnectionStr = process.env.DB_STRING, - dbName = 'todo' + dbConnectionStr = process.env.DB_STRING, // MongoDB connection string from environment + dbName = 'todo' // Name of the database +// Connect to MongoDB MongoClient.connect(dbConnectionStr, { useUnifiedTopology: true }) .then(client => { console.log(`Connected to ${dbName} Database`) - db = client.db(dbName) + db = client.db(dbName) // Assign the connected database to variable }) -app.set('view engine', 'ejs') -app.use(express.static('public')) -app.use(express.urlencoded({ extended: true })) -app.use(express.json()) - +app.set('view engine', 'ejs') // Set EJS as the templating engine +app.use(express.static('public')) // Serve static files from 'public' folder +app.use(express.urlencoded({ extended: true })) // Parse URL-encoded bodies (from HTML forms) +app.use(express.json()) // Parse JSON bodies +// GET route for home page app.get('/',async (request, response)=>{ - const todoItems = await db.collection('todos').find().toArray() - const itemsLeft = await db.collection('todos').countDocuments({completed: false}) - response.render('index.ejs', { items: todoItems, left: itemsLeft }) + const todoItems = await db.collection('todos').find().toArray() // Fetch all todo items from 'todos' collection + const itemsLeft = await db.collection('todos').countDocuments({completed: false}) // Count how many items are not completed + response.render('index.ejs', { items: todoItems, left: itemsLeft }) // Render index.ejs with the todo items and remaining count + + // Old promise-based approach (commented out) // db.collection('todos').find().toArray() // .then(data => { // db.collection('todos').countDocuments({completed: false}) @@ -35,59 +38,58 @@ app.get('/',async (request, response)=>{ // .catch(error => console.error(error)) }) +// POST route to add a new todo app.post('/addTodo', (request, response) => { - db.collection('todos').insertOne({thing: request.body.todoItem, completed: false}) + db.collection('todos').insertOne({thing: request.body.todoItem, completed: false}) // Add a new todo to the database, initially not completed .then(result => { console.log('Todo Added') - response.redirect('/') + response.redirect('/') // Redirect back to home page }) - .catch(error => console.error(error)) + .catch(error => console.error(error)) // Catch and log any errors }) +// PUT route to mark a todo as complete app.put('/markComplete', (request, response) => { - db.collection('todos').updateOne({thing: request.body.itemFromJS},{ - $set: { - completed: true - } - },{ - sort: {_id: -1}, - upsert: false - }) + db.collection('todos').updateOne( + { thing: request.body.itemFromJS }, // Find item by text + { $set: { completed: true } }, // Set completed to true + { sort: { _id: -1 }, upsert: false} // Update latest item, do not create if missing + ) .then(result => { - console.log('Marked Complete') - response.json('Marked Complete') + console.log('Marked Complete') // Log to the server console that the item was marked complete + response.json('Marked Complete') // Send a JSON response back to the client confirming the update }) - .catch(error => console.error(error)) + .catch(error => console.error(error)) // Catch and log any errors }) +// PUT route to mark a todo as incomplete app.put('/markUnComplete', (request, response) => { - db.collection('todos').updateOne({thing: request.body.itemFromJS},{ - $set: { - completed: false - } - },{ - sort: {_id: -1}, - upsert: false - }) + db.collection('todos').updateOne( + { thing: request.body.itemFromJS }, // Find item by text + { $set: { completed: false } }, // Set completed to false + { sort: { _id: -1 }, upsert: false } // Update latest item, do not create if missing + ) .then(result => { - console.log('Marked Complete') - response.json('Marked Complete') + console.log('Marked Incomplete') //Log to the server console that the item was marked incomplete + response.json('Marked Incomplete') // Send a JSON response back to the client confirming the update }) - .catch(error => console.error(error)) + .catch(error => console.error(error)) // Catch and log any errors }) +// DELETE route to remove a todo app.delete('/deleteItem', (request, response) => { db.collection('todos').deleteOne({thing: request.body.itemFromJS}) .then(result => { - console.log('Todo Deleted') - response.json('Todo Deleted') + console.log('Todo Deleted') //Log to the server console that a todo item was successfully deleted + response.json('Todo Deleted') // Respond with JSON message }) - .catch(error => console.error(error)) + .catch(error => console.error(error)) // Catch and log any errors }) +// Start the server app.listen(process.env.PORT || PORT, ()=>{ 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..e921486e 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -4,44 +4,43 @@ - Document + Todo List + + - - - - - - - Document - - +

Todo List:

+
    - <% for(let i=0; i < items.length; i++) {%> -
  • - <% if(items[i].completed === true) {%> - <%= items[i].thing %> - <% }else{ %> - <%= items[i].thing %> - <% } %> - -
  • - <% } %> + + <% for(let i=0; i < items.length; i++) {%> +
  • + + <% if(items[i].completed === true) {%> + <%= items[i].thing %> + <% }else{ %> + <%= items[i].thing %> + <% } %> + + +
  • + <% } %>
+

Left to do: <%= left %>

+

Add A Todo:

-
- + - + \ No newline at end of file