Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
.env
.env
.DS_Store
13 changes: 13 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
/*
This package.json defines the basic information and dependencies of the "rap-name-api" project.
- "name", "version", and "description" describe the project.
- "main" points to the entry file, which in this case is "index.js".
- "scripts" defines a test script placeholder.
- "dependencies" lists all the required npm packages for the app to run:
- express: web framework
- mongodb: connects to the MongoDB database
- ejs: renders HTML templates
- dotenv: loads environment variables from a .env file
- cors: enables Cross-Origin Resource Sharing
This file is essential for installing and managing everything the app needs to function.
*/
{
"name": "rap-name-api",
"version": "1.0.0",
Expand Down
33 changes: 23 additions & 10 deletions public/js/main.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,50 @@
//Select all delete buttons (trash icons)
const deleteBtn = document.querySelectorAll('.fa-trash')

//Select all to-do item spans (that are not completed)
const item = document.querySelectorAll('.item span')

//Select all to-do item spans that are marked as completed
const itemCompleted = document.querySelectorAll('.item span.completed')

//Add event listeners to all delete buttons
Array.from(deleteBtn).forEach((element)=>{
element.addEventListener('click', deleteItem)
element.addEventListener('click', deleteItem) //When clicked, run deleteItem()
})

//Add event listeners to all completed items
Array.from(item).forEach((element)=>{
element.addEventListener('click', markComplete)
element.addEventListener('click', markComplete)//When clicked, run markComplete()
})

//Add event listeners to all incomplete items
Array.from(itemCompleted).forEach((element)=>{
element.addEventListener('click', markUnComplete)
element.addEventListener('click', markUnComplete)//When clicked, run markUnComplete()
})


//Async function to delete an 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
try{
const response = await fetch('deleteItem', {
method: 'delete',
method: 'delete', //HTTP delete method
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
'itemFromJS': itemText
'itemFromJS': itemText //Send the item text to the server
})
})
const data = await response.json()
console.log(data)
location.reload()
const data = await response.json() //wait for server response
console.log(data) //log the response
location.reload() //reload the page to see changes

}catch(err){
console.log(err)
console.log(err) //log any error
}
}


//Async function to mark item as complete
async function markComplete(){
const itemText = this.parentNode.childNodes[1].innerText
try{
Expand All @@ -52,6 +64,7 @@ async function markComplete(){
}
}

//Async function to mark item as incomplete
async function markUnComplete(){
const itemText = this.parentNode.childNodes[1].innerText
try{
Expand Down
62 changes: 43 additions & 19 deletions server.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,46 @@

//Import the Express framework to create the server
const express = require('express')

//create an instance of the Express app
const app = express()

//Import MongoClient from the MongoDB library to connect to the database
const MongoClient = require('mongodb').MongoClient

//Define the port number, using either the environment or defaulting to 2121
const PORT = 2121
require('dotenv').config()


//Declare variables for the database connection
let db,
dbConnectionStr = process.env.DB_STRING,
dbName = 'todo'
dbConnectionStr = process.env.DB_STRING,//Get the connection string from the .env file
dbName = 'todo'//Name of the database

//Connect to MongoDB using the connection string
MongoClient.connect(dbConnectionStr, { useUnifiedTopology: true })
.then(client => {
console.log(`Connected to ${dbName} Database`)
db = client.db(dbName)
console.log(`Connected to ${dbName} Database`)//Log successful connection
db = client.db(dbName)//Store the database connection in the db variable
})


//Set tthe view engine to EJS so we can use templating in our HTML
app.set('view engine', 'ejs')

//Make the "public" folder accessible to the browser (for CSS, JS, images, etc.)
app.use(express.static('public'))

//Middleware to parse form data(from POST request)
app.use(express.urlencoded({ extended: true }))
app.use(express.json())

//Middleware to parse JSON data
app.use(express.json())

//GET route for the homepage
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()//Get all to-do items from the 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 the index page and pass the data to it
// db.collection('todos').find().toArray()
// .then(data => {
// db.collection('todos').countDocuments({completed: false})
Expand All @@ -35,36 +51,40 @@ app.get('/',async (request, response)=>{
// .catch(error => console.error(error))
})


//POST route 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 a new item into the database
.then(result => {
console.log('Todo Added')
response.redirect('/')
})
.catch(error => console.error(error))
})

//PUT route to mark an intem as complete
app.put('/markComplete', (request, response) => {
db.collection('todos').updateOne({thing: request.body.itemFromJS},{
$set: {
completed: true
completed: true //set the "completed" field to true
}
},{
sort: {_id: -1},
upsert: false
sort: {_id: -1},//sort by newest if there are duplicates
upsert: false //Do not insert a new document if none is found
})
.then(result => {
console.log('Marked Complete')
response.json('Marked Complete')
console.log('Marked Complete') // Log a success message
response.json('Marked Complete') //Send a response to the client
})
.catch(error => console.error(error))
.catch(error => console.error(error)) //Handle any errors

})

//PUT route to mark an item as incomplete
app.put('/markUnComplete', (request, response) => {
db.collection('todos').updateOne({thing: request.body.itemFromJS},{
$set: {
completed: false
completed: false //Set the "completed" field to false
}
},{
sort: {_id: -1},
Expand All @@ -78,8 +98,10 @@ app.put('/markUnComplete', (request, response) => {

})

//DELETE route 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 that matches the name
.then(result => {
console.log('Todo Deleted')
response.json('Todo Deleted')
Expand All @@ -88,6 +110,8 @@ app.delete('/deleteItem', (request, response) => {

})

//Start the server and listen on the defined port

app.listen(process.env.PORT || PORT, ()=>{
console.log(`Server running on port ${PORT}`)
})
1 change: 1 addition & 0 deletions todo-list-express
Submodule todo-list-express added at 8247ad
35 changes: 21 additions & 14 deletions views/index.ejs
Original file line number Diff line number Diff line change
@@ -1,47 +1,54 @@
<!-- define the HTML document structure -->
<!DOCTYPE html>
<html lang="en">

<head>
<!-- Metadata and browser compatibility-->
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- Title shown in browser tab -->
<title>Document</title>

<!-- Link to the CSS stylesheet -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
<link rel="stylesheet" href="css/style.css">
</head>

<body>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- Main heading of the page-->
<h1>Todo List: </h1>

<!-- unordered list that will display all todo items -->
<ul class="todoItems">
<!-- loop through each item in the items array passed from server -->
<% for(let i=0; i < items.length; i++) {%>
<li class="item">
<!-- check if the current item is completed -->
<% if(items[i].completed === true) {%>
<!-- if completed, add 'completed class to style to style it different' -->
<span class='completed'><%= items[i].thing %></span>
<% }else{ %>
<!-- if not completed, just show the item -->
<span><%= items[i].thing %></span>
<% } %>
<!-- trash icon to trigger delete -->
<span class='fa fa-trash'></span>
</li>
<% } %>
</ul>

<!-- show how many items are left to complete -->
<h2>Left to do: <%= left %></h2>

<!-- section to add a new todo item -->
<h2>Add A Todo:</h2>

<!-- form that sends a POST request to /addTodo -->
<form action="/addTodo" method="POST">
<input type="text" placeholder="Thing To Do" name="todoItem">
<input type="submit">
<input type="submit">
</form>


<!-- Link to the Javascript file that handles user interaction -->
<script src='js/main.js'></script>
</body>
</html>