From 79373f8eb829a5f25ff5dce4aeabf06fbae82c45 Mon Sep 17 00:00:00 2001 From: Devin Lane Date: Thu, 5 Dec 2024 17:33:23 -0800 Subject: [PATCH 1/5] reduce font size --- .vscode/settings.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c3c81b8b..8347b197 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,4 @@ { - "editor.fontSize": 42, - "terminal.integrated.fontSize": 62 -} \ No newline at end of file + "editor.fontSize": 18, + "terminal.integrated.fontSize": 20 +} From dd52f62f76aa7433506ef86044ca16e3c939bafe Mon Sep 17 00:00:00 2001 From: Devin Lane Date: Thu, 5 Dec 2024 17:33:29 -0800 Subject: [PATCH 2/5] comment server.js --- server.js | 218 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 144 insertions(+), 74 deletions(-) diff --git a/server.js b/server.js index 58b53e2f..d7e95f56 100644 --- a/server.js +++ b/server.js @@ -1,30 +1,54 @@ -const express = require('express') -const app = express() -const MongoClient = require('mongodb').MongoClient -const PORT = 2121 -require('dotenv').config() - +// import express +const express = require("express"); +// call the express function and store it in the `app` variable +const app = express(); +// create instance of the Mongo Client which represents a pool of connections to the database +const MongoClient = require("mongodb").MongoClient; +// set the port that we'll use for our application +// this is where our server is listening for requests +const PORT = 2121; +// require the dotenv package to keep environment variables secret +require("dotenv").config(); +// set variables for the database let db, + // store connection string for database in this variable dbConnectionStr = process.env.DB_STRING, - dbName = 'todo' + // name the database + dbName = "todo"; -MongoClient.connect(dbConnectionStr, { useUnifiedTopology: true }) - .then(client => { - console.log(`Connected to ${dbName} Database`) - db = client.db(dbName) - }) - -app.set('view engine', 'ejs') -app.use(express.static('public')) -app.use(express.urlencoded({ extended: true })) -app.use(express.json()) +// connect to the Mongo DB database, using the connection string +MongoClient.connect(dbConnectionStr, { useUnifiedTopology: true }).then( + (client) => { + // print successful database connection to the console + console.log(`Connected to ${dbName} Database`); + // store the database name in the db variable + db = client.db(dbName); + } +); +// middleware methods used +// set the view engine to EJS +app.set("view engine", "ejs"); +// serve files in the public directory as static files +app.use(express.static("public")); +// parse incoming requests with urlencoded payloads +// The “extended” syntax allows for rich objects and arrays to be encoded into the URL-encoded format, allowing for a JSON-like experience with URL-encoded. +// essentially decode URLS and arrays where the body matches the content type +app.use(express.urlencoded({ extended: true })); +// middleware to parse json data from incoming requests, replaces body-parser +app.use(express.json()); -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 }) +// for GET requests on the root route +app.get("/", async (request, response) => { + // asynchronous request to go to the todos collection, find everything, and turn it into an array, store the result in todoitems variable + const todoItems = await db.collection("todos").find().toArray(); + // return from the db all the todos that aren't completed yet, store in itemsLeft variable + const itemsLeft = await db + .collection("todos") + .countDocuments({ completed: false }); + // render the response in ejs, passin the variables under items and left + response.render("index.ejs", { items: todoItems, left: itemsLeft }); // db.collection('todos').find().toArray() // .then(data => { // db.collection('todos').countDocuments({completed: false}) @@ -33,61 +57,107 @@ app.get('/',async (request, response)=>{ // }) // }) // .catch(error => console.error(error)) -}) - -app.post('/addTodo', (request, response) => { - db.collection('todos').insertOne({thing: request.body.todoItem, completed: false}) - .then(result => { - console.log('Todo Added') - response.redirect('/') - }) - .catch(error => console.error(error)) -}) - -app.put('/markComplete', (request, response) => { - db.collection('todos').updateOne({thing: request.body.itemFromJS},{ - $set: { - completed: true - } - },{ - sort: {_id: -1}, - upsert: false - }) - .then(result => { - console.log('Marked Complete') - response.json('Marked Complete') - }) - .catch(error => console.error(error)) - -}) +}); -app.put('/markUnComplete', (request, response) => { - db.collection('todos').updateOne({thing: request.body.itemFromJS},{ - $set: { - completed: false - } - },{ - sort: {_id: -1}, - upsert: false - }) - .then(result => { - console.log('Marked Complete') - response.json('Marked Complete') - }) - .catch(error => console.error(error)) +// POST requests on the /addTodo route +app.post("/addTodo", (request, response) => { + // to the db collection todos + db.collection("todos") + // insert one todo: thing comes from the request body "todoItem", and completed is set to false + .insertOne({ thing: request.body.todoItem, completed: false }) + // after this is done + .then((result) => { + // log to the console + console.log("Todo Added"); + // refresh the page to the root route + response.redirect("/"); + }) + // throw the error if we have one + .catch((error) => console.error(error)); +}); -}) +// a PUT request on the "mark complete route" +app.put("/markComplete", (request, response) => { + // on the todos DB collection + db.collection("todos") + // update one item in the databse + .updateOne( + // get the item from the request body in the JS (comes from the client side code) + { thing: request.body.itemFromJS }, + { + // set the completed field to true + $set: { + completed: true, + }, + }, + { + // move the item to the bottom of the list + sort: { _id: -1 }, + // if this item doesn't exist, don't insert it + upsert: false, + } + ) + // upon success + .then((result) => { + // log to to the console + console.log("Marked Complete"); + // send a json response to the client that it was successful + response.json("Marked Complete"); + }) + // print the error if there is one + .catch((error) => console.error(error)); +}); -app.delete('/deleteItem', (request, response) => { - db.collection('todos').deleteOne({thing: request.body.itemFromJS}) - .then(result => { - console.log('Todo Deleted') - response.json('Todo Deleted') - }) - .catch(error => console.error(error)) +// a PUT request on the mark uncomplete route +app.put("/markUnComplete", (request, response) => { + // on the todo database + db.collection("todos") + // update one item in the database + .updateOne( + // get the thing from the request body from the client JS + { thing: request.body.itemFromJS }, + { + // set completed to false + $set: { + completed: false, + }, + }, + { + // sort to the bottom of the list + sort: { _id: -1 }, + // don't insert this if it doesn't exist already + upsert: false, + } + ) + .then((result) => { + // log to the console + console.log("Marked Complete"); + // send a response back to the client that it's successful + response.json("Marked Complete"); + }) + // log the error + .catch((error) => console.error(error)); +}); -}) +// DELETE request on the deleteitem route +app.delete("/deleteItem", (request, response) => { + // on the todos database + db.collection("todos") + // delete one item, based on the request body we get from the client side JS + .deleteOne({ thing: request.body.itemFromJS }) + // upon success + .then((result) => { + // log to the console + console.log("Todo Deleted"); + // send a response to the client + response.json("Todo Deleted"); + }) + // log the error if there is one + .catch((error) => console.error(error)); +}); -app.listen(process.env.PORT || PORT, ()=>{ - console.log(`Server running on port ${PORT}`) -}) \ No newline at end of file +// set the app to listen on the port set within the .env file +app.listen(process.env.PORT || PORT, () => { + // log that the server is running + console.log(`Server running on port ${PORT}`); +}); From 52652f69c19da5dd634cc9521397fbd57d48ac8b Mon Sep 17 00:00:00 2001 From: Devin Lane Date: Thu, 5 Dec 2024 17:47:22 -0800 Subject: [PATCH 3/5] index.ejs --- views/index.ejs | 90 +++++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/views/index.ejs b/views/index.ejs index a26617ae..e4953e89 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -1,47 +1,57 @@ + + - - - - - Document - - - - - - - - - - - Document - - -

