From 0407bf72c09e8b1b773b9efa7a473b91da149711 Mon Sep 17 00:00:00 2001 From: Byrnezy Date: Mon, 9 Sep 2024 16:49:55 -0400 Subject: [PATCH] Completed A2 --- README.md | 109 +++++---------------------------------- public/css/main.css | 35 ++++++++++++- public/index.html | 28 ++++++---- public/js/main.js | 121 ++++++++++++++++++++++++++++++++++++-------- server.js | 119 +++++++++++++++++++++++++++---------------- 5 files changed, 240 insertions(+), 172 deletions(-) diff --git a/README.md b/README.md index 4471f667..2d0da7b0 100644 --- a/README.md +++ b/README.md @@ -1,100 +1,19 @@ -Assignment 2 - Short Stack: Basic Two-tier Web Application using HTML/CSS/JS and Node.js -=== - -Due: September 9th, by 11:59 AM. - -This assignment will 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. - -Baseline Requirements ---- - -There are a 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 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` - -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 `
+ + + + + + + +
ModelYearMPGYears OldActions
- + \ No newline at end of file diff --git a/public/js/main.js b/public/js/main.js index a569258f..3ae52f91 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,27 +1,106 @@ -// 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() +let appdata = []; +const submitCar = async function(event) { + event.preventDefault(); + + const model = document.querySelector("#model").value.trim(); + const year = parseInt(document.querySelector("#year").value); + const mpg = parseInt(document.querySelector("#mpg").value); - const input = document.querySelector( '#yourname' ), - json = { yourname: input.value }, - body = JSON.stringify( json ) + console.log("Car Data:", { model, year, mpg }); + + if (!model || isNaN(year) || isNaN(mpg)) { + window.alert("Please fill in all fields correctly"); + return; + } + + const cardata = { model, year, mpg }; - const response = await fetch( '/submit', { - method:'POST', - body - }) + try { + const response = await fetch('/submit', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(cardata) + }); + const data = await response.json(); + updateCarTable(data); + } catch (error) { + console.error('Error:', error); + } +}; - const text = await response.text() +const editCar = function(index) { + const car = appdata[index]; - console.log( 'text:', text ) -} + document.querySelector("#model").value = car.model; + document.querySelector("#year").value = car.year; + document.querySelector("#mpg").value = car.mpg; +}; + +const removeCar = async function(index) { + try { + const response = await fetch(`/delete/${index}`, { + method: 'DELETE', + }); + const data = await response.json(); + updateCarTable(data); + } catch (error) { + console.error('Error:', error); + } +}; + +const submitEdit = async function(index) { + removeCar(index); + const model = document.querySelector("#model").value.trim(); + const year = parseInt(document.querySelector("#year").value); + const mpg = parseInt(document.querySelector("#mpg").value); + + console.log("Car Data:", { model, year, mpg }); + + if (!model || isNaN(year) || isNaN(mpg)) { + window.alert("Please fill in all fields correctly"); + return; + } + + const cardata = { model, year, mpg }; + try{ + const response = await fetch('/submit', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(cardata) + }); + } catch (error) { + console.error('Error:', error); + } +}; + +const updateCarTable = function(data) { + appdata = data; + const table = document.querySelector("#car-table"); + table.innerHTML = "ModelYearMPGYears OldActions"; + + data.forEach((car, index) => { + const row = ` + + ${car.model} + ${car.year} + ${car.mpg} + ${car.yearsOld} + + + + + + + `; + table.innerHTML += row; + }); +}; window.onload = function() { - const button = document.querySelector("button"); - button.onclick = submit; -} \ No newline at end of file + document.querySelector("#car-form").addEventListener("submit", submitCar); + + fetch('/data', { method: 'GET' }) + .then(response => response.json()) + .then(data => updateCarTable(data)) + .catch(error => console.error('Error:', error)); +}; diff --git a/server.js b/server.js index 9ac27fb8..0485ecdd 100644 --- a/server.js +++ b/server.js @@ -8,67 +8,96 @@ const http = require( 'http' ), dir = 'public/', port = 3000 -const appdata = [ +let 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 calculateYearsOld = function (cars) { + const currentYear = new Date().getFullYear(); + cars.forEach(car => { + car.yearsOld = 2024 - car.year; + }); +}; + +calculateYearsOld(appdata); + +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 { + sendFile(response, filename) } } - -const handlePost = function( request, response ) { +const handlePost = function (request, response) { + console.log("request URL" + request.url); let dataString = '' - - request.on( 'data', function( data ) { - dataString += data + 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') + request.on('end', function () { + console.log('Data received:', dataString); + let postResponse = JSON.parse(dataString); + console.log('Data received:', postResponse.year); + const yearsOld = 2024 - postResponse.year; + appdata.push({ + model: postResponse.model, + year: postResponse.year, + mpg: postResponse.mpg, + yearsOld: yearsOld + }); + + response.writeHead(200, "OK", { 'Content-Type': 'application/json' }); + response.end(JSON.stringify(appdata)); + }); +}; + +const handleDelete = function (request, response) { + let dataString = '' + request.on('data', function (data) { + dataString += data + }) + request.on('end', function () { + let modelToRemove = JSON.parse(dataString).modelToRemove + appdata = appdata.filter(function (car) { + return car.model !== modelToRemove; + }) + 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 the error = null, then we've loaded the file successfully - if( err === null ) { +const sendFile = function (response, filename) { + const type = mime.getType(filename) + console.log('Requested file:', filename); - // status code: https://httpstatuses.com - response.writeHeader( 200, { 'Content-Type': type }) - response.end( content ) + fs.readFile(filename, function (err, content) { - }else{ - - // file not found, error code 404 - response.writeHeader( 404 ) - response.end( '404 Error: File Not Found' ) - - } - }) + if (err === null) { + response.writeHeader(200, { 'Content-Type': type }) + response.end(content) + } else { + response.writeHeader(404) + response.end('404 Error: File Not Found') + } + }) } -server.listen( process.env.PORT || port ) +server.listen(process.env.PORT || port) \ No newline at end of file