diff --git a/.vscode/settings.json b/.vscode/settings.json index c3c81b8b..5011a806 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,4 @@ { - "editor.fontSize": 42, - "terminal.integrated.fontSize": 62 + "editor.fontSize": 15, + "terminal.integrated.fontSize": 30 } \ No newline at end of file diff --git a/public/js/main.js b/public/js/main.js index ff0eac39..0fb79ca5 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,72 +1,81 @@ +// Select all elements with the class 'fa-trash' (trash can icons used for deleting items) const deleteBtn = document.querySelectorAll('.fa-trash') +// Select all elements inside items (to-do tasks) const item = document.querySelectorAll('.item span') +// Select all elements that are marked as completed const itemCompleted = document.querySelectorAll('.item span.completed') -Array.from(deleteBtn).forEach((element)=>{ - element.addEventListener('click', deleteItem) +// Loop through each delete button and add a click event listener that calls the deleteItem function +Array.from(deleteBtn).forEach((element) => { + element.addEventListener('click', deleteItem) // Add click event to trigger deletion }) -Array.from(item).forEach((element)=>{ - element.addEventListener('click', markComplete) +// Loop through each to-do item and add a click event listener that calls the markComplete function +Array.from(item).forEach((element) => { + element.addEventListener('click', markComplete) // Add click event to mark item as complete }) -Array.from(itemCompleted).forEach((element)=>{ - element.addEventListener('click', markUnComplete) +// Loop through each completed to-do item and add a click event listener that calls the markUnComplete function +Array.from(itemCompleted).forEach((element) => { + element.addEventListener('click', markUnComplete) // Add click event to mark item as uncompleted }) +// Define an async function to delete a to-do item async function deleteItem(){ - const itemText = this.parentNode.childNodes[1].innerText + const itemText = this.parentNode.childNodes[1].innerText // Get the text of the to-do item to delete try{ - const response = await fetch('deleteItem', { - method: 'delete', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({ - 'itemFromJS': itemText + const response = await fetch('deleteItem', { // Send a DELETE request to the server + method: 'delete', // Specify HTTP method as DELETE + headers: {'Content-Type': 'application/json'}, // Set request headers + body: JSON.stringify({ // Send the item text as JSON + 'itemFromJS': itemText // Key-value pair for item text }) - }) - const data = await response.json() - console.log(data) - location.reload() + }) + const data = await response.json() // Wait for the server's JSON response + console.log(data) // Log the response to the console + location.reload() // Reload the page to update the list - }catch(err){ - console.log(err) + } catch(err){ + console.log(err) // Log any errors if they occur } } +// Define an async function to mark a to-do item as complete async function markComplete(){ - const itemText = this.parentNode.childNodes[1].innerText + const itemText = this.parentNode.childNodes[1].innerText // Get the text of the to-do item to update try{ - const response = await fetch('markComplete', { - method: 'put', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({ - 'itemFromJS': itemText + const response = await fetch('markComplete', { // Send a PUT request to the server + method: 'put', // Specify HTTP method as PUT + headers: {'Content-Type': 'application/json'}, // Set request headers + body: JSON.stringify({ // Send the item text as JSON + 'itemFromJS': itemText // Key-value pair for item text }) - }) - const data = await response.json() - console.log(data) - location.reload() + }) + const data = await response.json() // Wait for the server's JSON response + console.log(data) // Log the response to the console + location.reload() // Reload the page to show the updated status - }catch(err){ - console.log(err) + } catch(err){ + console.log(err) // Log any errors if they occur } } +// Define an async function to mark a completed to-do item as uncompleted async function markUnComplete(){ - const itemText = this.parentNode.childNodes[1].innerText + const itemText = this.parentNode.childNodes[1].innerText // Get the text of the to-do item to update try{ - const response = await fetch('markUnComplete', { - method: 'put', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({ - 'itemFromJS': itemText + const response = await fetch('markUnComplete', { // Send a PUT request to the server + method: 'put', // Specify HTTP method as PUT + headers: {'Content-Type': 'application/json'}, // Set request headers + body: JSON.stringify({ // Send the item text as JSON + 'itemFromJS': itemText // Key-value pair for item text }) - }) - const data = await response.json() - console.log(data) - location.reload() + }) + const data = await response.json() // Wait for the server's JSON response + console.log(data) // Log the response to the console + location.reload() // Reload the page to show the updated status - }catch(err){ - console.log(err) + } catch(err){ + console.log(err) // Log any errors if they occur } -} \ No newline at end of file +} diff --git a/server.js b/server.js index 58b53e2f..2a979cca 100644 --- a/server.js +++ b/server.js @@ -1,30 +1,42 @@ +// Import the express module const express = require('express') +// Create an instance of an Express app const app = express() +// Import the MongoClient from mongodb to interact with the database const MongoClient = require('mongodb').MongoClient +// Define the default port for the server to listen on const PORT = 2121 +// Load environment variables from a .env file require('dotenv').config() - +// Declare variables for the database and connection string let db, - dbConnectionStr = process.env.DB_STRING, - dbName = 'todo' + dbConnectionStr = process.env.DB_STRING, // Get the MongoDB connection string from .env + dbName = 'todo' // Define the database name -MongoClient.connect(dbConnectionStr, { useUnifiedTopology: true }) +// Connect to MongoDB +MongoClient.connect(dbConnectionStr, { useUnifiedTopology: true }) // Use unified topology to avoid warnings .then(client => { - console.log(`Connected to ${dbName} Database`) - db = client.db(dbName) + console.log(`Connected to ${dbName} Database`) // Log connection success + db = client.db(dbName) // Store reference to the connected database }) - + +// Set EJS as the templating engine app.set('view engine', 'ejs') +// Serve static files (like CSS and JS) from the "public" folder app.use(express.static('public')) +// Parse incoming request bodies (form data) app.use(express.urlencoded({ extended: true })) +// Parse incoming JSON data app.use(express.json()) +// Handle GET request for the homepage +app.get('/', async (request, response) => { + const todoItems = await db.collection('todos').find().toArray() // Fetch all to-do items + const itemsLeft = await db.collection('todos').countDocuments({ completed: false }) // Count items not completed + response.render('index.ejs', { items: todoItems, left: itemsLeft }) // Render the EJS view with data -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 }) + // --- Alternative approach using .then() instead of async/await --- // db.collection('todos').find().toArray() // .then(data => { // db.collection('todos').countDocuments({completed: false}) @@ -35,59 +47,55 @@ app.get('/',async (request, response)=>{ // .catch(error => console.error(error)) }) +// Handle POST request to add a new to-do item 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 }) // Insert new item .then(result => { - console.log('Todo Added') - response.redirect('/') + console.log('Todo Added') // Log success + response.redirect('/') // Redirect back to homepage }) - .catch(error => console.error(error)) + .catch(error => console.error(error)) // Log any errors }) +// Handle PUT request to mark an item as completed 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 }, // Match the item by its text + { $set: { completed: true } }, // Set "completed" to true + { sort: { _id: -1 }, upsert: false } // Sort and prevent upsert + ) .then(result => { - console.log('Marked Complete') - response.json('Marked Complete') + console.log('Marked Complete') // Log success + response.json('Marked Complete') // Send JSON response }) - .catch(error => console.error(error)) - + .catch(error => console.error(error)) // Log any errors }) +// Handle PUT request to mark an item as uncompleted 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 }, // Match the item by its text + { $set: { completed: false } }, // Set "completed" to false + { sort: { _id: -1 }, upsert: false } // Sort and prevent upsert + ) .then(result => { - console.log('Marked Complete') - response.json('Marked Complete') + console.log('Marked Complete') // Still logs "Marked Complete" (could update message for clarity) + response.json('Marked Complete') // Send JSON response }) - .catch(error => console.error(error)) - + .catch(error => console.error(error)) // Log any errors }) +// Handle DELETE request to remove an item app.delete('/deleteItem', (request, response) => { - db.collection('todos').deleteOne({thing: request.body.itemFromJS}) + db.collection('todos').deleteOne({ thing: request.body.itemFromJS }) // Delete the item .then(result => { - console.log('Todo Deleted') - response.json('Todo Deleted') + console.log('Todo Deleted') // Log success + response.json('Todo Deleted') // Send JSON response }) - .catch(error => console.error(error)) - + .catch(error => console.error(error)) // Log any errors }) -app.listen(process.env.PORT || PORT, ()=>{ - console.log(`Server running on port ${PORT}`) -}) \ No newline at end of file +// Start the server on the specified port +app.listen(process.env.PORT || PORT, () => { + console.log(`Server running on port ${PORT}`) // Log the port the server is running on +})