diff --git a/README.md b/README.md index 493995c1..f9ad7dc7 100644 --- a/README.md +++ b/README.md @@ -1,100 +1,48 @@ Assignment 2 - Short Stack: Basic Two-tier Web Application using HTML/CSS/JS and Node.js === -Due: September 11th, by 11:59 AM. +Adelynn Martin +Abmartin25 +Glitch: https://a2-abmartin25.glitch.me -This assignment aims to introduce you to creating a prototype two-tiered web application. -Your application will include the use of HTML, CSS, JavaScript, and Node.js functionality, with active communication between the client and the server over the life of a user session. +# Recipe Tracker -Baseline Requirements ---- +Recipe Tracker is a web application that allows users to track their recipes. Users can add new recipes, delete existing recipes, and view their recipe list. The application utilizes CSS Grid for layout and incorporates Google Fonts for improved typography. -There is a large range of application areas and possibilities that meet these baseline requirements. -Try to make your application do something useful! A todo list, storing / retrieving high scores for a very simple game... have a little fun with it. +## Tasks -Your application is required to implement the following functionalities: +### Base Assignment 1: Implementing Recipe Tracking -- a `Server` which not only serves files, but also maintains a tabular dataset with 3 or more fields related to your application -- a `Results` functionality which shows the entire dataset residing in the server's memory -- a `Form/Entry` functionality which allows a user to add or delete data items residing in the server's memory -- a `Server Logic` which, upon receiving new or modified "incoming" data, includes and uses a function that adds at least one additional derived field to this incoming data before integrating it with the existing dataset -- the `Derived field` for a new row of data must be computed based on fields already existing in the row. -For example, a `todo` dataset with `task`, `priority`, and `creation_date` may generate a new field `deadline` by looking at `creation_date` and `priority` +- Developed a server that serves files and maintains a tabular dataset with fields related to recipes. +- Implemented a Results functionality that displays the entire dataset residing in the server's memory. +- Created a Form/Entry functionality, allowing users to add or delete recipe items residing in the server's memory. +- Incorporated Server Logic that adds a derived field, "Cooking Time," to new recipe entries based on existing fields like "Ingredients" and "Directions." -Your application is required to demonstrate the use of the following concepts: +### Base Assignment 2: HTML and CSS Styling -HTML: -- One or more [HTML Forms](https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms), with any combination of form tags appropriate for the user input portion of the application -- A results page displaying all data currently available on the server. You will most likely use a `` tag for this, but `
+ + + + + + + + +
Recipe NameIngredientsDirectionsCooking Time
+ + + + + + diff --git a/public/js/main.js b/public/js/main.js index a569258f..34d112e6 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,27 +1,86 @@ // FRONT-END (CLIENT) JAVASCRIPT HERE -const submit = async function( event ) { - // stop form submission from trying to load - // a new .html page for displaying results... - // this was the original browser behavior and still - // remains to this day - event.preventDefault() - - const input = document.querySelector( '#yourname' ), - json = { yourname: input.value }, - body = JSON.stringify( json ) - - const response = await fetch( '/submit', { - method:'POST', - body - }) - - const text = await response.text() - - console.log( 'text:', text ) -} - -window.onload = function() { - const button = document.querySelector("button"); - button.onclick = submit; -} \ No newline at end of file +const addRecipe = async function (event) { + event.preventDefault(); + + const inputName = document.querySelector("#recipe_name"); + const inputIngredients = document.querySelector("#recipe_ingredients"); + const inputDirections = document.querySelector("#recipe_directions"); + + const recipeData = { + recipe_name: inputName.value, + recipe_ingredients: inputIngredients.value, + recipe_directions: inputDirections.value, + }; + + const response = await fetch("/add_recipe", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(recipeData), + }); + + const recipes = await response.json(); + + const tableRows = recipes + .map((recipe) => { + return ` + ${recipe.recipe_name} + ${recipe.recipe_ingredients} + ${recipe.recipe_directions} + ${recipe.cooking_time} minutes + `; + }) + .join(""); + + document.querySelector("#recipe_table").innerHTML = tableRows; + + inputName.value = ""; + inputIngredients.value = ""; + inputDirections.value = ""; +}; + +const deleteRecipe = async function (event) { + event.preventDefault(); + + const inputToDelete = document.querySelector("#recipe_to_delete"); + + const recipeToDelete = { + recipe_name: inputToDelete.value, + }; + + const response = await fetch("/delete_recipe", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(recipeToDelete), + }); + + const recipes = await response.json(); + + const tableRows = recipes + .map((recipe) => { + return ` + ${recipe.recipe_name} + ${recipe.recipe_ingredients} + ${recipe.recipe_directions} + ${recipe.cooking_time} minutes + `; + }) + .join(""); + + document.querySelector("#recipe_table").innerHTML = tableRows; + + inputToDelete.value = ""; +}; + + +window.onload = function () { + const addRecipeButton = document.getElementById("add_recipe"); + const deleteRecipeButton = document.getElementById("delete_recipe"); + + addRecipeButton.onclick = addRecipe; + deleteRecipeButton.onclick = deleteRecipe; +}; diff --git a/server.improved.js b/server.improved.js index 9ac27fb8..f76c2930 100644 --- a/server.improved.js +++ b/server.improved.js @@ -1,74 +1,85 @@ -const http = require( 'http' ), - fs = require( 'fs' ), - // IMPORTANT: you must run `npm install` in the directory for this assignment - // to install the mime library if you're testing this on your local machine. - // However, Glitch will install it automatically by looking in your package.json - // file. - mime = require( 'mime' ), - dir = 'public/', - port = 3000 - -const appdata = [ - { 'model': 'toyota', 'year': 1999, 'mpg': 23 }, - { 'model': 'honda', 'year': 2004, 'mpg': 30 }, - { 'model': 'ford', 'year': 1987, 'mpg': 14} -] - -const server = http.createServer( function( request,response ) { - if( request.method === 'GET' ) { - handleGet( request, response ) - }else if( request.method === 'POST' ){ - handlePost( request, response ) +const http = require("http"); +const fs = require("fs"); +const mime = require("mime"); +const dir = "public/"; +const port = process.env.PORT || 3000; + +const appdata = []; + +const server = http.createServer(function (request, response) { + if (request.method === "GET") { + handleGet(request, response); + } else if (request.method === "POST") { + handlePost(request, response); } -}) +}); -const handleGet = function( request, response ) { - const filename = dir + request.url.slice( 1 ) +const handleGet = function (request, response) { + const filename = dir + request.url.slice(1); - if( request.url === '/' ) { - sendFile( response, 'public/index.html' ) - }else{ - sendFile( response, filename ) + if (request.url === "/") { + sendFile(response, "public/index.html"); + } else { + sendFile(response, filename); } +}; + +const handlePost = function (request, response) { + let dataString = ""; + + request.on("data", function (data) { + dataString += data; + }); + + request.on("end", function () { + const requestData = JSON.parse(dataString); + + if (request.url === "/add_recipe") { + appdata.push(requestData); + } else if (request.url === "/delete_recipe") { + // Remove the recipe with the specified name + const recipeNameToDelete = requestData.recipe_name; + const indexToDelete = appdata.findIndex((recipe) => recipe.recipe_name === recipeNameToDelete); + if (indexToDelete !== -1) { + appdata.splice(indexToDelete, 1); + } + } + // Calculate cooking time based on ingredients complexity +const calculateCookingTime = (ingredients) => { + const ingredientCount = ingredients.split(',').length; + const cookingTime = ingredientCount * 5; // 5 minutes per ingredient + return cookingTime; +}; + +if (request.url === "/add_recipe") { + appdata.push(requestData); + const addedRecipe = requestData; + addedRecipe.cooking_time = calculateCookingTime(addedRecipe.recipe_ingredients); + response.writeHead(200, "OK", { "Content-Type": "application/json" }); + response.end(JSON.stringify(appdata)); } -const handlePost = function( request, response ) { - let dataString = '' - - request.on( 'data', function( data ) { - dataString += data - }) - - request.on( 'end', function() { - console.log( JSON.parse( dataString ) ) - - // ... do something with the data here!!! - - response.writeHead( 200, "OK", {'Content-Type': 'text/plain' }) - response.end('test') - }) -} - -const sendFile = function( response, filename ) { - const type = mime.getType( filename ) - - fs.readFile( filename, function( err, content ) { - - // if the error = null, then we've loaded the file successfully - if( err === null ) { - - // status code: https://httpstatuses.com - response.writeHeader( 200, { 'Content-Type': type }) - response.end( content ) - - }else{ - - // file not found, error code 404 - response.writeHeader( 404 ) - response.end( '404 Error: File Not Found' ) - - } - }) -} - -server.listen( process.env.PORT || port ) + console.log(appdata); + + response.writeHead(200, "OK", { "Content-Type": "application/json" }); + response.end(JSON.stringify(appdata)); + }); +}; + +const sendFile = function (response, filename) { + const type = mime.getType(filename); + + fs.readFile(filename, function (err, content) { + if (err === null) { + response.writeHead(200, { "Content-Type": type }); + response.end(content); + } else { + response.writeHead(404); + response.end("404 Error: File Not Found"); + } + }); +}; + +server.listen(port, () => { + console.log(`Server is running on port ${port}`); +});