From 144f48a3db3f223bf50b65186328a9d19d6e1d27 Mon Sep 17 00:00:00 2001 From: Craig Tweedy Date: Wed, 10 Feb 2021 23:39:48 +0000 Subject: [PATCH] Added variants, tweaked styling. Started building cart page --- public/assets/chopchop.svg | 2 +- src/App.tsx | 18 ++++++ .../product/listing/ProductListing.tsx | 44 +++++++++++++-- .../description/ProductDescription.tsx | 56 ++++++++++++++++--- .../product/product-card/ProductCard.css | 5 +- src/pages/cart/Cart.tsx | 40 +++++++++++++ src/pages/home/Home.css | 3 + src/pages/home/Home.tsx | 26 +++------ src/pages/product/Product.tsx | 22 +++++++- src/utils/modal.tsx | 12 ++++ 10 files changed, 196 insertions(+), 32 deletions(-) create mode 100644 src/pages/cart/Cart.tsx create mode 100644 src/utils/modal.tsx diff --git a/public/assets/chopchop.svg b/public/assets/chopchop.svg index cd28bed..fde8a4a 100644 --- a/public/assets/chopchop.svg +++ b/public/assets/chopchop.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 78045af..29526fd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -24,6 +24,9 @@ import "@ionic/react/css/display.css"; /* Theme variables */ import "./theme/variables.css"; import ProductDetail from "./pages/product/Product"; +import { createElement } from "react"; +import { render } from "react-dom"; +import CartModal from "./pages/cart/Cart"; if (isPlatform("desktop")) { setupConfig({ @@ -47,4 +50,19 @@ const App: React.FC = () => ( ); +class CartModalComponent extends HTMLElement { + createModal() { + return createElement(CartModal); + } + + connectedCallback() { + const mountPoint = document.createElement("span"); + this.appendChild(mountPoint); + + render(this.createModal(), mountPoint); + } +} + +window.customElements.define("cart-modal", CartModalComponent); + export default App; diff --git a/src/components/product/listing/ProductListing.tsx b/src/components/product/listing/ProductListing.tsx index 9771ebc..eaf2d82 100644 --- a/src/components/product/listing/ProductListing.tsx +++ b/src/components/product/listing/ProductListing.tsx @@ -1,4 +1,5 @@ import { IonCard, IonCol, IonGrid, IonRow } from "@ionic/react"; +import { useMemo, useState } from "react"; import ProductCard from "../product-card/ProductCard"; import ProductDescription from "./description/ProductDescription"; import "./ProductListing.css"; @@ -8,13 +9,43 @@ interface ProductListingProps { } const ProductListing: React.FC = ({ product }) => { - const { variants, assets = [], meta = {}, related_products = [] } = product; + const { + variants = [], + assets = [], + meta = {}, + related_products = [], + } = product; const images = assets.filter(({ is_image }) => is_image); + + const initialVariants = useMemo( + () => + variants.reduce((all, { id, options }) => { + const [firstOption] = options; + + return { ...all, [id]: firstOption.id }; + }, {}), + [product.permalink] + ); + + const [selectedVariants, setSelectedVariants] = useState(initialVariants); + + const handleVariantChange = ({ target: { id, value } }) => { + setSelectedVariants({ + ...selectedVariants, + [id]: value, + }); + }; + return ( - - + + @@ -55,7 +86,12 @@ const ProductListing: React.FC = ({ product }) => { - + diff --git a/src/components/product/listing/description/ProductDescription.tsx b/src/components/product/listing/description/ProductDescription.tsx index e0c3d71..e813e94 100644 --- a/src/components/product/listing/description/ProductDescription.tsx +++ b/src/components/product/listing/description/ProductDescription.tsx @@ -1,21 +1,63 @@ -import { IonCol, IonGrid, IonRow } from "@ionic/react"; +import { + IonCol, + IonGrid, + IonItem, + IonLabel, + IonRow, + IonSelect, + IonSelectOption, +} from "@ionic/react"; + +import "./ProductDescription.css"; interface ProductDescriptionProps { product: any; + variants: any[]; + defaultVariants: object; + onVariantChange: (any) => void; } -const ProductDescription: React.FC = ({ product }) => { +const ProductDescription: React.FC = ({ + product, + variants = [], + defaultVariants = {}, + onVariantChange, +}) => { return ( -
+

{product["name"]}

- - {product["price"]["formatted_with_symbol"]} - Variants - + {product["price"]["formatted_with_symbol"]} Add to bag + {variants.map(({ options, ...variant }) => { + return ( + + + + {variant["name"]} + + {options.map((option) => { + return ( + + {option["name"]} + + ); + })} + + + + + ); + })}
{ + const [cart, setCart] = useState([]); + + useEffect(() => { + const commerce = new Commerce(process.env.REACT_APP_CHEC_PUBLIC_KEY); + commerce.cart.retrieve().then((cart) => setCart(cart)); + }, []); + + console.log(cart); + + return ( + + Cart + + + Powered By Commerce.JS + + + + ); +}; + +export default CartModal; diff --git a/src/pages/home/Home.css b/src/pages/home/Home.css index e69de29..f1bf9fe 100644 --- a/src/pages/home/Home.css +++ b/src/pages/home/Home.css @@ -0,0 +1,3 @@ +.ion-page ion-grid.home { + padding-top: 44px; +} diff --git a/src/pages/home/Home.tsx b/src/pages/home/Home.tsx index 0a381d8..2ac3d95 100644 --- a/src/pages/home/Home.tsx +++ b/src/pages/home/Home.tsx @@ -29,25 +29,16 @@ const Home: React.FC = () => { return ( - - - - - - - - - - - - - - - + + + + + + - -   + + @@ -61,6 +52,7 @@ const Home: React.FC = () => { sizeLg="6" sizeXl="6" key={product.id} + className="ion-no-padding" > diff --git a/src/pages/product/Product.tsx b/src/pages/product/Product.tsx index ecaa8d4..b7c5f2c 100644 --- a/src/pages/product/Product.tsx +++ b/src/pages/product/Product.tsx @@ -1,5 +1,6 @@ import { IonBackButton, + IonButton, IonButtons, IonCol, IonContent, @@ -13,9 +14,10 @@ import { } from "@ionic/react"; import "./Product.css"; import Commerce from "@chec/commerce.js"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { RouteComponentProps } from "react-router"; import ProductListing from "../../components/product/listing/ProductListing"; +import { addModal } from "../../utils/modal"; interface ProductDetailPageProps extends RouteComponentProps<{ @@ -27,6 +29,7 @@ const ProductDetail: React.FC = ({ location: { state }, }) => { const [product, setProduct] = useState((state && state["product"]) || null); + const pageRef = useRef(null); useEffect(() => { const commerce = new Commerce(process.env.REACT_APP_CHEC_PUBLIC_KEY); @@ -36,8 +39,14 @@ const ProductDetail: React.FC = ({ .catch((e) => console.error(e)); }, [match.params.id]); + useEffect(() => { + if (state && state["product"]) { + setProduct(state["product"]); + } + }, [state]); + return ( - + @@ -46,6 +55,15 @@ const ProductDetail: React.FC = ({ + + { + addModal("cart-modal", pageRef); + }} + > + Cart + + diff --git a/src/utils/modal.tsx b/src/utils/modal.tsx new file mode 100644 index 0000000..2b29557 --- /dev/null +++ b/src/utils/modal.tsx @@ -0,0 +1,12 @@ +import { modalController } from "@ionic/core"; + +export const addModal = async (component, presentingElement) => { + if (presentingElement.current != null) { + const modal = await modalController.create({ + component, + swipeToClose: true, + presentingElement: presentingElement.current, + }); + await modal.present(); + } +};