diff --git a/framework/commerce/types/cart.ts b/framework/commerce/types/cart.ts index e4af878de..b3d3b1e59 100644 --- a/framework/commerce/types/cart.ts +++ b/framework/commerce/types/cart.ts @@ -17,6 +17,7 @@ export type LineItem = { quantity: number discounts: Discount[] // A human-friendly unique string automatically generated from the product’s name + slug: string path: string variant: ProductVariant options?: SelectedOption[] diff --git a/framework/commerce/types/product.ts b/framework/commerce/types/product.ts index ddf51c518..e31f34df9 100644 --- a/framework/commerce/types/product.ts +++ b/framework/commerce/types/product.ts @@ -30,6 +30,7 @@ export type ProductOptionValues = { export type ProductVariant = { id: string | number + name:string, options: ProductOption[] availableForSale?: boolean } @@ -48,7 +49,8 @@ export type Product = { options: ProductOption[] facetValueIds?: string[] collectionIds?: string[] - collection?: string, + collection?: string[], + variants?: ProductVariant[] } export type ProductCard = { @@ -65,6 +67,8 @@ export type ProductCard = { collectionIds?: string[], collection?: string, isNotSell?: boolean + productVariantId?:string + productVariantName?:string } export type SearchProductsBody = { diff --git a/framework/vendure/api/operations/get-all-products.ts b/framework/vendure/api/operations/get-all-products.ts index f70b4bcf3..1ff2675bc 100644 --- a/framework/vendure/api/operations/get-all-products.ts +++ b/framework/vendure/api/operations/get-all-products.ts @@ -5,7 +5,7 @@ import { normalizeSearchResult } from '../../utils/normalize' import { getAllProductsQuery } from '../../utils/queries/get-all-products-query' import { OperationContext } from '@commerce/api/operations' -export type ProductVariables = { first?: number, facetValueIds?: string[],collectionSlug?:string } +export type ProductVariables = { first?: number, facetValueIds?: string[], collectionSlug?:string, groupByProduct?:boolean } export default function getAllProductsOperation({ commerce, @@ -31,8 +31,8 @@ export default function getAllProductsOperation({ input: { take: vars.first, facetValueIds: vars.facetValueIds, - collectionSlug: vars.collectionSlug, - groupByProduct: true, + collectionSlug : vars.collectionSlug, + groupByProduct: vars.groupByProduct??true, }, } const { data } = await config.fetch(query, { diff --git a/framework/vendure/api/operations/get-product.ts b/framework/vendure/api/operations/get-product.ts index 0aa761ab0..66f798ee1 100644 --- a/framework/vendure/api/operations/get-product.ts +++ b/framework/vendure/api/operations/get-product.ts @@ -36,6 +36,7 @@ export default function getProductOperation({ })), variants: product.variants.map((v) => ({ id: v.id, + name:v.name, options: v.options.map((o) => ({ // This __typename property is required in order for the correct // variant selection to work, see `components/product/helpers.ts` @@ -54,7 +55,8 @@ export default function getProductOperation({ values: og.options.map((o) => ({ label: o.name })), })), facetValueIds: product.facetValues.map(item=> item.id), - collectionIds: product.collections.map(item => item.id) + collectionIds: product.collections.map(item => item.id), + collection:product.collections.map(item => item.name), } as Product } diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index ae4a5d64b..cef42ff5d 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -3055,7 +3055,7 @@ export type SearchResultFragment = { __typename?: 'SearchResult' } & Pick< SearchResult, 'productId' | 'sku' | 'productName' | 'description' | 'slug' | 'sku' | 'currencyCode' | 'productAsset' | 'price' | 'priceWithTax' | 'currencyCode' - | 'collectionIds' | 'facetValueIds' | 'collectionIds' + | 'collectionIds' | 'productVariantId' | 'facetValueIds' | "productVariantName" > & { productAsset?: Maybe< { __typename?: 'SearchResultAsset' } & Pick< @@ -3381,7 +3381,7 @@ export type GetProductQuery = { __typename?: 'Query' } & { variants: Array< { __typename?: 'ProductVariant' } & Pick< ProductVariant, - 'id' | 'priceWithTax' | 'currencyCode' | 'price' + 'id' | 'priceWithTax' | 'currencyCode' | 'price' | "name" > & { options: Array< { __typename?: 'ProductOption' } & Pick< @@ -3425,7 +3425,7 @@ export type GetProductQuery = { __typename?: 'Query' } & { collections: Array< { __typename?: 'Collection' } & Pick< Collection, - 'id' + 'id'|"name" > > } diff --git a/framework/vendure/utils/fragments/search-result-fragment.ts b/framework/vendure/utils/fragments/search-result-fragment.ts index d2d82f42e..5a5998dca 100644 --- a/framework/vendure/utils/fragments/search-result-fragment.ts +++ b/framework/vendure/utils/fragments/search-result-fragment.ts @@ -7,6 +7,8 @@ export const searchResultFragment = /* GraphQL */ ` slug sku currencyCode + productVariantId + productVariantName productAsset { id preview diff --git a/framework/vendure/utils/normalize.ts b/framework/vendure/utils/normalize.ts index d088b2579..871352070 100644 --- a/framework/vendure/utils/normalize.ts +++ b/framework/vendure/utils/normalize.ts @@ -1,6 +1,6 @@ import { Cart } from '@commerce/types/cart' -import { ProductCard } from '@commerce/types/product' -import { CartFragment, SearchResultFragment,Favorite,ActiveCustomerQuery } from '../schema' +import { ProductCard, Product } from '@commerce/types/product' +import { CartFragment, SearchResultFragment,Favorite } from '../schema' export function normalizeSearchResult(item: SearchResultFragment): ProductCard { return { @@ -10,6 +10,8 @@ export function normalizeSearchResult(item: SearchResultFragment): ProductCard { imageSrc: item.productAsset?.preview ? item.productAsset?.preview + '?w=800&mode=crop' : '', price: (item.priceWithTax as any).min / 100, currencyCode: item.currencyCode, + productVariantId: item.productVariantId, + productVariantName:item.productVariantName, facetValueIds: item.facetValueIds, collectionIds: item.collectionIds, @@ -47,7 +49,7 @@ export function normalizeCart(order: CartFragment): Cart { id: l.id, name: l.productVariant.name, quantity: l.quantity, - url: l.productVariant.product.slug, + slug: l.productVariant.product.slug, variantId: l.productVariant.id, productId: l.productVariant.productId, images: [{ url: l.featuredAsset?.preview + '?preset=thumb' || '' }], @@ -67,3 +69,18 @@ export function normalizeCart(order: CartFragment): Cart { })), } } + +export function normalizeProductCard(product: Product): ProductCard { + return { + id: product.id, + name: product.name, + slug: product.slug, + imageSrc: product.images[0].url, + price: product.price, + currencyCode: product.currencyCode, + productVariantId: product.variants?.[0].id.toString(), + productVariantName:product.variants?.[0].name, + facetValueIds: product.facetValueIds, + collectionIds: product.collectionIds, + } +} \ No newline at end of file diff --git a/framework/vendure/utils/queries/get-product-query.ts b/framework/vendure/utils/queries/get-product-query.ts index 6db960a96..1ff057e61 100644 --- a/framework/vendure/utils/queries/get-product-query.ts +++ b/framework/vendure/utils/queries/get-product-query.ts @@ -12,6 +12,7 @@ export const getProductQuery = /* GraphQL */ ` } variants { id + name priceWithTax currencyCode options { @@ -41,6 +42,7 @@ export const getProductQuery = /* GraphQL */ ` } collections { id + name } } } diff --git a/next-env.d.ts b/next-env.d.ts index c6643fda1..9bc3dd46b 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,3 +1,6 @@ /// /// /// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/pages/index.tsx b/pages/index.tsx index ab86005e5..51127909a 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -6,6 +6,8 @@ import { GetStaticPropsContext } from 'next'; import { Layout } from 'src/components/common'; import { FeaturedProductsCarousel, FreshProducts, HomeBanner, HomeCategories, HomeCollection, HomeCTA, HomeFeature, HomeRecipe, HomeSubscribe, HomeVideo } from 'src/components/modules/home'; import HomeSpice from 'src/components/modules/home/HomeSpice/HomeSpice'; +import { FACET } from 'src/utils/constanst.utils'; +import { FilterOneVatiant, getFacetIdByName } from 'src/utils/funtion.utils'; import { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED,COLLECTION_SLUG_SPICE } from 'src/utils/constanst.utils'; import { getAllFacetValueIdsByParentCode, getAllFacetValuesForFeatuedProducts, getAllPromies, getFreshFacetId } from 'src/utils/funtion.utils'; import { PromiseWithKey } from 'src/utils/types.utils'; @@ -16,8 +18,10 @@ interface Props { featuredProducts: ProductCard[], collections: Collection[] spiceProducts:ProductCard[] + veggie: ProductCard[], + } -export default function Home({ featuredAndDiscountFacetsValue, +export default function Home({ featuredAndDiscountFacetsValue, veggie, freshProducts, featuredProducts, collections,spiceProducts }: Props) { @@ -26,8 +30,8 @@ export default function Home({ featuredAndDiscountFacetsValue, + - {spiceProducts.length>0 && } @@ -56,6 +60,8 @@ export async function getStaticProps({ config, preview, }) + + props.featuredAndDiscountFacetsValue = getAllFacetValuesForFeatuedProducts(facets) // fresh products @@ -73,7 +79,20 @@ export async function getStaticProps({ props.freshProducts = [] } - + //veggie + const veggieProductvariables: ProductVariables = { + groupByProduct:false + } + const veggieId = getFacetIdByName(facets,FACET.CATEGORY.PARENT_NAME,FACET.CATEGORY.VEGGIE) + if (veggieId) { + veggieProductvariables.facetValueIds = [veggieId] + } + const veggieProductsPromise = commerce.getAllProducts({ + variables: veggieProductvariables, + config, + preview, + }) + promisesWithKey.push({ key: 'veggie', promise: veggieProductsPromise, keyResult: 'products' }) // featured products const allFeaturedFacetIds = getAllFacetValueIdsByParentCode(facets, CODE_FACET_FEATURED) const allDiscountFacetIds = getAllFacetValueIdsByParentCode(facets, CODE_FACET_DISCOUNT) @@ -115,7 +134,7 @@ export async function getStaticProps({ const rs = await Promise.all(promises) promisesWithKey.map((item, index) => { - props[item.key] = item.keyResult ? rs[index][item.keyResult] : rs[index] + props[item.key] = item.keyResult ? FilterOneVatiant(rs[index][item.keyResult]) : rs[index] return null }) return { diff --git a/pages/product/[slug].tsx b/pages/product/[slug].tsx index 2da14a995..b107dc36d 100644 --- a/pages/product/[slug].tsx +++ b/pages/product/[slug].tsx @@ -1,22 +1,43 @@ -import { Product } from '@framework/schema' +import { Collection } from '@commerce/types/collection' +import { Product, ProductCard } from '@commerce/types/product' import commerce from '@lib/api/commerce' import { GetStaticPathsContext, GetStaticPropsContext, InferGetStaticPropsType } from 'next' +import { useEffect, useState } from 'react' import { Layout, RecipeDetail, RecommendedRecipes, RelevantBlogPosts } from 'src/components/common' +import { useLocalStorage } from 'src/components/hooks/useLocalStorage' import { ProductInfoDetail, ReleventProducts, ViewedProducts } from 'src/components/modules/product-detail' -import { MAX_PRODUCT_CAROUSEL, REVALIDATE_TIME } from 'src/utils/constanst.utils' +import { LOCAL_STORAGE_KEY, MAX_PRODUCT_CAROUSEL, REVALIDATE_TIME } from 'src/utils/constanst.utils' import { BLOGS_DATA_TEST, INGREDIENT_DATA_TEST, RECIPE_DATA_TEST } from 'src/utils/demo-data' import { getAllPromies } from 'src/utils/funtion.utils' +import { normalizeProductCard } from '@framework/utils/normalize'; import { PromiseWithKey } from 'src/utils/types.utils' - -export default function Slug({ product, relevantProducts, collections }: InferGetStaticPropsType) { - +interface Props { + relevantProducts: ProductCard[], + product: Product, + collections: Collection[] +} +export default function Slug({ product, relevantProducts, collections }: Props) { + const [local,setLocal] = useLocalStorage(LOCAL_STORAGE_KEY.VIEWEDPRODUCT, []); + const [viewed, setViewed] = useState([]) + useEffect(() => { + if(local){ + if(!local.find(p => p.id === product.id)){ + setLocal([...local, product]) + }else{ + setViewed(local.filter((p)=>p.id !== product.id).map((p)=>normalizeProductCard(p))) + } + }else{ + setLocal([product]) + } + }, [product]) + return <> - + - + } @@ -68,7 +89,6 @@ export async function getStaticProps({ }) promisesWithKey.push({ key: 'collections', promise: collectionsPromise, keyResult: 'collections' }) - try { const promises = getAllPromies(promisesWithKey) const rs = await Promise.all(promises) diff --git a/src/components/common/CartDrawer/CartDrawer.tsx b/src/components/common/CartDrawer/CartDrawer.tsx index 03cb966ad..089e8b620 100644 --- a/src/components/common/CartDrawer/CartDrawer.tsx +++ b/src/components/common/CartDrawer/CartDrawer.tsx @@ -1,5 +1,7 @@ +import { normalizeCart } from '@framework/utils/normalize'; import React from 'react'; import { useCartDrawer } from 'src/components/contexts'; +import useGetActiveOrder from 'src/components/hooks/cart/useGetActiveOrder'; import { PRODUCT_CART_DATA_TEST } from 'src/utils/demo-data'; import { DrawerCommon } from '..'; import s from './CartDrawer.module.scss'; @@ -14,14 +16,15 @@ interface Props { const CartDrawer = ({ }: Props) => { const { cartVisible, closeCartDrawer } = useCartDrawer() + const {order} = useGetActiveOrder() return (
- +
diff --git a/src/components/common/CartDrawer/components/ProductCartItem/ProductCartItem.tsx b/src/components/common/CartDrawer/components/ProductCartItem/ProductCartItem.tsx index 7ec3ecbdb..ef219d31d 100644 --- a/src/components/common/CartDrawer/components/ProductCartItem/ProductCartItem.tsx +++ b/src/components/common/CartDrawer/components/ProductCartItem/ProductCartItem.tsx @@ -1,25 +1,64 @@ -import React from 'react'; +import React, { useCallback, useState } from 'react' import Link from 'next/link' -import { QuanittyInput } from 'src/components/common'; -import { IconDelete } from 'src/components/icons'; -import { ROUTE } from 'src/utils/constanst.utils'; -import { ProductProps } from 'src/utils/types.utils'; -import ImgWithLink from '../../../ImgWithLink/ImgWithLink'; -import LabelCommon from '../../../LabelCommon/LabelCommon'; -import s from './ProductCartItem.module.scss'; +import { ModalConfirm, QuanittyInput } from 'src/components/common' +import { IconDelete } from 'src/components/icons' +import { ROUTE } from 'src/utils/constanst.utils' +import ImgWithLink from '../../../ImgWithLink/ImgWithLink' +import LabelCommon from '../../../LabelCommon/LabelCommon' +import s from './ProductCartItem.module.scss' +import { LineItem } from '@commerce/types/cart' +import { useUpdateProductInCart } from 'src/components/hooks/cart' +import { debounce } from 'lodash' +import useRemoveProductInCart from 'src/components/hooks/cart/useRemoveProductInCart' -export interface ProductCartItempProps extends ProductProps { - quantity: number, +export interface ProductCartItempProps extends LineItem { + currency: { code: string } } -const ProductCartItem = ({ name, slug, weight, price, oldPrice, discount, imageSrc, quantity }: ProductCartItempProps) => { +const ProductCartItem = ({ + slug, + discounts, + quantity, + variant, + name, + currency, + id +}: ProductCartItempProps) => { + const [visible, setVisible] = useState(false) + const {updateProduct} = useUpdateProductInCart() + const {removeProduct, loading} = useRemoveProductInCart() + const handleQuantityChangeCallback = (isSuccess:boolean,mess?:string) => { + if(!isSuccess){ + console.log(mess) + } + } + const handleRemoveCallback = (isSuccess:boolean,mess?:string) => { + if(!isSuccess){ + console.log(mess) + }else{ + setVisible(false) + } + } + const handleQuantityChange = (value:number) => { + updateProduct({orderLineId:id,quantity:value},handleQuantityChangeCallback) + } + const debounceFn = useCallback(debounce(handleQuantityChange, 500), []); + const handleCancel = () => { + setVisible(false) + } + const handleOpen = () => { + setVisible(true) + } + const handleConfirm = () => { + removeProduct({orderLineId:id},handleRemoveCallback) + } return (
- +
@@ -27,30 +66,32 @@ const ProductCartItem = ({ name, slug, weight, price, oldPrice, discount, imageS
- {name} {weight ? `(${weight})` : ''} + {name} {variant?.weight ? `(${variant.weight})` : ''}
- { - oldPrice && -
- {oldPrice} - {discount} -
- } -
{price}
+ {discounts.length > 0 && ( +
+ {/* {oldPrice} */} + {discounts[0]} +
+ )} +
{variant?.price} {currency?.code}
-
+
- +
+ + Are you sure want to remove {name} form your cart +
) } -export default ProductCartItem; \ No newline at end of file +export default ProductCartItem diff --git a/src/components/common/CartDrawer/components/ProductsInCart/ProductsInCart.tsx b/src/components/common/CartDrawer/components/ProductsInCart/ProductsInCart.tsx index b455d4d73..7d6432a9d 100644 --- a/src/components/common/CartDrawer/components/ProductsInCart/ProductsInCart.tsx +++ b/src/components/common/CartDrawer/components/ProductsInCart/ProductsInCart.tsx @@ -1,25 +1,21 @@ +import { LineItem } from '@commerce/types/cart'; import React from 'react'; import ProductCartItem, { ProductCartItempProps } from '../ProductCartItem/ProductCartItem'; import s from './ProductsInCart.module.scss'; interface Props { - data: ProductCartItempProps[] + data: LineItem[] + currency: { code: string } } -const ProductsInCart = ({ data }: Props) => { +const ProductsInCart = ({ data, currency }: Props) => { return (
    { data.map(item =>
  • ) } diff --git a/src/components/common/MenuFilter/MenuFilterItem/MenuFilterItem.tsx b/src/components/common/MenuFilter/MenuFilterItem/MenuFilterItem.tsx index eeb96fae1..b694e7da8 100644 --- a/src/components/common/MenuFilter/MenuFilterItem/MenuFilterItem.tsx +++ b/src/components/common/MenuFilter/MenuFilterItem/MenuFilterItem.tsx @@ -1,5 +1,4 @@ import classNames from 'classnames'; -import { route } from 'next/dist/server/router'; import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; import s from './MenuFilterItem.module.scss'; diff --git a/src/components/common/ModalConfirm/ModalConfirm.tsx b/src/components/common/ModalConfirm/ModalConfirm.tsx index 1e425482f..a41dd41d7 100644 --- a/src/components/common/ModalConfirm/ModalConfirm.tsx +++ b/src/components/common/ModalConfirm/ModalConfirm.tsx @@ -5,6 +5,7 @@ import s from './ModalConfirm.module.scss' interface ModalConfirmProps extends ModalCommonProps { okText?: String cancelText?: String + loading?:boolean onOk?: () => void onCancel?: () => void } @@ -16,6 +17,7 @@ const ModalConfirm = ({ onCancel, children, title = 'Confirm', + loading, ...props }: ModalConfirmProps) => { return ( @@ -25,7 +27,7 @@ const ModalConfirm = ({
    {cancelText}
    - {okText} + {okText}
) diff --git a/src/components/common/ProductCard/ProductCard.tsx b/src/components/common/ProductCard/ProductCard.tsx index 51038c9d6..4f14e5b1f 100644 --- a/src/components/common/ProductCard/ProductCard.tsx +++ b/src/components/common/ProductCard/ProductCard.tsx @@ -10,7 +10,9 @@ import ItemWishList from '../ItemWishList/ItemWishList' import LabelCommon from '../LabelCommon/LabelCommon' import s from './ProductCard.module.scss' import ProductNotSell from './ProductNotSell/ProductNotSell' - +import {useAddProductToCart} from "../../hooks/cart" +import { useCartDrawer } from 'src/components/contexts' +import Router from 'next/router' export interface ProductCardProps extends ProductCard { buttonText?: string isSingleButton?: boolean, @@ -29,14 +31,41 @@ const ProductCardComponent = ({ imageSrc, isNotSell, isSingleButton, + productVariantId, + productVariantName, activeWishlist }: ProductCardProps) => { + + const {addProduct,loading} = useAddProductToCart() + const { openCartDrawer } = useCartDrawer() + + const handleAddToCart = () => { + if(productVariantId){ + addProduct({variantId:productVariantId,quantity:1},handleAddToCartCallback) + } + } + const handleAddToCartCallback = () => { + openCartDrawer && openCartDrawer() + } + + const handleBuyNowCallback = (success:boolean) => { + if(success){ + Router.push(ROUTE.CHECKOUT) + } + } + + const handleBuyNow = () => { + if(productVariantId){ + addProduct({variantId:productVariantId,quantity:1},handleBuyNowCallback) + } + } + if (isNotSell) { return
- } + return (
@@ -59,7 +88,7 @@ const ProductCardComponent = ({
-
{name}
+
{productVariantName}
{weight}
@@ -75,15 +104,15 @@ const ProductCardComponent = ({ { isSingleButton ?
- } size='small'>Add to cart + } size='small' onClick={handleAddToCart}>Add to cart
: <> -
- +
+
- {buttonText} + {buttonText}
} diff --git a/src/components/common/QuanittyInput/QuanittyInput.tsx b/src/components/common/QuanittyInput/QuanittyInput.tsx index e31abb880..e2229830f 100644 --- a/src/components/common/QuanittyInput/QuanittyInput.tsx +++ b/src/components/common/QuanittyInput/QuanittyInput.tsx @@ -26,10 +26,6 @@ const QuanittyInput = ({ }: QuanittyInputProps) => { const [value, setValue] = useState(0) - useEffect(() => { - onChange && onChange(value) - }, [value]) - useEffect(() => { initValue && setValue(initValue) }, [initValue]) @@ -37,16 +33,20 @@ const QuanittyInput = ({ const onPlusClick = () => { if (max && value + step > max) { setValue(max) + onChange && onChange(max) } else { setValue(value + step) + onChange && onChange(value + step) } } const onMinusClick = () => { if (min && value - step < min) { setValue(min) + onChange && onChange(min) } else { setValue(value - step) + onChange && onChange(value - step) } } @@ -54,10 +54,13 @@ const QuanittyInput = ({ let value = Number(e.target.value) || 0 if (min && value < min) { setValue(min) + onChange && onChange(min) } else if (max && value > max) { setValue(max) + onChange && onChange(max) } else { setValue(value) + onChange && onChange(value) } } diff --git a/src/components/hooks/cart/index.ts b/src/components/hooks/cart/index.ts new file mode 100644 index 000000000..950b32e7d --- /dev/null +++ b/src/components/hooks/cart/index.ts @@ -0,0 +1,3 @@ +export { default as useAddProductToCart } from './useAddProductToCart' +export { default as useUpdateProductInCart } from './useUpdateProductInCart' +export { default as useGetActiveOrder } from './useGetActiveOrder' \ No newline at end of file diff --git a/src/components/hooks/cart/useAddProductToCart.tsx b/src/components/hooks/cart/useAddProductToCart.tsx new file mode 100644 index 000000000..2e6c538e2 --- /dev/null +++ b/src/components/hooks/cart/useAddProductToCart.tsx @@ -0,0 +1,40 @@ +import { useState } from 'react' +import { CommonError } from 'src/domains/interfaces/CommonError' +import rawFetcher from 'src/utils/rawFetcher' +import { AddItemToOrderMutation, AddItemToOrderMutationVariables } from '@framework/schema' +import { errorMapping } from 'src/utils/errrorMapping' +import { useGetActiveOrder } from '.' +import { addItemToOrderMutation } from '@framework/utils/mutations/add-item-to-order-mutation' + +const useAddProductToCart = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const { mutate } = useGetActiveOrder() + + const addProduct = (options:AddItemToOrderMutationVariables, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + rawFetcher({ + query: addItemToOrderMutation , + variables: options, + }) + .then(({ data }) => { + if (data.addItemToOrder.__typename !== "Order") { + throw CommonError.create(errorMapping(data.addItemToOrder.message), data.addItemToOrder.errorCode) + } + mutate() + fCallBack(true) + }) + .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + } + + return { loading, addProduct, error } +} + +export default useAddProductToCart diff --git a/src/components/hooks/cart/useGetActiveOrder.tsx b/src/components/hooks/cart/useGetActiveOrder.tsx new file mode 100644 index 000000000..4c26a1786 --- /dev/null +++ b/src/components/hooks/cart/useGetActiveOrder.tsx @@ -0,0 +1,23 @@ +import { Cart } from '@commerce/types/cart' +import { ActiveOrderQuery } from '@framework/schema' +import { cartFragment } from '@framework/utils/fragments/cart-fragment' +import { normalizeCart } from '@framework/utils/normalize' +import { gql } from 'graphql-request' +import gglFetcher from 'src/utils/gglFetcher' +import useSWR from 'swr' +const query = gql` + query activeOrder { + activeOrder { + ...Cart + } + } + ${ cartFragment } +` + +const useGetActiveOrder = () => { + const { data, ...rest } = useSWR([query], gglFetcher) + return { order: data?.activeOrder ? normalizeCart(data!.activeOrder) : null, ...rest } + +} + +export default useGetActiveOrder diff --git a/src/components/hooks/cart/useRemoveProductInCart.tsx b/src/components/hooks/cart/useRemoveProductInCart.tsx new file mode 100644 index 000000000..d66fd4306 --- /dev/null +++ b/src/components/hooks/cart/useRemoveProductInCart.tsx @@ -0,0 +1,41 @@ +import { useState } from 'react' +import { CommonError } from 'src/domains/interfaces/CommonError' +import rawFetcher from 'src/utils/rawFetcher' +import { AdjustOrderLineMutationVariables,AdjustOrderLineMutation, RemoveOrderLineMutation, RemoveOrderLineMutationVariables } from '@framework/schema' +import { errorMapping } from 'src/utils/errrorMapping' +import { useGetActiveOrder } from '.' +import { adjustOrderLineMutation } from '@framework/utils/mutations/adjust-order-line-mutation' +import { removeOrderLineMutation } from '@framework/utils/mutations/remove-order-line-mutation' + +const useRemoveProductInCart = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const { mutate } = useGetActiveOrder() + + const removeProduct = (options:RemoveOrderLineMutationVariables, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + rawFetcher({ + query: removeOrderLineMutation , + variables: options, + }) + .then(({ data }) => { + if (data.removeOrderLine.__typename !== "Order") { + throw CommonError.create(errorMapping(data.removeOrderLine.message), data.removeOrderLine.errorCode) + } + mutate() + fCallBack(true) + }) + .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + } + + return { loading, removeProduct, error } +} + +export default useRemoveProductInCart diff --git a/src/components/hooks/cart/useUpdateProductInCart.tsx b/src/components/hooks/cart/useUpdateProductInCart.tsx new file mode 100644 index 000000000..b2a0423bb --- /dev/null +++ b/src/components/hooks/cart/useUpdateProductInCart.tsx @@ -0,0 +1,40 @@ +import { useState } from 'react' +import { CommonError } from 'src/domains/interfaces/CommonError' +import rawFetcher from 'src/utils/rawFetcher' +import { AdjustOrderLineMutationVariables,AdjustOrderLineMutation } from '@framework/schema' +import { errorMapping } from 'src/utils/errrorMapping' +import { useGetActiveOrder } from '.' +import { adjustOrderLineMutation } from '@framework/utils/mutations/adjust-order-line-mutation' + +const useUpdateProductInCart = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const { mutate } = useGetActiveOrder() + + const updateProduct = (options:AdjustOrderLineMutationVariables, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + rawFetcher({ + query: adjustOrderLineMutation , + variables: options, + }) + .then(({ data }) => { + if (data.adjustOrderLine.__typename !== "Order") { + throw CommonError.create(errorMapping(data.adjustOrderLine.message), data.adjustOrderLine.errorCode) + } + mutate() + fCallBack(true) + }) + .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + } + + return { loading, updateProduct, error } +} + +export default useUpdateProductInCart diff --git a/src/components/hooks/useGetProductListByCollection.tsx b/src/components/hooks/useGetProductListByCollection.tsx new file mode 100644 index 000000000..49ec4c81b --- /dev/null +++ b/src/components/hooks/useGetProductListByCollection.tsx @@ -0,0 +1,47 @@ +// import { gql } from 'graphql-request' +import { useMemo, useState } from 'react' +// import useActiveCustomer from './useActiveCustomer' +import { CommonError } from 'src/domains/interfaces/CommonError' +import rawFetcher from 'src/utils/rawFetcher' +import { + CollectionList, + CollectionListOptions, + GetCollectionsQuery, + GetCollectionsQueryVariables, + LoginMutation, +} from '@framework/schema' +import { gql } from 'graphql-request' + +import { getCollectionsQuery } from '@framework/utils/queries/get-collections-query' +import useSWR from 'swr' +import gglFetcher from 'src/utils/gglFetcher' + +const query = gql` + query getCollections($option: CollectionListOptions) { + collections(options:$option) { + items { + id + name + description + slug + productVariants { + totalItems + } + parent { + id + } + children { + id + } + } + } + } +` + +const useGetProductListByCollection = (options: any) => { + + const { data, ...rest } = useSWR([query, options], gglFetcher) + return { collections: data?.collections, ...rest } +} + +export default useGetProductListByCollection diff --git a/src/components/hooks/useLocalStorage.tsx b/src/components/hooks/useLocalStorage.tsx new file mode 100644 index 000000000..b265ded9a --- /dev/null +++ b/src/components/hooks/useLocalStorage.tsx @@ -0,0 +1,36 @@ +import { useState } from "react"; + +// Hook +export function useLocalStorage(key: string, initialValue: T) { + // State to store our value + // Pass initial state function to useState so logic is only executed once + const [storedValue, setStoredValue] = useState(() => { + try { + // Get from local storage by key + const item = localStorage.getItem(key); + // Parse stored json or if none return initialValue + return item ? JSON.parse(item) : initialValue; + } catch (error) { + // If error also return initialValue + // console.log(error); + return initialValue; + } + }); + // Return a wrapped version of useState's setter function that ... + // ... persists the new value to localStorage. + const setValue = (value: T | ((val: T) => T)) => { + try { + // Allow value to be a function so we have same API as useState + const valueToStore = + value instanceof Function ? value(storedValue) : value; + // Save state + setStoredValue(valueToStore); + // Save to local storage + localStorage.setItem(key, JSON.stringify(valueToStore)); + } catch (error) { + // A more advanced implementation would handle the error case + // console.log(error); + } + }; + return [storedValue, setValue] as const; +} \ No newline at end of file diff --git a/src/components/modules/home/HomeBanner/HomeBanner.tsx b/src/components/modules/home/HomeBanner/HomeBanner.tsx index ebb9af6bf..e5e678893 100644 --- a/src/components/modules/home/HomeBanner/HomeBanner.tsx +++ b/src/components/modules/home/HomeBanner/HomeBanner.tsx @@ -1,5 +1,7 @@ -import React from 'react' +import { CollectionListOptions, GetCollectionsQuery } from '@framework/schema' +import React, { useEffect, useMemo, useState } from 'react' import { Banner, StaticImage } from 'src/components/common' +import useGetProductListByCollection from 'src/components/hooks/useGetProductListByCollection' import { ROUTE } from 'src/utils/constanst.utils' import BannerImgRight from './assets/banner_full.png' import HomeBannerImg from './assets/home_banner.png' @@ -11,6 +13,10 @@ interface Props { } const HomeBanner = ({ }: Props) => { + // const variables = useMemo(() => { + // return {option: {filter: {name: {eq: "Computers" }}}} + // }, []) + // const {collections} = useGetProductListByCollection(variables) return (
diff --git a/src/components/modules/home/HomeCollection/HomeCollection.tsx b/src/components/modules/home/HomeCollection/HomeCollection.tsx index 98ab5624a..4753f9ebe 100644 --- a/src/components/modules/home/HomeCollection/HomeCollection.tsx +++ b/src/components/modules/home/HomeCollection/HomeCollection.tsx @@ -1,10 +1,13 @@ import React from 'react' +import { ProductCard } from '@commerce/types/product' import { CollectionCarcousel } from '..' import image5 from '../../../../../public/assets/images/image5.png' import image6 from '../../../../../public/assets/images/image6.png' import image7 from '../../../../../public/assets/images/image7.png' import image8 from '../../../../../public/assets/images/image8.png' -interface HomeCollectionProps {} +interface HomeCollectionProps { + data: ProductCard[] +} const dataTest = [ { name: 'Tomato', @@ -92,39 +95,39 @@ const dataTest = [ }, ] -const HomeCollection = (props: HomeCollectionProps) => { +const HomeCollection = ({data}: HomeCollectionProps) => { return (
{ - const dataWithCategoryName = useMemo(() => { - return { - ...productDetail, - collection: getCategoryNameFromCollectionId(collections, productDetail.collectionIds ? productDetail.collectionIds[0] : undefined) - } - }, [productDetail, collections]) +const ProductInfoDetail = ({ productDetail }: Props) => { return (
- +
) } diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.module.scss b/src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.module.scss new file mode 100644 index 000000000..d22660a4a --- /dev/null +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.module.scss @@ -0,0 +1,37 @@ +.warpper{ + display: flex; + justify-content: flex-start; + flex-direction: column; + align-items: flex-start; + .name{ + margin-bottom: 0.5rem; + margin-top: 0.5rem; + font-size: 2rem; + font-weight: 700; + text-transform: capitalize; + } + .option{ + display: flex; + justify-content: flex-start; + align-items: flex-start; + // > button { + // margin-right: 1rem; + // } + } + .button { + margin: 1rem 0; + padding: 0; + div { + padding: 0.8rem 1.6rem; + margin-right: 0.8rem; + background-color: var(--gray); + border-radius: 0.8rem; + cursor: pointer; + &.active { + color: var(--white); + background-color: var(--primary); + } + } + } + +} \ No newline at end of file diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.tsx b/src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.tsx new file mode 100644 index 000000000..0d7e13c84 --- /dev/null +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductDetailOption/ProductDetailOption.tsx @@ -0,0 +1,55 @@ +import { ProductOption, ProductOptionValues } from '@commerce/types/product' +import classNames from 'classnames' +import React, { useEffect, useState } from 'react' +import { SelectedOptions } from 'src/utils/types.utils' +import s from './ProductDetailOption.module.scss' +interface Props { + option: ProductOption + onChane: (values: SelectedOptions) => void +} + +const ProductDetailOption = React.memo(({ option, onChane }: Props) => { + const [selected, setSelected] = useState('') + useEffect(() => { + if (option) { + setSelected(option.values[0].label) + } + }, [option]) + const handleClick = (value:string) => { + setSelected(value) + onChane && onChane({[option.displayName]:value}) + } + return ( +
+
{option.displayName}:
+
+ {option.values.map((value) => { + return + })} +
+
+ ) +}) +interface ProductDetailOptionButtonProps { + value: ProductOptionValues + selected: string + onClick: (value: string) => void +} +const ProductDetailOptionButton = ({ + value, + selected, + onClick, +}: ProductDetailOptionButtonProps) => { + const handleClick = () => { + onClick && onClick(value.label) + } + return ( +
+
+ {value.label} +
+
+ ) +} + +export default ProductDetailOption diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx b/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx index c3e51d46d..961d8e29b 100644 --- a/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx @@ -1,8 +1,15 @@ import { Product } from '@commerce/types/product' -import React from 'react' +import Router from 'next/router' +import React, { useEffect, useState } from 'react' import { ButtonCommon, LabelCommon, QuanittyInput } from 'src/components/common' +import { useCartDrawer, useMessage } from 'src/components/contexts' +import { useAddProductToCart } from 'src/components/hooks/cart' import { IconBuy } from 'src/components/icons' +import { ROUTE } from 'src/utils/constanst.utils' +import { getProductVariant } from 'src/utils/funtion.utils' import { LANGUAGE } from 'src/utils/language.utils' +import { SelectedOptions } from 'src/utils/types.utils' +import ProductDetailOption from '../ProductDetailOption/ProductDetailOption' import s from './ProductInfo.module.scss' interface Props { @@ -10,11 +17,73 @@ interface Props { } const ProductInfo = ({ productInfoDetail }: Props) => { - console.log(productInfoDetail) + const [option, setOption] = useState({}) + const [quanitty, setQuanitty] = useState(0) + const [addToCartLoading, setAddToCartLoading] = useState(false) + const [buyNowLoading, setBuyNowLoading] = useState(false) + const { showMessageSuccess, showMessageError } = useMessage() + useEffect(() => { + let defaultOption:SelectedOptions = {} + productInfoDetail.options.map((option)=>{ + defaultOption[option.displayName] = option.values[0].label + return null + }) + }, [productInfoDetail]) + + const {addProduct} = useAddProductToCart() + const { openCartDrawer } = useCartDrawer() + + function handleAddToCart() { + setAddToCartLoading(true) + const variant = getProductVariant(productInfoDetail, option) + if (variant) { + addProduct({ variantId: variant.id.toString(), quantity: quanitty }, handleAddToCartCallback) + }else{ + setAddToCartLoading(false) + } + } + const handleAddToCartCallback = (isSuccess:boolean,message?:string) => { + setAddToCartLoading(false) + if(isSuccess){ + showMessageSuccess("Add to cart successfully!", 4000) + openCartDrawer && openCartDrawer() + }else{ + showMessageError(message||"Error") + } + + } + + const handleBuyNowCallback = (success:boolean,message?:string) => { + setBuyNowLoading(false) + if(success){ + Router.push(ROUTE.CHECKOUT) + }else{ + showMessageError(message||"Error") + } + } + + const handleBuyNow = () => { + setBuyNowLoading(true) + const variant = getProductVariant(productInfoDetail, option) + if (variant) { + addProduct({ variantId: variant.id.toString(), quantity: quanitty }, handleBuyNowCallback) + }else{ + setBuyNowLoading(false) + } + } + + const handleQuanittyChange = (value:number) => { + setQuanitty(value) + } + const onSelectOption = (value:SelectedOptions) => { + setOption({...option,...value}) + // let variant = getProductVariant(productInfoDetail,value) + // console.log(variant) + } return (
- {productInfoDetail.collection} + {productInfoDetail.collection?.[0]}

{productInfoDetail.name}

@@ -26,14 +95,22 @@ const ProductInfo = ({ productInfoDetail }: Props) => {
{productInfoDetail.description}
+
+ { + productInfoDetail.options.map((option)=>{ + return + }) + } + +
- +
{/* {LANGUAGE.BUTTON_LABEL.PREORDER} */} - {LANGUAGE.BUTTON_LABEL.BUY_NOW} + {LANGUAGE.BUTTON_LABEL.BUY_NOW} - + {LANGUAGE.BUTTON_LABEL.ADD_TO_CARD} diff --git a/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx b/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx index d1afde538..9e2581833 100644 --- a/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx +++ b/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx @@ -1,5 +1,5 @@ +import { Collection } from '@commerce/types/collection'; import { ProductCard } from '@commerce/types/product'; -import { Collection } from '@framework/schema'; import React, { useMemo } from 'react'; import ListProductWithInfo from 'src/components/common/ListProductWithInfo/ListProductWithInfo'; import { getCategoryNameFromCollectionId } from 'src/utils/funtion.utils'; diff --git a/src/components/modules/product-detail/ViewedProducts/ViewedProducts.tsx b/src/components/modules/product-detail/ViewedProducts/ViewedProducts.tsx index 87e600416..22190b49a 100644 --- a/src/components/modules/product-detail/ViewedProducts/ViewedProducts.tsx +++ b/src/components/modules/product-detail/ViewedProducts/ViewedProducts.tsx @@ -1,13 +1,22 @@ -import React from 'react'; +import { Product } from '@commerce/types/product'; +import React, { useEffect, useState } from 'react'; import ListProductWithInfo from 'src/components/common/ListProductWithInfo/ListProductWithInfo'; -import { PRODUCT_DATA_TEST } from 'src/utils/demo-data'; - -const ViewedProducts = () => { +import { ProductCardProps } from 'src/components/common/ProductCard/ProductCard'; +import { LOCAL_STORAGE_KEY } from 'src/utils/constanst.utils' +import { normalizeProductCard } from '@framework/utils/normalize'; +import { useLocalStorage } from 'src/components/hooks/useLocalStorage'; +interface Props { + data: ProductCardProps[] +} +const ViewedProducts = ({data}:Props) => { + if (data.length===0){ + return
+ } return ( ); diff --git a/src/domains/enums/Message.ts b/src/domains/enums/Message.ts new file mode 100644 index 000000000..3d8b4e288 --- /dev/null +++ b/src/domains/enums/Message.ts @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/utils/constanst.utils.ts b/src/utils/constanst.utils.ts index 108e96265..8ad8657ed 100644 --- a/src/utils/constanst.utils.ts +++ b/src/utils/constanst.utils.ts @@ -44,7 +44,8 @@ export const ACCOUNT_TAB = { } export const LOCAL_STORAGE_KEY = { - TOKEN: 'token' + TOKEN: 'token', + VIEWEDPRODUCT: "viewed-product" } export const QUERY_SPLIT_SEPERATOR = ',' @@ -82,46 +83,58 @@ export const DEFAULT_PAGE_SIZE = 20; export const CATEGORY = [ - { - name: 'All', - link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=${OPTION_ALL}`, - }, - { - name: 'Veggie', - link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=veggie`, - }, - { - name: 'Seafood', - link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=seafood`, - }, - { - name: 'Frozen', - link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=frozen`, - }, - { - name: 'Coffee Bean', - link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=coffee_bean`, - }, - { - name: 'Sauce', - link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=sauce`, - }, -] + { + name: 'All', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=${OPTION_ALL}`, + }, + { + name: 'Veggie', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=veggie`, + }, + { + name: 'Seafood', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=seafood`, + }, + { + name: 'Frozen', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=frozen`, + }, + { + name: 'Coffee Bean', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=coffee_bean`, + }, + { + name: 'Sauce', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=sauce`, + }, + ] + + export const BRAND = [ + { + name: 'Maggi', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=maggi`, + }, + { + name: 'Chomilex', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=chomilex`, + }, + { + name: 'Chinsu', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=chinsu`, + }, + ] -export const BRAND = [ - { - name: 'Maggi', - link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=maggi`, +export const FACET = { + FEATURE: { + PARENT_NAME: 'Featured', + FRESH: 'Fresh', + BEST_SELLERS: 'Best seller' }, - { - name: 'Chomilex', - link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=chomilex`, - }, - { - name: 'Chinsu', - link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=chinsu`, - }, -] + CATEGORY: { + PARENT_NAME:"category", + VEGGIE:"veggie" + } +} export const CODE_FACET_FEATURED = 'featured' export const CODE_FACET_DISCOUNT = 'discount' diff --git a/src/utils/enum.ts b/src/utils/enum.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/utils/funtion.utils.ts b/src/utils/funtion.utils.ts index 408d9d0fd..94521e072 100644 --- a/src/utils/funtion.utils.ts +++ b/src/utils/funtion.utils.ts @@ -1,7 +1,9 @@ +import { Collection } from '@commerce/types/collection'; import { Facet } from "@commerce/types/facet"; -import { Collection, FacetValue, SearchResultSortParameter } from './../../framework/vendure/schema.d'; -import { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED, CODE_FACET_FEATURED_VARIANT, PRODUCT_SORT_OPTION_VALUE } from "./constanst.utils"; -import { PromiseWithKey, SortOrder } from "./types.utils"; +import { Product, ProductCard, ProductOption, ProductOptionValues } from "@commerce/types/product"; +import { FacetValue, SearchResultSortParameter } from './../../framework/vendure/schema.d'; +import { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED, CODE_FACET_FEATURED_VARIANT, FACET, PRODUCT_SORT_OPTION_VALUE } from "./constanst.utils"; +import { PromiseWithKey, SelectedOptions, SortOrder } from "./types.utils"; export function isMobile() { return window.innerWidth < 768 @@ -79,6 +81,18 @@ export function getFreshFacetId(facets: Facet[]) { return freshFacetValue?.id } +export function getFacetIdByName(facets: Facet[], facetName: string, valueName:string) { + const featuredFacet = facets.find((item: Facet) => item.name === facetName) + const freshFacetValue = featuredFacet?.values.find((item: FacetValue) => item.name === valueName) + return freshFacetValue?.id +} + + +export function getAllFeaturedFacetId(facets: Facet[]) { + const featuredFacet = facets.find((item: Facet) => item.name === FACET.FEATURE.PARENT_NAME) + const rs = featuredFacet?.values.map((item: FacetValue) => item.id) + return rs || [] +} export function getAllFacetValueIdsByParentCode(facets: Facet[], code: string) { const featuredFacet = facets.find((item: Facet) => item.code === code) const rs = featuredFacet?.values.map((item: FacetValue) => item.id) @@ -127,4 +141,36 @@ export const getCategoryNameFromCollectionId = (colelctions: Collection[], colle export function getAllPromies(promies: PromiseWithKey[]) { return promies.map(item => item.promise) +} + +export const FilterOneVatiant = (products:ProductCard[]) => { + let idList:string[] = [] + let filtedProduct: ProductCard[]=[] + products.map((product:ProductCard)=>{ + if(!idList.includes(product.id)){ + filtedProduct.push(product) + idList.push(product.id) + } + }) + return filtedProduct +} + +export const convertOption = (values :ProductOptionValues[]) => { + return values.map((value)=>{ return {name:value.label,value:value.label}}) +} + +export function getProductVariant(product: Product, opts: SelectedOptions) { + const variant = product.variants?.find((variant) => { + return Object.entries(opts).every(([key, value]) => + variant.options.find((option) => { + if ( + option.__typename === 'MultipleChoiceOption' && + option.displayName.toLowerCase() === key.toLowerCase() + ) { + return option.values.find((v) => v.label.toLowerCase() === value) + } + }) + ) + }) + return variant } \ No newline at end of file diff --git a/src/utils/types.utils.ts b/src/utils/types.utils.ts index e3eee3e9d..055fb799c 100644 --- a/src/utils/types.utils.ts +++ b/src/utils/types.utils.ts @@ -1,3 +1,4 @@ + export interface ProductProps { category?: string name: string @@ -57,6 +58,14 @@ export type filterContextType = { close: () => void; }; +export interface StringMap { [key: string]: string; } + +export interface FacetMap extends StringMap{ + PARENT_NAME: string +} +export interface FacetConstant{ + [key: string]: FacetMap; +} export type PromiseWithKey = { key: string promise: PromiseLike @@ -77,3 +86,4 @@ export type OrderState = | 'Created' | 'ArrangingAdditionalPayment' | 'Cancelled' +export type SelectedOptions = Record