Todo List:

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

    Todo List:

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

    Left to do: <%= left %>

    + <% } %> + + +
  • + <% } %> +
+ +

Left to do: <%= left %>

-

Add A Todo:

+

Add A Todo:

-
- - -
- + +
+ + +
- - + + + From 8389c432b5b49f3539cce4564690d7b2a7dab356 Mon Sep 17 00:00:00 2001 From: Devin Lane Date: Fri, 6 Dec 2024 13:01:47 -0800 Subject: [PATCH 4/5] main.js --- public/js/main.js | 155 +++++++++++++++++++++++++++++----------------- 1 file changed, 97 insertions(+), 58 deletions(-) diff --git a/public/js/main.js b/public/js/main.js index ff0eac39..888c542d 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,72 +1,111 @@ -const deleteBtn = document.querySelectorAll('.fa-trash') -const item = document.querySelectorAll('.item span') -const itemCompleted = document.querySelectorAll('.item span.completed') +// create a "nodelist" of every item with these classes (trash icon) +const deleteBtn = document.querySelectorAll(".fa-trash"); +// create a "nodelist" of every item with these classes (item span) +const item = document.querySelectorAll(".item span"); +// create a "nodelist" of every item with these classes (item, completed) +const itemCompleted = document.querySelectorAll(".item span.completed"); -Array.from(deleteBtn).forEach((element)=>{ - element.addEventListener('click', deleteItem) -}) +// create an array from these node lists, and add event listeners to each one +Array.from(deleteBtn).forEach((element) => { + // run the deleteItem function when we click on the item + element.addEventListener("click", deleteItem); +}); -Array.from(item).forEach((element)=>{ - element.addEventListener('click', markComplete) -}) +Array.from(item).forEach((element) => { + // run the markComplete function when we click on the item + element.addEventListener("click", markComplete); +}); -Array.from(itemCompleted).forEach((element)=>{ - element.addEventListener('click', markUnComplete) -}) +Array.from(itemCompleted).forEach((element) => { + // run the markUnComplete function when we click on the item + element.addEventListener("click", markUnComplete); +}); -async function deleteItem(){ - const itemText = this.parentNode.childNodes[1].innerText - try{ - const response = await fetch('deleteItem', { - method: 'delete', - headers: {'Content-Type': 'application/json'}, +// delete item function +async function deleteItem() { + // from the trash icon, go up to the parent node (the
  • ) + // then go to the second child node (index 0), and grab the innerText + // essentially - save the todo item text in a variable + const itemText = this.parentNode.childNodes[1].innerText; + try { + // make a fetch request to the deleteItem route + const response = await fetch("deleteItem", { + // DELETE method + method: "delete", + // set the headers to json + headers: { "Content-Type": "application/json" }, + // in the body of the text body: JSON.stringify({ - 'itemFromJS': itemText - }) - }) - const data = await response.json() - console.log(data) - location.reload() - - }catch(err){ - console.log(err) + // send the text of the todo + itemFromJS: itemText, + }), + }); + // wait for the response + const data = await response.json(); + // log the data + console.log(data); + // reload the current URL + location.reload(); + } catch (err) { + // otherwise log the error + console.log(err); } } -async function markComplete(){ - const itemText = this.parentNode.childNodes[1].innerText - try{ - const response = await fetch('markComplete', { - method: 'put', - headers: {'Content-Type': 'application/json'}, +// mark complete function +async function markComplete() { + // grab the text from the todo + const itemText = this.parentNode.childNodes[1].innerText; + // make a fetch reqeust to the mark complete route + try { + const response = await fetch("markComplete", { + // PUT request + method: "put", + // json data + headers: { "Content-Type": "application/json" }, + // convert the objects to string body: JSON.stringify({ - 'itemFromJS': itemText - }) - }) - const data = await response.json() - console.log(data) - location.reload() - - }catch(err){ - console.log(err) + // send the todo text + itemFromJS: itemText, + }), + }); + // wait for the response + const data = await response.json(); + // log the data + console.log(data); + // reload the current route + location.reload(); + } catch (err) { + // log the error + console.log(err); } } -async function markUnComplete(){ - const itemText = this.parentNode.childNodes[1].innerText - try{ - const response = await fetch('markUnComplete', { - method: 'put', - headers: {'Content-Type': 'application/json'}, +// marking an item as uncomplete +async function markUnComplete() { + // grab the todo text + const itemText = this.parentNode.childNodes[1].innerText; + try { + // fetch request to the mark uncomplete route + const response = await fetch("markUnComplete", { + // PUT request + method: "put", + // json data is set + headers: { "Content-Type": "application/json" }, + // stringify the object body: JSON.stringify({ - 'itemFromJS': itemText - }) - }) - const data = await response.json() - console.log(data) - location.reload() - - }catch(err){ - console.log(err) + // send the todo text in the body of the request + itemFromJS: itemText, + }), + }); + // wait for the response + const data = await response.json(); + // log the data + console.log(data); + // reload the page + location.reload(); + } catch (err) { + // log the error if there is one + console.log(err); } -} \ No newline at end of file +} From b2d264507d7b460d5293183c1d0fa4c3fc73c37b Mon Sep 17 00:00:00 2001 From: Devin Lane Date: Fri, 6 Dec 2024 13:02:30 -0800 Subject: [PATCH 5/5] style.css --- public/css/style.css | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/public/css/style.css b/public/css/style.css index 0475253a..25275d12 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -1,7 +1,9 @@ -h1{ +/* set the H1 text color to red */ +h1 { color: red; } -.completed{ +/* set the completed items to gray, and strike a line through the text */ +.completed { color: gray; text-decoration: line-through; -} \ No newline at end of file +}