diff options
| author | Mike Vink <mike1994vink@gmail.com> | 2021-06-09 16:50:28 +0200 |
|---|---|---|
| committer | Mike Vink <mike1994vink@gmail.com> | 2021-06-09 16:50:28 +0200 |
| commit | d4ba547a722e3ab72a8bd283a3d94d569518ea68 (patch) | |
| tree | 179bb356124a841c57164908fa1feee37104b947 | |
| parent | 2f9cd43f44f8cdd4bdb16bb95a507b5f45c8e44d (diff) | |
working server with attractions and orders
| -rw-r--r-- | client/shoppingbasket.html | 2 | ||||
| -rw-r--r-- | client/src/functions.js | 5 | ||||
| -rw-r--r-- | client/src/index.js | 83 | ||||
| -rw-r--r-- | client/src/shoppingbasket.js | 18 | ||||
| -rw-r--r-- | client/src/templateImplementations.js | 2 | ||||
| -rw-r--r-- | main.js | 151 | ||||
| -rw-r--r-- | mongodbFunctions.js | 160 | ||||
| -rw-r--r-- | package.json | 3 |
8 files changed, 282 insertions, 142 deletions
diff --git a/client/shoppingbasket.html b/client/shoppingbasket.html index 8464aaf..9bf9a77 100644 --- a/client/shoppingbasket.html +++ b/client/shoppingbasket.html @@ -69,7 +69,7 @@ async function requestPlaceOrder() { var main = document.querySelector("main"); var orders = localStorage.getItem("shoppingBasketArray"); - console.log(orders); + // console.log(orders); const response = await fetch("api/placeorder", { diff --git a/client/src/functions.js b/client/src/functions.js index 7f06c3b..a43dbac 100644 --- a/client/src/functions.js +++ b/client/src/functions.js @@ -1,4 +1,4 @@ -// Dynamic article displaying +// client/src/function.js export async function fetchAttractions() { try { @@ -10,9 +10,10 @@ export async function fetchAttractions() { throw new Error(message); } - const attractions = response.json(); + const attractions = await response.json(); return attractions; + } catch(error) { console.log("something went wrong when fetching attractions: ", error); } diff --git a/client/src/index.js b/client/src/index.js index 018693f..f9ee48d 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -3,9 +3,12 @@ import { displayNumberOfItemsInShoppingBasketWithBadge, dutchCurrencyFormat, dut import { fetchAttractions } from "./functions.js" +// ik struggle een beetje met de database connecten met de api... +// +// loop ineens tegen de volgende error aan: function displayArticles(articles) { - + console.log("displaying attraction articles"); const parkArticleFunctionality = { orderButtonClick: orderButtonClicked, displayTotal: displayTotal, @@ -20,7 +23,8 @@ function displayArticles(articles) { } function disableButton(name, button) { - return function inputEventReceiver(event) { + return function receiver(payload) { + console.log('checking if button should be disabled'); const inputs = button.parentNode.querySelectorAll("input"); var inputTickets = 0; for (let i = 0; i < inputs.length; i++) { @@ -30,42 +34,57 @@ function disableButton(name, button) { } const shoppingBasketArray = JSON.parse(localStorage.getItem("shoppingBasketArray")); + // console.log(shoppingBasketArray); var shoppingBasketTickets = 0; if (shoppingBasketArray) { for (let i = 0; i < shoppingBasketArray.length; i++) { if (shoppingBasketArray[i].name === name) { - shoppingBasketTickets = inputTickets + shoppingBasketArray[i].numberOfKids + shoppingBasketArray[i].numberOfAdults; + shoppingBasketTickets = shoppingBasketTickets + shoppingBasketArray[i].numberOfKids + shoppingBasketArray[i].numberOfAdults; } } } const totalTickets = inputTickets + shoppingBasketTickets; - fetchAttractions() - .then(attractions => { - var attraction; - for (let i = 0; i < attractions.length; i++) { - if (attractions[i].name === name) { - attraction = attractions[i]; + function disablerHelper(payload) { + var attraction; + if (Array.isArray(payload)) { + for (let i = 0; i < payload.length; i++) { + if (payload[i].name === name) { + attraction = payload[i]; } } + } else attraction = payload; + + var front = button.querySelector(".front"); + if (attraction.available < totalTickets || attraction.available === 0 || attraction.available === shoppingBasketTickets) { + console.log("---> disabling " + attraction.name + " button since the available tickets are " + attraction.available + " and tickets among current order is " + totalTickets); + front.classList.add("disabled"); + button.removeEventListener("click", orderButtonClicked); + } else { + console.log("---> enabling " + attraction.name + " button since the available tickets are " + attraction.available + " and tickets among current order is " + totalTickets); + front.classList.remove("disabled"); + button.addEventListener("click", orderButtonClicked); + } - var front = button.querySelector(".front"); - if (attraction.available < totalTickets || attraction.available === 0 || attraction.available === shoppingBasketTickets) { - front.classList.add("disabled"); - button.removeEventListener("click", orderButtonClicked); - } else { - front.classList.remove("disabled"); - button.addEventListener("click", orderButtonClicked); - } + } - }) - .catch(error => {console.error(error)}); + // console.log(payload) + if (payload && payload.name) { + if (payload.name) { + // console.log("prevented unnecesary fetch") + disablerHelper(payload); + } + } else { + // console.log("unnecesary fetch") + fetchAttractions() + .then(disablerHelper) + .catch(error => {console.error(error)}); + } } } function orderButtonClicked(event) { - console.log("button click"); var button; @@ -84,6 +103,7 @@ function orderButtonClicked(event) { numberOfAdults: Number(order.querySelector(".numberofadults").value), } + console.log("---> found this info on the client side:") console.log(orderClientSideInfo); if ((orderClientSideInfo.numberOfKids > 0 && orderClientSideInfo.numberOfAdults >= 0) || (orderClientSideInfo.numberOfAdults > 0 && orderClientSideInfo.numberOfKids >= 0)) { @@ -91,7 +111,7 @@ function orderButtonClicked(event) { .then(checkTicketAvailability(button, orderClientSideInfo)) .then(saveOrderInShoppingBasket(orderClientSideInfo)) .then(disableButton(orderClientSideInfo.name, button)) - .catch((error) => {console.log(error.message)}) + .catch((error) => {console.error(error)}) } } @@ -122,12 +142,13 @@ export function checkTicketAvailability(button, orderClientSideInfo) { } function saveOrderInShoppingBasket(orderClientSideInfo) { - console.log("saving in shopping basket"); + console.log("---> ---> saving info in shopping basket"); return function serverAttractionsAccepter(serverAttractionsArray) { // const orderClientSideInfo = this; var price; + var attraction; for (let i = 0; i < serverAttractionsArray.length; i++) { if (serverAttractionsArray[i].name === orderClientSideInfo.name) { price = calulateTotal( @@ -135,12 +156,13 @@ function saveOrderInShoppingBasket(orderClientSideInfo) { orderClientSideInfo.numberOfAdults, serverAttractionsArray[i] ); + attraction = serverAttractionsArray[i]; } } - console.log("totalprice: " + price.total); - console.log("discount: " + price.discount); orderClientSideInfo.price = price; + console.log("---> ---> price is saved in the shopping basket order"); + console.log(orderClientSideInfo); var shoppingBasketArray; @@ -149,18 +171,20 @@ function saveOrderInShoppingBasket(orderClientSideInfo) { shoppingBasketArray.push(orderClientSideInfo); } else { shoppingBasketArray = JSON.parse(localStorage.getItem("shoppingBasketArray")); - console.log("before adding to array: " + shoppingBasketArray); shoppingBasketArray.push(orderClientSideInfo); - console.log("after adding to array: " + shoppingBasketArray); } localStorage.setItem("shoppingBasketArray", JSON.stringify(shoppingBasketArray)); + console.log("---> ---> order is saved in array in localstorage"); + console.log(localStorage); displayNumberOfItemsInShoppingBasketWithBadge(); + return attraction; } } function calulateTotal(numberOfKids, numberOfAdults, serverSideAttraction) { - console.log("Calculating total !"); + console.log("---> calculating total of order in shoppingbasket!"); + console.log("---> ---> fetched this attraction to calculate actual prices!"); console.log(serverSideAttraction); const adultPrice = serverSideAttraction.adultPrice; @@ -191,11 +215,14 @@ function calulateTotal(numberOfKids, numberOfAdults, serverSideAttraction) { } function displayTotal(event) { + console.log("displaying a total price based on client side info"); var order = event.target.parentNode; var total = order.querySelector(".total"); var kids = order.querySelector(".numberofkids").value; var adults = order.querySelector(".numberofadults").value; + if (kids === "") kids = 0; + if (adults === "") adults = 0; let re = /\d+/; var kidsPrice = order.querySelector(".kidsprice") @@ -229,6 +256,7 @@ function displayTotal(event) { if (Number.parseInt(kids) >= Number.parseInt(minNumberkids) && Number.parseInt(adults) >= Number.parseInt(minNumberadults)) { discount = value * Number.parseFloat(discountPercentage) / 100 value = value - discount; + console.log("---> applying the discount of " + discountPercentage + "%, resulting in " + discount + " discount") } // console.log(value); @@ -241,6 +269,7 @@ function displayTotal(event) { function setStickyNavBar() { + console.log("making the navbar sticky"); // Get the header var header = document.getElementById("sticky-header"); diff --git a/client/src/shoppingbasket.js b/client/src/shoppingbasket.js index 7355a99..56e717a 100644 --- a/client/src/shoppingbasket.js +++ b/client/src/shoppingbasket.js @@ -9,12 +9,22 @@ function getOrderArray() { function displayOrders() { displayNumberOfItemsInShoppingBasketWithBadge(); + console.log("displaying orders in shopppingbasket"); const orderFunctionality = { cancel: cancelOrder, }; var orders = getOrderArray(); - if (orders === null) return; + if (orders === null || orders.length === 0) { + var button = document.querySelector("#finalizepaymentbutton"); + var front = button.querySelector(".front"); + + front.classList.add("disabled"); + button.removeEventListener("click", finalizePayment); + console.log(button); + console.log(front); + return; + } var main = document.querySelector("main"); @@ -26,6 +36,7 @@ function displayOrders() { function cancelOrder(event) { //console.log(event.target); + console.log("cancel button clicked"); const article = findParentWithTag.bind(event.target)("article"); var previous = article.previousSibling; @@ -38,10 +49,14 @@ function cancelOrder(event) { } var orders = getOrderArray(); + console.log("---> canceling order "); + console.log(orders[i]); + console.log("---> removing it from shoppingbasket") orders.splice(i, 1); localStorage.setItem("shoppingBasketArray", JSON.stringify(orders)); var main = document.querySelector("main"); + console.log("---> refreshing displayed orders") childKillerUsingTags(main)(main.firstChild)("article"); displayOrders(); } @@ -51,6 +66,7 @@ function cancelOrder(event) { function finalizePayment(event) { console.log("finalizing payments"); + localStorage.clear(); window.location.replace("orderplaced.html"); diff --git a/client/src/templateImplementations.js b/client/src/templateImplementations.js index 24b8c9a..9db0271 100644 --- a/client/src/templateImplementations.js +++ b/client/src/templateImplementations.js @@ -34,7 +34,7 @@ export class Order extends TemplatedNode { clone.querySelector(".numberofadults").textContent = "Adults: " + this.numberOfAdults; - var priceString = "Total: " + dutchCurrencyFormat(this.price.total); + var priceString = "Total: " + dutchCurrencyFormatWithSign(this.price.total); if (this.price.discount) { priceString = priceString + " discount: " + dutchCurrencyFormatWithSign(this.price.discount); } @@ -5,6 +5,14 @@ */ const express = require('express'); const app = express(); +const dbUtils = require('./mongodbFunctions.js'); + +/** + * Import the dummy attractions in the database + * + */ +dbUtils.clearMainDataBaseAndInsertDummyForTestingTheSite(); + /** * Host all files in the client folder as static resources. * That means: localhost:8080/someFileName.js corresponds to client/someFileName.js. @@ -17,97 +25,6 @@ app.use(express.static('client')); app.use(express.json()); /** - * Our code starts here. - */ -const attractions = [ - { - name: "De Efteling", - description: "The Dutch fairy tale themed park. In high demand!", - adultPrice: 32, - kidsPrice: 32, - minimumNumberOfAdults: 2, - minimumNumberOfKids: 1, - discount: 15, - available: 1, - location: { lat: 51.649718, lon: 5.043689 }, - }, - - { - name: "Madurodam", - description: "The Netherlands smallest theme park.", - adultPrice: 25, - kidsPrice: 20, - minimumNumberOfAdults: 1, - minimumNumberOfKids: 2, - discount: 25, - available: 5, - location: { lat: 52.0994779, lon: 4.299619900000039 }, - }, - - { - name: "Toverland", - description: "Experience magic and wonder.", - adultPrice: 30, - kidsPrice: 30, - minimumNumberOfAdults: 2, - minimumNumberOfKids: 2, - discount: 33, - available: 3, - location: { lat: 51.3968994, lon: 5.9825161 }, - }, - - { - name: "Walibi Holland", - description: "Need an Adrenaline Rush?", - adultPrice: 37, - kidsPrice: 37, - minimumNumberOfAdults: 4, - minimumNumberOfKids: 0, - discount: 10, - available: 20, - location: { lat: 52.438554, lon: 5.766986 }, - }, - - { - name: "Duinrell", - description: "From the Kikkerbaan to the Tikibad.", - adultPrice: 22, - kidsPrice: 19, - minimumNumberOfAdults: 1, - minimumNumberOfKids: 3, - discount: 7, - available: 20, - location: { lat: 52.147433, lon: 4.383922 }, - }, - - { - name: "Slagharen", - description: "Fun for the whole family in a true western style.", - adultPrice: 28, - kidsPrice: 20, - minimumNumberOfAdults: 2, - minimumNumberOfKids: 2, - discount: 50, - available: 2, - location: { lat: 52.6249522, lon: 6.563149500000009 }, - }, - - { - name: "Drievliet", - description: "Come and experience our wonderful attractions.", - adultPrice: 26, - kidsPrice: 24, - minimumNumberOfAdults: 1, - minimumNumberOfKids: 2, - discount: 25, - available: 0, - location: { lat: 52.052608, lon: 4.352633 }, - }, -] - -var ordersOnServer = []; - -/** * A route is like a method call. It has a name, some parameters and some return value. * * Name: /api/attractions @@ -120,36 +37,51 @@ var ordersOnServer = []; * the Express framework will call one of the methods defined here. * These are just regular functions. You can edit, expand or rewrite the code here as needed. */ -app.get("/api/attractions", function (request, response) { + +// main.js +app.get("/api/attractions", async function (request, response) { console.log("Api call received for /attractions"); - response.json(attractions) + const attractions = await dbUtils.connectToDatabaseAndDo( + (db) => {return db.collection("attractions").find().toArray()} + ); + response.json(attractions); }); -app.post("/api/placeorder", function (request, response) { +app.post("/api/placeorder", async function (request, response) { console.log("Api call received for /placeorder"); - // console.log("hello"); var orders = request.body; for (let i = 0; i < orders.length; i++) { - for (let j = 0; j < attractions.length; j++) { - if (orders[i].name === attractions[j].name) { - attractions[j].available = attractions[j].available - orders[i].numberOfAdults - orders[i].numberOfKids; + orders[i] = dbUtils.giveUnique_idField(orders[i]); + + const order = orders[i]; + await dbUtils.connectToDatabaseAndDo( + db => { + const attractions = db.collection("attractions"); + const attraction = attractions.findOne({name: order.name}); + const currentOrders = attraction.orders; + if (!currentOrders) { + attractions.updateOne( + {name: order.name}, + { + $set: {orders: [order._id]} + } + ) + } else { + attractions.updateOne( + {name: order.name}, + { + $set: {orders: currentOrders.push(order._id)} + } + ) + } } - } + ); } - ordersOnServer = ordersOnServer.concat(orders); - - - console.log("orders serverside: "); - console.log(ordersOnServer); - - /** - * Send the status code 200 back to the clients browser. - * This means OK. - */ + await dbUtils.connectToDatabaseAndDo(db => {return db.collection("orders").insertMany(orders)}); response.sendStatus(200); }); @@ -166,6 +98,7 @@ app.get("/api/admin/edit", function (request, response) { }); + /** * Make our webserver available on port 8000. * Visit localhost:8000 in any browser to see your site! diff --git a/mongodbFunctions.js b/mongodbFunctions.js new file mode 100644 index 0000000..13ef179 --- /dev/null +++ b/mongodbFunctions.js @@ -0,0 +1,160 @@ +//https://attacomsian.com/blog/nodejs-mongodb-local-connection +const MongoClient = require('mongodb').MongoClient; +const ObjectId = require('mongodb').ObjectId; +const url = 'mongodb://127.0.0.1:27017'; + +module.exports = { + connectToDatabaseAndDo: connectToDatabaseAndDo, + clearMainDataBaseAndInsertDummyForTestingTheSite: clearMainDataBaseAndInsertDummyForTestingTheSite, + giveUnique_idField: giveUnique_idField, + addOrderToAttraction: addOrderToAttraction, +} + +function connectToDatabaseAndDo(func, dbName='webcasedatabase') { + return MongoClient.connect(url, { + useNewUrlParser: true, + useUnifiedTopology: true + }).then((client) => {return client.db(dbName)}) + .then(func) + .catch(rejected => {console.log(rejected)}); +} + + +function addOrderToAttraction(db) { + const attractions = db.collection("attractions"); + const attraction = attractions.findOne({name: order.name}); + const currentOrders = attraction.orders; + if (!currentOrders) { + attractions.updateOne( + {name: order.name}, + { + $set: {orders: [order._id]} + } + ) + } else { + attractions.updateOne( + {name: order.name}, + { + $set: {orders: currentOrders.push(order._id)} + } + ) + } +} + +function giveUnique_idField(obj) { + obj._id = ObjectId(); + return obj; +} + +function giveUnique_customerField(obj) { + obj.customer = ObjectId(); + return obj; +} + + +function clearMainDataBaseAndInsertDummyForTestingTheSite() { + const attractions = [ + { + name: "De Efteling", + description: "The Dutch fairy tale themed park. In high demand!", + adultPrice: 32, + kidsPrice: 32, + minimumNumberOfAdults: 2, + minimumNumberOfKids: 1, + discount: 15, + available: 1, + location: { lat: 51.649718, lon: 5.043689 }, + }, + + { + name: "Madurodam", + description: "The Netherlands smallest theme park.", + adultPrice: 25, + kidsPrice: 20, + minimumNumberOfAdults: 1, + minimumNumberOfKids: 2, + discount: 25, + available: 5, + location: { lat: 52.0994779, lon: 4.299619900000039 }, + }, + + { + name: "Toverland", + description: "Experience magic and wonder.", + adultPrice: 30, + kidsPrice: 30, + minimumNumberOfAdults: 2, + minimumNumberOfKids: 2, + discount: 33, + available: 3, + location: { lat: 51.3968994, lon: 5.9825161 }, + }, + + { + name: "Walibi Holland", + description: "Need an Adrenaline Rush?", + adultPrice: 37, + kidsPrice: 37, + minimumNumberOfAdults: 4, + minimumNumberOfKids: 0, + discount: 10, + available: 20, + location: { lat: 52.438554, lon: 5.766986 }, + }, + + { + name: "Duinrell", + description: "From the Kikkerbaan to the Tikibad.", + adultPrice: 22, + kidsPrice: 19, + minimumNumberOfAdults: 1, + minimumNumberOfKids: 3, + discount: 7, + available: 20, + location: { lat: 52.147433, lon: 4.383922 }, + }, + + { + name: "Slagharen", + description: "Fun for the whole family in a true western style.", + adultPrice: 28, + kidsPrice: 20, + minimumNumberOfAdults: 2, + minimumNumberOfKids: 2, + discount: 50, + available: 2, + location: { lat: 52.6249522, lon: 6.563149500000009 }, + }, + + { + name: "Drievliet", + description: "Come and experience our wonderful attractions.", + adultPrice: 26, + kidsPrice: 24, + minimumNumberOfAdults: 1, + minimumNumberOfKids: 2, + discount: 25, + available: 0, + location: { lat: 52.052608, lon: 4.352633 }, + }, + ] + + connectToDatabaseAndDo((db) => { + db.dropDatabase(); + const collection = db.collection("attractions"); + const count = collection.countDocuments(); + count + .then((documents) => { + if (documents == 0) { + db.collection("attractions").insertMany(attractions, (err, res) => { + if (err) { + console.log(err); + } + console.log("clear database and inserted dummy attraction data"); + }); + } + }); + + }); +} + diff --git a/package.json b/package.json index 0997564..8bf39c5 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Het project voor de Ticketshop opdracht", "main": "main.js", "dependencies": { - "express": "^4.16.4" + "express": "^4.16.4", + "mongodb": "^3.6.9" } } |
