summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Vink <mike1994vink@gmail.com>2021-06-04 17:08:53 +0200
committerMike Vink <mike1994vink@gmail.com>2021-06-04 17:08:53 +0200
commit2f9cd43f44f8cdd4bdb16bb95a507b5f45c8e44d (patch)
tree34fd744bf9475fdc977fc697331854db61d0f15c
parent0114244663fbb8cd45a7cc4489bda469b31f0698 (diff)
server and response api
-rw-r--r--client/index.html166
-rw-r--r--client/shoppingbasket.html46
-rw-r--r--client/src/functions.js20
-rw-r--r--client/src/index.js285
-rw-r--r--client/src/shoppingbasket.js82
-rw-r--r--client/src/templateImplementations.js96
-rw-r--r--client/src/utils.js48
-rw-r--r--client/style/main.css28
-rw-r--r--client/style/shoppingbasket.css2
-rw-r--r--main.js19
10 files changed, 538 insertions, 254 deletions
diff --git a/client/index.html b/client/index.html
index 0ca5740..e918f39 100644
--- a/client/index.html
+++ b/client/index.html
@@ -47,11 +47,14 @@
<main>
<div id="center-articles">
+
+ </div>
+ </main>
+
+ <template id="parkarticle">
<article>
- <div class="parkname">De Efteling</div>
- <div class="parkdescription">
- The Netherlands's most famous theme park. Located in Kaatsheuvel.
- </div>
+ <div class="parkname"></div>
+ <div class="parkdescription"></div>
<div class="order">
<div class="prices">
<div class="adultprice">Adults: <span class="sign">&euro;</span><span class="price">32,-</span></div>
@@ -71,160 +74,9 @@
</button>
</div>
</article>
+ </template>
- <article>
- <div class="parkname">Madurodam</div>
- <div class="parkdescription">
- The Netherlands smallest theme park.
- </div>
- <div class="order">
- <div class="prices">
- <div class="adultprice">Adults: <span class="sign">&euro;</span><span class="price">25,-</span></div>
- <div class="kidsprice">Kids: <span class="sign">&euro;</span><span class="price">20,-</span></div>
- <div class="discountrequirement">
- <em>Family ticket:</em>
- Buy <span class="adults">1</span> adult tickets & <span class="child">2</span> kid tickets for a <span class="percentage">25</span>% discount!
- </div>
- </div>
- <label>Adults: </label><input placeholder="adults" type="number" class="numberofadults" />
- <label>Kids: </label><input placeholder="kids" type="number" class="numberofkids" />
- <div class="total"><span class="sign">&euro;</span><span class="price">0,-</span></div>
- <button class="orderbutton">
- <span class="front">
- Add to shopping basket
- </span>
- </button>
- </div>
- </article>
-
- <article>
- <div class="parkname">Toverland</div>
- <div class="parkdescription">
- Experience magic and wonder.
- </div>
- <div class="order">
- <div class="prices">
- <div class="adultprice">Adults: <span class="sign">&euro;</span><span class="price">30,-</span></div>
- <div class="kidsprice">Kids: <span class="sign">&euro;</span><span class="price">30,-</span></div>
- <div class="discountrequirement">
- <em>Family ticket:</em>
- Buy <span class="adults">2</span> adult tickets & <span class="child">2</span> kid tickets for a <span class="percentage">33</span>% discount!
- </div>
- </div>
- <label>Adults: </label><input placeholder="adults" type="number" class="numberofadults" />
- <label>Kids: </label><input placeholder="kids" type="number" class="numberofkids" />
- <div class="total"><span class="sign">&euro;</span><span class="price">0,-</span></div>
- <button class="orderbutton">
- <span class="front">
- Add to shopping basket
- </span>
- </button>
- </div>
- </article>
-
- <article>
- <div class="parkname">Walibi Holland</div>
- <div class="parkdescription">
- Need an Adrenaline Rush?
- </div>
- <div class="order">
- <div class="prices">
- <div class="adultprice">Adults: <span class="sign">&euro;</span><span class="price">37,-</span></div>
- <div class="kidsprice">Kids: <span class="sign">&euro;</span><span class="price">37,-</span></div>
- <div class="discountrequirement">
- <em>Family ticket:</em>
- Buy <span class="adults">4</span> adult tickets & <span class="child">0</span> kid tickets for a <span class="percentage">10</span>% discount!
- </div>
- </div>
- <label>Adults: </label><input placeholder="adults" type="number" class="numberofadults" />
- <label>Kids: </label><input placeholder="kids" type="number" class="numberofkids" />
- <div class="total"><span class="sign">&euro;</span><span class="price">0,-</span></div>
- <button class="orderbutton">
- <span class="front">
- Add to shopping basket
- </span>
- </button>
- </div>
- </article>
-
- <article>
- <div class="parkname">Duinrell</div>
- <div class="parkdescription">
- From the Kikkerbaan to the Tikibad.
- </div>
- <div class="order">
- <div class="prices">
- <div class="adultprice">Adults: <span class="sign">&euro;</span><span class="price">22,-</span></div>
- <div class="kidsprice">Kids: <span class="sign">&euro;</span><span class="price">19,-</span></div>
- <div class="discountrequirement">
- <em>Family ticket:</em>
- Buy <span class="adults">1</span> adult tickets & <span class="child">3</span> kid tickets for a <span class="percentage">20</span>% discount!
- </div>
- </div>
- <label>Adults: </label><input placeholder="adults" type="number" class="numberofadults" />
- <label>Kids: </label><input placeholder="kids" type="number" class="numberofkids" />
- <div class="total"><span class="sign">&euro;</span><span class="price">0,-</span></div>
- <button class="orderbutton">
- <span class="front">
- Add to shopping basket
- </span>
- </button>
- </div>
- </article>
-
- <article>
- <div class="parkname">Slagharen</div>
- <div class="parkdescription">
- Fun for the whole family in a true western style.
- </div>
- <div class="order">
- <div class="prices">
- <div class="adultprice">Adults: <span class="sign">&euro;</span><span class="price">28,-</span></div>
- <div class="kidsprice">Kids: <span class="sign">&euro;</span><span class="price">20,-</span></div>
- <div class="discountrequirement">
- <em>Family ticket:</em>
- Buy <span class="adults">2</span> adult tickets & <span class="child">2</span> kid tickets for a <span class="percentage">50</span>% discount!
- </div>
- </div>
- <label>Adults: </label><input placeholder="adults" type="number" class="numberofadults" />
- <label>Kids: </label><input placeholder="kids" type="number" class="numberofkids" />
- <div class="total"><span class="sign">&euro;</span><span class="price">0,-</span></div>
- <button class="orderbutton">
- <span class="front">
- Add to shopping basket
- </span>
- </button>
- </div>
- </article>
-
- <article>
- <div class="parkname">Drievliet</div>
- <div class="parkdescription">
- Come and experience our wonderful attractions.
- </div>
- <div class="order">
- <div class="prices">
- <div class="adultprice">Adults: <span class="sign">&euro;</span><span class="price">26,-</span></div>
- <div class="kidsprice">Kids: <span class="sign">&euro;</span><span class="price">24,-</span></div>
- <div class="discountrequirement">
- <em>Family ticket:</em>
- Buy <span class="adults">1</span> adult tickets & <span class="child">2</span> kid tickets for a <span class="percentage">25</span>% discount!
- </div>
- </div>
- <label>Adults: </label><input placeholder="adults" type="number" class="numberofadults" />
- <label>Kids: </label><input placeholder="kids" type="number" class="numberofkids" />
- <div class="total"><span class="sign">&euro;</span><span class="price">0,-</span></div>
- <button class="orderbutton">
- <span class="front">
- Add to shopping basket
- </span>
- </button>
- </div>
- </article>
-
- </div>
- </main>
- <script src="src/index.js"></script>
+ <script type="module" src="src/index.js"></script>
</body>
</html>
diff --git a/client/shoppingbasket.html b/client/shoppingbasket.html
index 720c463..8464aaf 100644
--- a/client/shoppingbasket.html
+++ b/client/shoppingbasket.html
@@ -41,18 +41,52 @@
</nav>
<main>
- <button id="finalizepaymentbutton">Pay now</button>
+ <button id="finalizepaymentbutton" onclick="requestPlaceOrder()" class="orderbutton">
+ <span class="front">
+ Pay now
+ </span>
+ </button>
</main>
<template id="ticket">
<article>
- <div>Parkname</div>
- <div>Adults: </div>
- <div>Kids:</div>
- <button>Cancel order</button>
+ <div class="parkname"></div>
+ <div class="numberofadults"></div>
+ <div class="numberofkids"></div>
+ <div class="price"></div>
+ <button class="orderbutton cancel">
+ <span class="front cancel">
+ Cancel order
+ </span>
+ </button>
</article>
</template>
</body>
- <script src="src/shoppingbasket.js"></script>
+ <script type="module" src="src/shoppingbasket.js"></script>
+
+ <script>
+ async function requestPlaceOrder() {
+ var main = document.querySelector("main");
+ var orders = localStorage.getItem("shoppingBasketArray");
+ console.log(orders);
+
+ const response = await fetch("api/placeorder",
+ {
+ method: 'POST', // *GET, POST, PUT, DELETE, etc.
+ mode: 'cors', // no-cors, *cors, same-origin
+ cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
+ credentials: 'same-origin', // include, *same-origin, omit
+ headers: {
+ 'Content-Type': 'application/json'
+ // 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ redirect: 'follow', // manual, *follow, error
+ referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
+ body: orders // body data type must match "Content-Type" header
+ }
+ );
+ }
+ </script>
+
</html>
diff --git a/client/src/functions.js b/client/src/functions.js
new file mode 100644
index 0000000..7f06c3b
--- /dev/null
+++ b/client/src/functions.js
@@ -0,0 +1,20 @@
+// Dynamic article displaying
+export async function fetchAttractions() {
+
+ try {
+
+ const response = await fetch("api/attractions");
+
+ if (!response.ok) {
+ const message = `An error has occured: ${response.status}`;
+ throw new Error(message);
+ }
+
+ const attractions = 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 13d7219..018693f 100644
--- a/client/src/index.js
+++ b/client/src/index.js
@@ -1,75 +1,270 @@
+import { ParkArticle } from "./templateImplementations.js";
+import { displayNumberOfItemsInShoppingBasketWithBadge, dutchCurrencyFormat, dutchCurrencyFormatWithSign } from "./utils.js";
+import { fetchAttractions } from "./functions.js"
+
+
+
+function displayArticles(articles) {
+
+ const parkArticleFunctionality = {
+ orderButtonClick: orderButtonClicked,
+ displayTotal: displayTotal,
+ disableButton: disableButton,
+ }
+
+ for (var i = 0; i < articles.length; i++) {
+ var parkArticle = new ParkArticle(articles[i], document.querySelector("#parkarticle"));
+ parkArticle.addToNode(document.querySelector("#center-articles"), parkArticleFunctionality);
+ }
+
+}
+
+function disableButton(name, button) {
+ return function inputEventReceiver(event) {
+ const inputs = button.parentNode.querySelectorAll("input");
+ var inputTickets = 0;
+ for (let i = 0; i < inputs.length; i++) {
+ if (inputs[i].value > 0) {
+ inputTickets = inputTickets + Number.parseInt(inputs[i].value);
+ }
+ }
+
+ const shoppingBasketArray = JSON.parse(localStorage.getItem("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;
+ }
+ }
+ }
+ 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];
+ }
+ }
+
+ 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)});
+ }
+}
+
function orderButtonClicked(event) {
+
console.log("button click");
var button;
+
if (event.target.classList.contains("orderbutton")) {
button = event.target;
} else {
button = event.target.parentNode;
}
- var node = button.previousElementSibling;
- var adults;
- var kids;
- var parkName;
- while (true) {
- if (node.classList.contains("numberofkids")) {
- kids = Number(node.value);
+
+ const order = button.parentNode;
+ const parkArticle = order.parentNode;
+
+ const orderClientSideInfo = {
+ name: parkArticle.querySelector(".parkname").textContent,
+ numberOfKids: Number(order.querySelector(".numberofkids").value),
+ numberOfAdults: Number(order.querySelector(".numberofadults").value),
+ }
+
+ console.log(orderClientSideInfo);
+
+ if ((orderClientSideInfo.numberOfKids > 0 && orderClientSideInfo.numberOfAdults >= 0) || (orderClientSideInfo.numberOfAdults > 0 && orderClientSideInfo.numberOfKids >= 0)) {
+ fetchAttractions()
+ .then(checkTicketAvailability(button, orderClientSideInfo))
+ .then(saveOrderInShoppingBasket(orderClientSideInfo))
+ .then(disableButton(orderClientSideInfo.name, button))
+ .catch((error) => {console.log(error.message)})
+ }
+}
+
+class TicketsNotAvailableError extends Error {
+ constructor(message) {
+ super(message);
+ this.name = "TicketsNotAvailableError";
+ }
+}
+
+
+export function checkTicketAvailability(button, orderClientSideInfo) {
+
+ return function serverAttractionsAccepter(serverAttractionsArray) {
+ var attraction;
+ for (let i = 0; i < serverAttractionsArray.length; i++) {
+ if (serverAttractionsArray[i].name === orderClientSideInfo.name) {
+ attraction = serverAttractionsArray[i]
+ }
}
- if (node.classList.contains("numberofadults")) {
- adults = Number(node.value)
+
+ if (attraction.available < orderClientSideInfo.numberOfKids + orderClientSideInfo.numberOfAdults) {
+ throw new TicketsNotAvailableError("The tickets of the order exceed the available tickets!");
}
- if (node.classList.contains("parkname")) {
- parkName = node.innerText;
- break
+
+ return serverAttractionsArray;
+ }
+}
+
+function saveOrderInShoppingBasket(orderClientSideInfo) {
+ console.log("saving in shopping basket");
+
+ return function serverAttractionsAccepter(serverAttractionsArray) {
+ // const orderClientSideInfo = this;
+
+ var price;
+ for (let i = 0; i < serverAttractionsArray.length; i++) {
+ if (serverAttractionsArray[i].name === orderClientSideInfo.name) {
+ price = calulateTotal(
+ orderClientSideInfo.numberOfKids,
+ orderClientSideInfo.numberOfAdults,
+ serverAttractionsArray[i]
+ );
+ }
}
- if (node.previousElementSibling == null) {
- node = node.parentNode;
+
+ console.log("totalprice: " + price.total);
+ console.log("discount: " + price.discount);
+ orderClientSideInfo.price = price;
+
+ var shoppingBasketArray;
+
+ if (localStorage.getItem("shoppingBasketArray") === null) {
+ shoppingBasketArray = [];
+ shoppingBasketArray.push(orderClientSideInfo);
} else {
- node = node.previousElementSibling;
+ 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));
+ displayNumberOfItemsInShoppingBasketWithBadge();
}
+}
- if (kids > 0 || adults > 0) {
- saveOrderInShoppingBasket(parkName, adults, kids);
+function calulateTotal(numberOfKids, numberOfAdults, serverSideAttraction) {
+ console.log("Calculating total !");
+ console.log(serverSideAttraction);
+
+ const adultPrice = serverSideAttraction.adultPrice;
+ const kidsPrice = serverSideAttraction.kidsPrice;
+
+ const discountPercentage = serverSideAttraction.discount;
+ const minNumberkids = serverSideAttraction.minimumNumberOfKids;
+ const minNumberAdults = serverSideAttraction.minimumNumberOfAdults;
+
+ var totalPrice = 0;
+ if (numberOfKids > 0) {
+ totalPrice = totalPrice + numberOfKids * kidsPrice;
+ }
+ if (numberOfAdults > 0) {
+ totalPrice = totalPrice + numberOfAdults * adultPrice;
}
-};
-function saveOrderInShoppingBasket(name, adults, kids) {
- var order = {
- name: name,
- adults: adults,
- children: kids,
- };
- var orderString = JSON.stringify(order);
- localStorage.setItem(localStorage.length + 1, orderString)
- document.querySelector(".badge").innerText = localStorage.length;
+ if (numberOfKids >= minNumberkids && numberOfAdults >= minNumberAdults) {
+ var discount = totalPrice * discountPercentage / 100;
+ totalPrice = totalPrice - discount;
+ }
+
+ if (discount) {
+ return {total:totalPrice, discount: discount}
+ } else {
+ return {total: totalPrice};
+ }
}
-document.querySelector(".badge").innerText = localStorage.length;
-var buttons = document.querySelectorAll(".orderbutton");
+function displayTotal(event) {
+ var order = event.target.parentNode;
+ var total = order.querySelector(".total");
+
+ var kids = order.querySelector(".numberofkids").value;
+ var adults = order.querySelector(".numberofadults").value;
+
+ let re = /\d+/;
+ var kidsPrice = order.querySelector(".kidsprice")
+ .textContent
+ .match(re)[0];
+ var adultPrice = order.querySelector(".adultprice")
+ .textContent
+ .match(re)[0];
+
+ var discountReq = order.querySelector(".discountrequirement")
+ var minNumberkids = discountReq.querySelector(".child")
+ .textContent
+ .match(re)[0]
+ var minNumberadults = discountReq.querySelector(".adults")
+ .textContent
+ .match(re)[0]
+ var discountPercentage = discountReq.querySelector(".percentage")
+ .textContent
+ .match(re)[0];
+ // console.log(discountPercentage);
+
+ var value = 0;
+ if (kids > 0) {
+ value = value + Number.parseInt(kids) * Number.parseFloat(kidsPrice);
+ }
+ if (adults > 0) {
+ value = value + Number.parseInt(adults) * Number.parseFloat(adultPrice);
+ }
+ var discount;
+ if (Number.parseInt(kids) >= Number.parseInt(minNumberkids) && Number.parseInt(adults) >= Number.parseInt(minNumberadults)) {
+ discount = value * Number.parseFloat(discountPercentage) / 100
+ value = value - discount;
+ }
+ // console.log(value);
-for (var i = 0; i < buttons.length; i++) {
- console.log(buttons[i]);
- buttons[i].addEventListener("click", orderButtonClicked);
+ var priceString = dutchCurrencyFormat(value);
+ if (!(discount === undefined)) {
+ priceString = priceString + " discount: " + dutchCurrencyFormatWithSign(discount);
+ }
+ total.querySelector(".price").textContent = priceString;
}
-// When the user scrolls the page, execute myFunction
-window.onscroll = function() {myFunction()};
+function setStickyNavBar() {
+ // Get the header
+ var header = document.getElementById("sticky-header");
-// Get the header
-var header = document.getElementById("sticky-header");
+ // Get the offset position of the navbar
+ var sticky = header.offsetTop;
-// Get the offset position of the navbar
-var sticky = header.offsetTop;
+ // Add the sticky class to the header when you reach its scroll position. Remove "sticky" when you leave the scroll position
+ function makeHeaderStickyWhenScrolling() {
+
+ if (window.pageYOffset > sticky) {
+ header.classList.add("sticky");
+ } else {
+ header.classList.remove("sticky");
+ }
+ }
+ // Sticky navigation bar stuff
+ //
+ // When the user scrolls the page, execute myFunction
+ window.onscroll = function() {makeHeaderStickyWhenScrolling()};
-// Add the sticky class to the header when you reach its scroll position. Remove "sticky" when you leave the scroll position
-function myFunction() {
- if (window.pageYOffset > sticky) {
- header.classList.add("sticky");
- } else {
- header.classList.remove("sticky");
- }
}
+displayNumberOfItemsInShoppingBasketWithBadge();
+setStickyNavBar();
+fetchAttractions()
+ .then(displayArticles);
diff --git a/client/src/shoppingbasket.js b/client/src/shoppingbasket.js
index c23c02c..7355a99 100644
--- a/client/src/shoppingbasket.js
+++ b/client/src/shoppingbasket.js
@@ -1,70 +1,62 @@
-document.querySelector(".badge").innerText = localStorage.length;
+import { Order } from "./templateImplementations.js"
+import { displayNumberOfItemsInShoppingBasketWithBadge, findParentWithTag, childKillerUsingTags } from "./utils.js";
+
function getOrderArray() {
- var orders = new Array;
- for (let i = 0; i < localStorage.length; i++) {
- var order = localStorage.getItem(i+1);
- order = JSON.parse(order);
- orders.push(order);
- }
- // console.log(orders);
+ var orders = JSON.parse(localStorage.getItem("shoppingBasketArray"));
return orders;
}
-class Order {
- constructor(orderJSON) {
- for (const [key, value] of Object.entries(orderJSON)) {
- this[key] = value;
- }
-
- }
-
- addToMain() {
- // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template
- var main = document.querySelector("main");
- var template = document.querySelector("#ticket");
+function displayOrders() {
+ displayNumberOfItemsInShoppingBasketWithBadge();
+ const orderFunctionality = {
+ cancel: cancelOrder,
+ };
- var clone = template.content.cloneNode(true);
- // console.log(clone);
- var lines = clone.querySelectorAll("div");
+ var orders = getOrderArray();
+ if (orders === null) return;
- for (var i = 0; i < lines.length; i++) {
- var text = lines[i].textContent;
+ var main = document.querySelector("main");
- if (text === "Parkname") {
- console.log(this.name);
- lines[i].textContent = this.name;
- }
+ for (let i = 0; i < orders.length; i++) {
+ var orderObj = new Order(orders[i], document.querySelector("#ticket"));
+ orderObj.addToNode(main, orderFunctionality);
+ }
+}
- if (text.toLowerCase().includes("adults")) {
- lines[i].textContent = text + " " + this.adults;
- }
+function cancelOrder(event) {
+ //console.log(event.target);
+ const article = findParentWithTag.bind(event.target)("article");
- if (text.toLowerCase().includes("kids")) {
- lines[i].textContent = text + " " + this.children;
- }
+ var previous = article.previousSibling;
+ var i = 0;
+ while (previous) {
+ if (previous.tagName === "ARTICLE") {
+ i = i+1;
}
-
- main.appendChild(clone);
+ previous = previous.previousSibling;
}
-}
-
-function displayOrders() {
var orders = getOrderArray();
- for (let i = 0; i < orders.length; i++) {
- orderObj = new Order(orders[i]);
- orderObj.addToMain();
- }
+ orders.splice(i, 1);
+ localStorage.setItem("shoppingBasketArray", JSON.stringify(orders));
+ var main = document.querySelector("main");
+ childKillerUsingTags(main)(main.firstChild)("article");
+ displayOrders();
}
-displayOrders();
+
+
function finalizePayment(event) {
console.log("finalizing payments");
localStorage.clear();
+
window.location.replace("orderplaced.html");
}
+
document.querySelector("#finalizepaymentbutton").addEventListener("click", finalizePayment);
+
+displayOrders();
diff --git a/client/src/templateImplementations.js b/client/src/templateImplementations.js
new file mode 100644
index 0000000..24b8c9a
--- /dev/null
+++ b/client/src/templateImplementations.js
@@ -0,0 +1,96 @@
+import { dutchCurrencyFormat, dutchCurrencyFormatWithSign } from "./utils.js"
+import { fetchAttractions } from "./functions.js"
+/**
+ * Abstract class
+ *
+ *
+ * @class TemplatedNode
+ */
+class TemplatedNode {
+ constructor(json, template) {
+ // console.log(json);
+ for (const [key, value] of Object.entries(json)) {
+ this[key] = value;
+ }
+
+ this.template = template;
+ }
+
+ addToNode(node) {
+ throw new Error("Method 'addToNode' node be implemented.");
+ }
+}
+
+
+export class Order extends TemplatedNode {
+
+ addToNode(node, orderFunctionality) {
+ // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template
+
+ var clone = this.template.content.cloneNode(true);
+ // console.log(clone);
+ clone.querySelector(".parkname").textContent = this.name;
+ clone.querySelector(".numberofkids").textContent = "Kids: " + this.numberOfKids;
+ clone.querySelector(".numberofadults").textContent = "Adults: " + this.numberOfAdults;
+
+
+ var priceString = "Total: " + dutchCurrencyFormat(this.price.total);
+ if (this.price.discount) {
+ priceString = priceString + " discount: " + dutchCurrencyFormatWithSign(this.price.discount);
+ }
+ clone.querySelector(".price").textContent = priceString;
+
+ clone.querySelector("button").addEventListener("click", orderFunctionality.cancel);
+
+ node.appendChild(clone);
+ }
+
+}
+
+export class ParkArticle extends TemplatedNode {
+
+ addToNode(node, parkArticleFunctionality) {
+ // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template
+
+ var clone = this.template.content.cloneNode(true);
+ this.clone = clone;
+ var cloneChildren = clone.querySelectorAll("div");
+
+ for (var i = 0; i < cloneChildren.length; i++) {
+ // console.log(cloneChildren[i].className);
+ var element = cloneChildren[i];
+ var className = element.className;
+ var text = element.textContent;
+ if (className === "parkname") {
+ element.textContent = this.name;
+ }
+
+ if (className === "parkdescription") {
+ element.textContent = this.description;
+ }
+
+ if (className === "adultprice") {
+ element.querySelector(".price").textContent = dutchCurrencyFormat(this.adultPrice);
+ }
+
+ if (className === "kidsprice") {
+ element.querySelector(".price").textContent = dutchCurrencyFormat(this.kidsPrice);
+ }
+
+ if (className === "discountrequirement") {
+ element.querySelector(".adults").textContent = this.minimumNumberOfAdults;
+ element.querySelector(".child").textContent = this.minimumNumberOfKids;
+ }
+ }
+
+ var button = clone.querySelector(".orderbutton");
+ parkArticleFunctionality.disableButton(this.name, button)(null);
+
+ var inputElements = clone.querySelectorAll("input");
+ for (let i = 0; i < inputElements.length; i++) {
+ inputElements[i].addEventListener("input", parkArticleFunctionality.displayTotal);
+ inputElements[i].addEventListener("input", parkArticleFunctionality.disableButton(this.name, button));
+ }
+ node.appendChild(clone);
+ }
+}
diff --git a/client/src/utils.js b/client/src/utils.js
new file mode 100644
index 0000000..03416f0
--- /dev/null
+++ b/client/src/utils.js
@@ -0,0 +1,48 @@
+export function displayNumberOfItemsInShoppingBasketWithBadge() {
+ var shoppingBasketArray = JSON.parse(localStorage.getItem("shoppingBasketArray"));
+ if (shoppingBasketArray === null) {
+ document.querySelector(".badge").innerText = 0;
+ } else {
+ document.querySelector(".badge").innerText = shoppingBasketArray.length;
+ }
+}
+
+export function dutchCurrencyFormat(number) {
+ var decimal = (number * 10) % 10
+ if (decimal === 0) return number + ",-";
+ else {
+ return (number * 10 - decimal) / 10 + "," + decimal;
+ }
+}
+
+export function dutchCurrencyFormatWithSign(number) {
+ return "\u20AC" + dutchCurrencyFormat(number);
+}
+
+
+export function findParentWithTag(tagName) {
+ if (this.tagName === tagName.toUpperCase()) {
+ return this;
+ } else {
+ return findParentWithTag.bind(this.parentNode)(tagName);
+ }
+}
+
+export function childKillerUsingTags(parent) {
+
+ return function oneOfMyChildren(child) {
+
+ return function killChildrenWithTag(tag) {
+ if (child === null) {
+ return
+ } else if (child.tagName === tag.toUpperCase()) {
+ var next = child.nextSibling;
+ parent.removeChild(child);
+ return oneOfMyChildren(next)(tag);
+ } else {
+ return oneOfMyChildren(child.nextSibling)(tag);
+ }
+ }
+
+ }
+}
diff --git a/client/style/main.css b/client/style/main.css
index 7ec539a..c828d62 100644
--- a/client/style/main.css
+++ b/client/style/main.css
@@ -113,6 +113,7 @@ article {
outline-offset: 4px;
margin: 20px;
}
+
.front {
display: block;
padding: 12px 42px;
@@ -126,6 +127,16 @@ article {
cubic-bezier(.3, .7, .4, 1);
}
+.disabled {
+ display: block;
+ padding: 12px 42px;
+ border-radius: 12px;
+ font-size: 1.25rem;
+ background: grey;
+ color: white;
+ transform: translateY(-2px);
+}
+
.orderbutton:hover .front {
transform: translateY(-6px);
transition:
@@ -134,6 +145,23 @@ article {
cubic-bezier(.3, .7, .4, 1.5);
}
+
.orderbutton:active .front {
transform: translateY(-2px);
}
+
+.orderbutton:active .disabled {
+ transform: translateY(-2px);
+}
+
+.orderbutton:hover .disabled {
+ transform: translateY(-2px);
+}
+
+
+
+
+.cancel .front {
+ font-size: 1rem;
+ padding: 6px 15px;
+}
diff --git a/client/style/shoppingbasket.css b/client/style/shoppingbasket.css
index 44990ad..871a380 100644
--- a/client/style/shoppingbasket.css
+++ b/client/style/shoppingbasket.css
@@ -1,3 +1,3 @@
article {
height: auto;
-} \ No newline at end of file
+}
diff --git a/main.js b/main.js
index 6b942d7..4cc62ba 100644
--- a/main.js
+++ b/main.js
@@ -105,6 +105,8 @@ const attractions = [
},
]
+var ordersOnServer = [];
+
/**
* A route is like a method call. It has a name, some parameters and some return value.
*
@@ -126,6 +128,23 @@ app.get("/api/attractions", function (request, response) {
app.post("/api/placeorder", 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;
+ }
+ }
+ }
+
+ ordersOnServer = ordersOnServer.concat(orders);
+
+
+ console.log("orders serverside: ");
+ console.log(ordersOnServer);
/**
* Send the status code 200 back to the clients browser.