From aca215cbbbedc7daa17b693fdf4ad2d436b19e5d Mon Sep 17 00:00:00 2001 From: Bel Curcio Date: Sat, 5 Jun 2021 13:16:34 -0300 Subject: [PATCH] Adding ProductOptions Component and more helpers --- .../ProductCard/ProductCard.module.css | 2 +- .../product/ProductOptions/ProductOptions.tsx | 51 +++++++++ components/product/ProductOptions/index.ts | 1 + .../product/ProductView/ProductView.tsx | 104 ++++++------------ components/product/helpers.ts | 16 ++- components/product/index.ts | 1 + 6 files changed, 105 insertions(+), 70 deletions(-) create mode 100644 components/product/ProductOptions/ProductOptions.tsx create mode 100644 components/product/ProductOptions/index.ts diff --git a/components/product/ProductCard/ProductCard.module.css b/components/product/ProductCard/ProductCard.module.css index a8b1b67bd..72539e899 100644 --- a/components/product/ProductCard/ProductCard.module.css +++ b/components/product/ProductCard/ProductCard.module.css @@ -1,7 +1,7 @@ .root { @apply relative max-h-full w-full box-border overflow-hidden bg-no-repeat bg-center bg-cover transition-transform - ease-linear cursor-pointer inline-block; + ease-linear cursor-pointer inline-block bg-accent-1; height: 100% !important; &:hover { diff --git a/components/product/ProductOptions/ProductOptions.tsx b/components/product/ProductOptions/ProductOptions.tsx new file mode 100644 index 000000000..52d05744e --- /dev/null +++ b/components/product/ProductOptions/ProductOptions.tsx @@ -0,0 +1,51 @@ +import { Swatch } from '@components/product' +import type { ProductOption } from '@commerce/types/product' +import { SelectedOptions } from '../helpers' + +interface ProductOptionsProps { + options: ProductOption[] + selectedOptions: SelectedOptions + setSelectedOptions: React.Dispatch> +} + +const ProductOptions: React.FC = ({ + options, + selectedOptions, + setSelectedOptions, +}) => { + return ( +
+ {options.map((opt) => ( +
+

+ {opt.displayName} +

+
+ {opt.values.map((v, i: number) => { + const active = selectedOptions[opt.displayName.toLowerCase()] + return ( + { + setSelectedOptions((selectedOptions) => { + return { + ...selectedOptions, + [opt.displayName.toLowerCase()]: v.label.toLowerCase(), + } + }) + }} + /> + ) + })} +
+
+ ))} +
+ ) +} + +export default ProductOptions diff --git a/components/product/ProductOptions/index.ts b/components/product/ProductOptions/index.ts new file mode 100644 index 000000000..252415ab7 --- /dev/null +++ b/components/product/ProductOptions/index.ts @@ -0,0 +1 @@ +export { default } from './ProductOptions' diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx index b34929aab..2c0e70b1e 100644 --- a/components/product/ProductView/ProductView.tsx +++ b/components/product/ProductView/ProductView.tsx @@ -5,47 +5,46 @@ import s from './ProductView.module.css' import { FC, useEffect, useState } from 'react' import type { Product } from '@commerce/types/product' import usePrice from '@framework/product/use-price' -import { getVariant, SelectedOptions } from '../helpers' -import { Swatch, ProductSlider } from '@components/product' -import { Button, Container, Text, useUI } from '@components/ui' +import { + getProductVariant, + selectDefaultOptionFromProduct, + SelectedOptions, +} from '../helpers' import { useAddItem } from '@framework/cart' -import Rating from '@components/ui/Rating' -import Collapse from '@components/ui/Collapse' -import ProductCard from '@components/product/ProductCard' -import WishlistButton from '@components/wishlist/WishlistButton' +import { WishlistButton } from '@components/wishlist' +import { ProductSlider, ProductCard, ProductOptions } from '@components/product' +import { + Button, + Container, + Text, + useUI, + Rating, + Collapse, +} from '@components/ui' -interface Props { - children?: any +interface ProductViewProps { product: Product - relatedProducts: Product[] className?: string + relatedProducts: Product[] + children?: React.ReactNode } -const ProductView: FC = ({ product, relatedProducts }) => { - // TODO: fix this missing argument issue - /* @ts-ignore */ +const ProductView: FC = ({ product, relatedProducts }) => { + const { openSidebar } = useUI() + const [loading, setLoading] = useState(false) + const [selectedOptions, setSelectedOptions] = useState({}) const addItem = useAddItem() const { price } = usePrice({ amount: product.price.value, baseAmount: product.price.retailPrice, currencyCode: product.price.currencyCode!, }) - const { openSidebar } = useUI() - const [loading, setLoading] = useState(false) - const [choices, setChoices] = useState({}) useEffect(() => { - // Selects the default option - product.variants[0].options?.forEach((v) => { - setChoices((choices) => ({ - ...choices, - [v.displayName.toLowerCase()]: v.values[0].label.toLowerCase(), - })) - }) + selectDefaultOptionFromProduct(product, setSelectedOptions) }, []) - const variant = getVariant(product, choices) - + const variant = getProductVariant(product, selectedOptions) const addToCart = async () => { setLoading(true) try { @@ -84,9 +83,7 @@ const ProductView: FC = ({ product, relatedProducts }) => {

{product.name}

- {price} - {` `} - {product.price?.currencyCode} + {`${price} ${product.price?.currencyCode}`}
@@ -116,43 +113,15 @@ const ProductView: FC = ({ product, relatedProducts }) => { )}
-
- {product.options?.map((opt) => ( -
-

- {opt.displayName} -

-
- {opt.values.map((v, i: number) => { - const active = (choices as any)[ - opt.displayName.toLowerCase() - ] - - return ( - { - setChoices((choices) => { - return { - ...choices, - [opt.displayName.toLowerCase()]: v.label.toLowerCase(), - } - }) - }} - /> - ) - })} -
-
- ))} -
- -
-
+ +
@@ -173,13 +142,12 @@ const ProductView: FC = ({ product, relatedProducts }) => { : 'Add To Cart'}
-
- + This is a limited edition production run. Printing starts when the drop ends. - + This is a limited edition production run. Printing starts when the drop ends. Reminder: Bad Boys For Life. Shipping may take 10+ days due to COVID-19. diff --git a/components/product/helpers.ts b/components/product/helpers.ts index 19ec2a171..d3fbd5ef5 100644 --- a/components/product/helpers.ts +++ b/components/product/helpers.ts @@ -1,7 +1,8 @@ import type { Product } from '@commerce/types/product' export type SelectedOptions = Record +import { Dispatch, SetStateAction } from 'react' -export function getVariant(product: Product, opts: SelectedOptions) { +export function getProductVariant(product: Product, opts: SelectedOptions) { const variant = product.variants.find((variant) => { return Object.entries(opts).every(([key, value]) => variant.options.find((option) => { @@ -16,3 +17,16 @@ export function getVariant(product: Product, opts: SelectedOptions) { }) return variant } + +export function selectDefaultOptionFromProduct( + product: Product, + updater: Dispatch> +) { + // Selects the default option + product.variants[0].options?.forEach((v) => { + updater((choices) => ({ + ...choices, + [v.displayName.toLowerCase()]: v.values[0].label.toLowerCase(), + })) + }) +} diff --git a/components/product/index.ts b/components/product/index.ts index 82ac6c548..8b70f8e2e 100644 --- a/components/product/index.ts +++ b/components/product/index.ts @@ -2,3 +2,4 @@ export { default as Swatch } from './Swatch' export { default as ProductView } from './ProductView' export { default as ProductCard } from './ProductCard' export { default as ProductSlider } from './ProductSlider' +export { default as ProductOptions } from './ProductOptions'