services/Menu.js
jsexport async function getProductById(id) {if (app.store.menu == null) {await loadData()}for (let c of app.store.menu) {for (let p of c.products) {if (p.id == id) {return p}}}return null}
components/DetailsPage.js
jsimport { getProductById } from "../services/Menu.js"export default class DetailsPage extends HTMLElement {constructor() {super()this.root = this.attachShadow({ mode: "open" })const template = document.getElementById("details-page-template",)const content = template.content.cloneNode(true)const styles = document.createElement("style")this.root.appendChild(content)this.root.appendChild(styles)async function loadCSS() {const request = await fetch("/components/DetailsPage.css",)styles.textContent = await request.text()}loadCSS()}async renderData() {if (this.dataset.productId) {this.product = await getProductById(this.dataset.productId,)this.root.querySelector("h2").textContent =this.product.namethis.root.querySelector("img",).src = `/data/images/${this.product.image}`this.root.querySelector(".description").textContent =this.product.descriptionthis.root.querySelector(".price",).textContent = `$ ${this.product.price.toFixed(2,)} ea`this.root.querySelector("button").addEventListener("click", () => {// TODO addToCart(this.product.id);app.router.go("/order")})} else {alert("Invalid Product ID")}}connectedCallback() {this.renderData()}}customElements.define("details-page", DetailsPage)
services/Order.js
jsimport { getProductById } from "./Menu.js"export function placeOrder() {alert("Your order will be ready under the number " +parseInt(Math.random() * 100),)app.store.menu = []}export async function addToCart(id) {const product = await getProductById(id)const results = app.store.cart.filter((prodInCart) => prodInCart.product.id == id,)if (results.length == 1) {app.store.cart = app.store.cart.map((p) =>p.product.id == id? { ...p, quantity: p.quantity + 1 }: p,)} else {app.store.cart = [...app.store.cart,{ product, quantity: 1 },]}}export function removeFromCart(id) {app.store.cart = app.store.cart.filter((prodInCart) => prodInCart.product.id != id,)}
app.js
Add the following code
jswindow.addEventListener("appcartchange", (event) => {const badge = document.getElementById("badge")const qty = app.store.cart.reduce((acc, item) => acc + item.quantity,0,)badge.textContent = qtybadge.hidden = qty == 0})
components/CartItem.js
jsimport { removeFromCart } from "../services/Order.js"export default class CartItem extends HTMLElement {constructor() {super()}connectedCallback() {const item = JSON.parse(this.dataset.item)this.innerHTML = "" // Clear the elementconst template = document.getElementById("cart-item-template",)const content = template.content.cloneNode(true)this.appendChild(content)this.querySelector(".qty",).textContent = `${item.quantity}x`this.querySelector(".name").textContent =item.product.namethis.querySelector(".price",).textContent = `$${item.product.price.toFixed(2)}`this.querySelector("a.delete-button").addEventListener("click",(event) => {removeFromCart(item.product.id)},)}}customElements.define("cart-item", CartItem)
components/OrderPage.js
jsexport default class OrderPage extends HTMLElement {#user = {name: "",phone: "",email: "",}constructor() {super()this.root = this.attachShadow({ mode: "open" })const styles = document.createElement("style")this.root.appendChild(styles)const section = document.createElement("section")this.root.appendChild(section)async function loadCSS() {const request = await fetch("/components/OrderPage.css",)styles.textContent = await request.text()}loadCSS()}connectedCallback() {window.addEventListener("appcartchange", () => {this.render()})this.render()}render() {let section = this.root.querySelector("section")if (app.store.cart.length == 0) {section.innerHTML = `<p class="empty">Your order is empty</p>`} else {let html = `<h2>Your Order</h2><ul></ul>`section.innerHTML = htmlconst template = document.getElementById("order-form-template",)const content = template.content.cloneNode(true)section.appendChild(content)let total = 0for (let prodInCart of app.store.cart) {const item = document.createElement("cart-item")item.dataset.item = JSON.stringify(prodInCart)this.root.querySelector("ul").appendChild(item)total +=prodInCart.quantity * prodInCart.product.price}this.root.querySelector("ul").innerHTML += `<li><p class='total'>Total</p><p class='price-total'>$${total.toFixed(2,)}</p></li>`}this.setFormBindings(this.root.querySelector("form"))}setFormBindings(form) {form.addEventListener("submit", (event) => {event.preventDefault()alert(`Thanks for your order ${this.#user.name}. ${this.#user.email? "We will be sending you the receipt over email.": "Ask at the counter for a receipt."}`,)this.#user.name = ""this.#user.email = ""this.#user.phone = ""// TODO: sent user and cart's details to the server})// Set double data bindingArray.from(form.elements).forEach((element) => {if (element.name) {element.addEventListener("change", (event) => {this.#user[element.name] = element.value})}})this.#user = new Proxy(this.#user, {set(target, property, value) {target[property] = valueform.elements[property].value = valuereturn true},})}}