summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/CartItem.js27
-rw-r--r--components/DetailsPage.js46
-rw-r--r--components/MenuPage.js54
-rw-r--r--components/OrderPage.js100
-rw-r--r--components/ProductItem.js30
5 files changed, 257 insertions, 0 deletions
diff --git a/components/CartItem.js b/components/CartItem.js
new file mode 100644
index 0000000..dd3fcef
--- /dev/null
+++ b/components/CartItem.js
@@ -0,0 +1,27 @@
+import { 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 element
+
+ const 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.name;
+ this.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);
diff --git a/components/DetailsPage.js b/components/DetailsPage.js
new file mode 100644
index 0000000..4f8eb87
--- /dev/null
+++ b/components/DetailsPage.js
@@ -0,0 +1,46 @@
+import { getProductById } from "../services/Menu.js";
+import { addToCart } from "../services/Order.js";
+
+export 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.name;
+ this.root.querySelector("img").src = `/data/images/${this.product.image}`;
+ this.root.querySelector(".description").textContent =
+ this.product.description;
+ this.root.querySelector(".price").textContent =
+ `$ ${this.product.price.toFixed(2)} ea`;
+ this.root.querySelector("button").addEventListener("click", () => {
+ addToCart(this.product.id);
+ app.router.go("/order");
+ });
+ } else {
+ alert("Invalid Product ID");
+ }
+ }
+
+ connectedCallback() {
+ this.renderData();
+ }
+}
+
+customElements.define("details-page", DetailsPage);
diff --git a/components/MenuPage.js b/components/MenuPage.js
new file mode 100644
index 0000000..cd593fc
--- /dev/null
+++ b/components/MenuPage.js
@@ -0,0 +1,54 @@
+export class MenuPage extends HTMLElement {
+ constructor() {
+ super();
+
+ this.root = this.attachShadow({ mode: "open" });
+
+ const styles = document.createElement("style");
+ this.root.appendChild(styles);
+
+ async function loadCSS() {
+ const request = await fetch("/components/MenuPage.css");
+ const css = await request.text();
+ styles.textContent = css;
+ }
+
+ loadCSS();
+ }
+
+ // when the component is attached to the DOM
+ connectedCallback() {
+ const template = document.getElementById("menu-page-template");
+ const content = template.content.cloneNode(true);
+ this.root.appendChild(content);
+
+ window.addEventListener("appmenuchange", () => {
+ this.render();
+ });
+ this.render();
+ }
+
+ render() {
+ if (app.store.menu) {
+ this.root.querySelector("#menu").innerHTML = "";
+ for (let category of app.store.menu) {
+ const liCategory = document.createElement("li");
+ liCategory.innerHTML = `
+ <h3>${category.name}</h3>
+ <ul class='category'></ul>
+ `;
+ this.root.querySelector("#menu").appendChild(liCategory);
+
+ category.products.forEach((product) => {
+ const item = document.createElement("product-item");
+ item.dataset.product = JSON.stringify(product);
+ liCategory.querySelector("ul").appendChild(item);
+ });
+ }
+ } else {
+ this.root.querySelector("#menu").innerHTML = "Loading...";
+ }
+ }
+}
+
+customElements.define("menu-page", MenuPage);
diff --git a/components/OrderPage.js b/components/OrderPage.js
new file mode 100644
index 0000000..adb6427
--- /dev/null
+++ b/components/OrderPage.js
@@ -0,0 +1,100 @@
+export class OrderPage extends HTMLElement {
+ // the hash defines a private property in js
+ #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 = html;
+
+ const template = document.getElementById("order-form-template");
+ const content = template.content.cloneNode(true);
+ section.appendChild(content);
+
+ let total = 0;
+ for (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>
+ `;
+ }
+
+ // use the shadow dom to select the form otherwise it doesnt work
+ this.setFormBindings(this.root.querySelector("form"));
+ }
+
+ setFormBindings(form) {
+ // use the submit event so the enter key and the button works
+ form.addEventListener("submit", (event) => {
+ event.preventDefault();
+ alert(`Thanks for your order ${this.#user.name}.`);
+ this.#user.name = "";
+ this.#user.email = "";
+ this.#user.phone = "";
+ // TODO: Send the data to the Server
+ });
+
+ // set double data binding
+ this.#user = new Proxy(this.#user, {
+ set(target, property, value) {
+ target[property] = value;
+ form.elements[property].value = value;
+ // needed to indicate that the modification was successful
+ return true;
+ },
+ });
+ Array.from(form.elements).forEach((element) => {
+ // the change event does only get triggered when the user changes the
+ // element via the ui
+ element.addEventListener("change", (event) => {
+ this.#user[element.name] = element.value;
+ });
+ });
+ }
+}
+
+customElements.define("order-page", OrderPage);
diff --git a/components/ProductItem.js b/components/ProductItem.js
new file mode 100644
index 0000000..ac9253b
--- /dev/null
+++ b/components/ProductItem.js
@@ -0,0 +1,30 @@
+import { addToCart } from "../services/Order.js";
+
+export default class ProductItem extends HTMLElement {
+ constructor() {
+ super();
+ }
+
+ connectedCallback() {
+ const template = document.getElementById("product-item-template");
+ const content = template.content.cloneNode(true);
+
+ this.appendChild(content);
+
+ const product = JSON.parse(this.dataset.product);
+ this.querySelector("h4").textContent = product.name;
+ this.querySelector("p.price").textContent = `$${product.price.toFixed(2)}`;
+ this.querySelector("img").src = `data/images/${product.image}`;
+ this.querySelector("a").addEventListener("click", (event) => {
+ console.log(event.target.tagName);
+ if (event.target.tagName.toLowerCase() == "button") {
+ addToCart(product.id);
+ } else {
+ app.router.go(`/product-${product.id}`);
+ }
+ event.preventDefault();
+ });
+ }
+}
+
+customElements.define("product-item", ProductItem);