Skip to content

Commit

Permalink
Added variants, tweaked styling. Started building cart page
Browse files Browse the repository at this point in the history
  • Loading branch information
craigtweedy committed Feb 10, 2021
1 parent c76584b commit 144f48a
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 32 deletions.
2 changes: 1 addition & 1 deletion public/assets/chopchop.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -47,4 +50,19 @@ const App: React.FC = () => (
</IonApp>
);

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;
44 changes: 40 additions & 4 deletions src/components/product/listing/ProductListing.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -8,13 +9,43 @@ interface ProductListingProps {
}

const ProductListing: React.FC<ProductListingProps> = ({ 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 (
<IonGrid className="product-listing">
<IonRow>
<IonCol className="ion-hide-md-down" size="5">
<ProductDescription product={product} />
<IonCol className="ion-hide-md-down">
<ProductDescription
product={product}
variants={variants}
defaultVariants={initialVariants}
onVariantChange={handleVariantChange}
/>
</IonCol>
<IonCol>
<IonGrid>
Expand Down Expand Up @@ -55,7 +86,12 @@ const ProductListing: React.FC<ProductListingProps> = ({ product }) => {
</IonRow>
<IonRow className="ion-hide-md-up">
<IonCol>
<ProductDescription product={product} />
<ProductDescription
product={product}
variants={variants}
defaultVariants={initialVariants}
onVariantChange={handleVariantChange}
/>
</IonCol>
</IonRow>
<IonRow>
Expand Down
56 changes: 49 additions & 7 deletions src/components/product/listing/description/ProductDescription.tsx
Original file line number Diff line number Diff line change
@@ -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<ProductDescriptionProps> = ({ product }) => {
const ProductDescription: React.FC<ProductDescriptionProps> = ({
product,
variants = [],
defaultVariants = {},
onVariantChange,
}) => {
return (
<div>
<div className="product-description">
<h1>{product["name"]}</h1>
<IonGrid className="ion-no-padding">
<IonRow>
<IonCol>
<span>{product["price"]["formatted_with_symbol"]}</span>
<span>Variants</span>
</IonCol>
<IonCol>{product["price"]["formatted_with_symbol"]}</IonCol>
<IonCol className="ion-text-end">Add to bag</IonCol>
</IonRow>
{variants.map(({ options, ...variant }) => {
return (
<IonRow key={variant["id"]}>
<IonCol>
<IonItem lines="none" className="variant ion-no-padding">
<IonLabel>{variant["name"]}</IonLabel>
<IonSelect
id={variant["id"]}
onIonChange={onVariantChange}
defaultValue={defaultVariants[variant["id"]]}
>
{options.map((option) => {
return (
<IonSelectOption
key={option["id"]}
value={option["id"]}
>
{option["name"]}
</IonSelectOption>
);
})}
</IonSelect>
</IonItem>
</IonCol>
</IonRow>
);
})}
<IonRow>
<IonCol>
<div
Expand Down
5 changes: 4 additions & 1 deletion src/components/product/product-card/ProductCard.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
.product-card {
margin: 0 15px;
}
.product-card img {
height: 300px;
height: 450px;
width: 100%;
object-fit: cover;
border-radius: 0.5rem;
Expand Down
40 changes: 40 additions & 0 deletions src/pages/cart/Cart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {
IonCol,
IonContent,
IonFooter,
IonGrid,
IonHeader,
IonIcon,
IonImg,
IonPage,
IonRow,
IonSplitPane,
IonTitle,
IonToolbar,
} from "@ionic/react";
import Commerce from "@chec/commerce.js";
import { useEffect, useState } from "react";

const CartModal: React.FC = () => {
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 (
<IonPage>
<IonContent fullscreen>Cart</IonContent>
<IonFooter>
<IonToolbar>
<IonTitle>Powered By Commerce.JS</IonTitle>
</IonToolbar>
</IonFooter>
</IonPage>
);
};

export default CartModal;
3 changes: 3 additions & 0 deletions src/pages/home/Home.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.ion-page ion-grid.home {
padding-top: 44px;
}
26 changes: 9 additions & 17 deletions src/pages/home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,16 @@ const Home: React.FC = () => {

return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>
<img src="assets/chopchop.svg" height="28px" width="144px" />
</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">
<img src="assets/chopchop.svg" height="28px" />
</IonTitle>
</IonToolbar>
</IonHeader>
<IonGrid>
<IonGrid className="home">
<IonRow>
<IonCol className="ion-hide-md-up">
<img src="assets/chopchop.svg" />
</IonCol>
</IonRow>
<IonRow>
<IonCol className="ion-hide-md-down" size="5">
&nbsp;
<IonCol className="ion-hide-md-down">
<img src="assets/chopchop.svg" />
</IonCol>
<IonCol>
<IonGrid>
Expand All @@ -61,6 +52,7 @@ const Home: React.FC = () => {
sizeLg="6"
sizeXl="6"
key={product.id}
className="ion-no-padding"
>
<ProductCard product={product} />
</IonCol>
Expand Down
22 changes: 20 additions & 2 deletions src/pages/product/Product.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
IonBackButton,
IonButton,
IonButtons,
IonCol,
IonContent,
Expand All @@ -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<{
Expand All @@ -27,6 +29,7 @@ const ProductDetail: React.FC<ProductDetailPageProps> = ({
location: { state },
}) => {
const [product, setProduct] = useState((state && state["product"]) || null);
const pageRef = useRef<HTMLElement>(null);

useEffect(() => {
const commerce = new Commerce(process.env.REACT_APP_CHEC_PUBLIC_KEY);
Expand All @@ -36,8 +39,14 @@ const ProductDetail: React.FC<ProductDetailPageProps> = ({
.catch((e) => console.error(e));
}, [match.params.id]);

useEffect(() => {
if (state && state["product"]) {
setProduct(state["product"]);
}
}, [state]);

return (
<IonPage>
<IonPage ref={pageRef}>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
Expand All @@ -46,6 +55,15 @@ const ProductDetail: React.FC<ProductDetailPageProps> = ({
<IonTitle>
<img src="assets/chopchop.svg" height="28px" width="144px" />
</IonTitle>
<IonButtons slot="end">
<IonButton
onClick={(e) => {
addModal("cart-modal", pageRef);
}}
>
Cart
</IonButton>
</IonButtons>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
Expand Down
12 changes: 12 additions & 0 deletions src/utils/modal.tsx
Original file line number Diff line number Diff line change
@@ -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();
}
};

0 comments on commit 144f48a

Please sign in to comment.