diff --git a/README.md b/README.md index f229958..cd2f690 100644 --- a/README.md +++ b/README.md @@ -1,98 +1,13 @@ -Assignment 2 - Short Stack: Basic Two-tier Web Application using HTML/CSS/JS and Node.js -=== +Liliana Foucault +https://a2-lbfoucault.glitch.me/ -Due: September 8th, by 11:59 AM. - -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. - -Baseline Requirements ---- - -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. - -Your application is required to implement the following functionalities: - -- 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, modify, or delete (complete at least two) 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` - -Your application is required to demonstrate the use of the following concepts: - -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 `
+ +
+ + + diff --git a/public/js/scripts.js b/public/js/scripts.js index de052ea..671d79c 100644 --- a/public/js/scripts.js +++ b/public/js/scripts.js @@ -1,3 +1,105 @@ // Add some Javascript code here, to run on the front end. -console.log("Welcome to assignment 2!") \ No newline at end of file +window.onload = function () { + console.log("Welcome to assignment 2!"); + + populateTable(); + + const submit_btn = document.getElementById("submit"); + submit_btn.onclick = submit; +}; + +// POST submit entry +const submit = (e) => { + // debugger + e.preventDefault(); + + const name = document.getElementById("name").value, + grade = document.getElementById("grade").value, + food = document.getElementById("food").value, + activity = document.getElementById("activity").value; + + if (name == undefined || name === "") { + alert("Please fill in each category"); + return; + } + + const json = { name: name, grade: grade, activity: activity, food: food }, + body = JSON.stringify(json); + + fetch("/submit", { + method: "POST", + body, + }) + .then(async (response) => populateTable(await response.json())) + .catch((err) => console.error(err)); + + return false; +}; + +// GET appdata +const populateTable = () => { + fetch("/data", { + method: "GET", + }) + .then(async (response) => updateData(await response.json())) + .catch((err) => console.error(err)); +}; + +// DELETE remove row +const deleteRow = (e) => { + debugger + e.preventDefault(); + const id = e.target.id; + + fetch("/" + id, { + method: "DELETE", + }) + .then(async (response) => updateData(await response.json())) + .catch((err) => console.error(err)); +}; + +const updateData = (json) => { + const table = document.getElementById("dataTable"); + table.innerHTML = ""; + + // add the headers back + const headers = table.insertRow(0); + headers.innerHTML = ` + + Name + Grade + Class of + Fav Food + Fun Activity + Actions + + `; + + let i = 1; + for (let j of json) { + const row = table.insertRow(i); + const html = ` + ${j.name} + ${j.grade} + ${j.year} + ${j.food} + ${j.activity} + + + + `; + row.innerHTML = html; + row.id = `${i}`; + row.onclick = deleteRow; + i++; + } + +}; + + diff --git a/server.improved.js b/server.improved.js index 26673fc..93b1c1c 100644 --- a/server.improved.js +++ b/server.improved.js @@ -1,72 +1,107 @@ -const http = require( 'http' ), - fs = require( 'fs' ), - // IMPORTANT: you must run `npm install` in the directory for this assignment - // to install the mime library used in the following line of code - mime = require( 'mime' ), - dir = 'public/', - port = 3000 +const http = require("http"), + fs = require("fs"), + mime = require("mime"), + dir = "public/", + port = 3000; +// initial data 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 ) + { + name: "Liliana", + grade: "Senior", + year: 2023, + food: "chicken soup", + activity: "volleyball", + }, +]; + +// API +const server = http.createServer(function (request, response) { + if (request.method === "GET") { + handleGet(request, response); + } else if (request.method === "POST") { + handlePost(request, response); + } else if (request.method === "DELETE") { + handleDelete(request, response); } -}) - -const handleGet = function( request, response ) { - const filename = dir + request.url.slice( 1 ) - - if( request.url === '/' ) { - sendFile( response, 'public/index.html' ) - }else{ - sendFile( response, filename ) +}); + +const handleGet = function (request, response) { + const filename = dir + request.url.slice(1); + + if (request.url === "/") { + sendFile(response, "public/index.html"); + } else if (request.url === "/data") { + response.writeHeader(200, { "Content-type": "application/json" }); + response.end(JSON.stringify(appdata)); + } else if (request.url === "/submit") { + response.writeHeader(200, { "Content-type": "application/json" }); + response.end(JSON.stringify(appdata)); + } else { + sendFile(response, filename); } -} - -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() - }) -} - -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' ) - - } - }) -} +}; + +const handlePost = function (request, response) { + let dataString = ""; + + request.on("data", function (data) { + dataString += data; + }); + + request.on("end", function () { + // add entry to appdata + let newEntry = JSON.parse(dataString); + newEntry.year = getGradYear(newEntry.grade); + appdata[appdata.length] = newEntry; + + response.writeHeader(200, { "Content-type": "application/json" }); + response.end(JSON.stringify(appdata)); + }); +}; + +const handleDelete = function (request, response) { + // remove row from appdata. request url looks like /remove# + // debugger + const idx = parseInt(request.url.subtstring(7)); + appdata.splice(idx, 1); + + response.writeHeader(200, { "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 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"); + } + }); +}; + +// get derived field from given grade +const getGradYear = (grade) => { + let year = ""; + if (grade === "Freshman") { + year = 2026; + } else if (grade === "Sophomore") { + year = 2025; + } else if (grade === "Junior") { + year = 2024; + } else if (grade === "Senior") { + year = 2023; + } else { + year = ""; + } + return year; +}; -server.listen( process.env.PORT || port ) +server.listen(process.env.PORT || port); diff --git a/shrinkwrap.yaml b/shrinkwrap.yaml new file mode 100644 index 0000000..31342b3 --- /dev/null +++ b/shrinkwrap.yaml @@ -0,0 +1,38 @@ +dependencies: + cors: 2.8.5 + mime: 2.6.0 +packages: + /cors/2.8.5: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + dev: false + engines: + node: '>= 0.10' + resolution: + integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + /mime/2.6.0: + dev: false + engines: + node: '>=4.0.0' + hasBin: true + resolution: + integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + /object-assign/4.1.1: + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + /vary/1.1.2: + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== +registry: 'https://registry.npmjs.org/' +shrinkwrapMinorVersion: 9 +shrinkwrapVersion: 3 +specifiers: + cors: ^2.8.5 + mime: ^2.6.0