diff --git a/framework/commerce/api/operations.ts b/framework/commerce/api/operations.ts index 2910a2d82..342d6bbc9 100644 --- a/framework/commerce/api/operations.ts +++ b/framework/commerce/api/operations.ts @@ -1,3 +1,4 @@ +import { GetAllFacetsOperation } from './../types/facet'; import type { ServerResponse } from 'http' import type { LoginOperation } from '../types/login' import type { GetAllPagesOperation, GetPageOperation } from '../types/page' @@ -23,6 +24,8 @@ export const OPERATIONS = [ 'getAllProductPaths', 'getAllProducts', 'getProduct', + 'getAllFacets', + ] as const export const defaultOperations = OPERATIONS.reduce((ops, k) => { @@ -154,8 +157,27 @@ export type Operations

= { } & OperationOptions ): Promise } + + getAllFacets: { + (opts: { + variables?: T['variables'] + config?: P['config'] + preview?: boolean + }): Promise + + ( + opts: { + variables?: T['variables'] + config?: P['config'] + preview?: boolean + } & OperationOptions + ): Promise + } + + } + export type APIOperations

= { [K in keyof Operations

]?: (ctx: OperationContext

) => Operations

[K] } diff --git a/framework/commerce/new-provider.md b/framework/commerce/new-provider.md index 8c2feeab2..a48e6961b 100644 --- a/framework/commerce/new-provider.md +++ b/framework/commerce/new-provider.md @@ -15,6 +15,7 @@ Adding a commerce provider means adding a new folder in `framework` with a folde - useSearch - getProduct - getAllProducts + - getAllFacets - `wishlist` - useWishlist - useAddItem diff --git a/framework/commerce/types/facet.ts b/framework/commerce/types/facet.ts new file mode 100644 index 000000000..adfe1e061 --- /dev/null +++ b/framework/commerce/types/facet.ts @@ -0,0 +1,52 @@ +import { FacetValue } from './../../vendure/schema.d'; + +export type Facet = { + id: string + name: string + code: string + values: FacetValue[] +} + +export type SearchFacetsBody = { + search?: string + sort?: string + locale?: string +} + +export type FacetTypes = { + facet: Facet + searchBody: SearchFacetsBody +} + +export type SearchFacetsHook = { + data: { + facets: T['facet'][] + found: boolean + } + body: T['searchBody'] + input: T['searchBody'] + fetcherInput: T['searchBody'] +} + +export type FacetsSchema = { + endpoint: { + options: {} + handlers: { + getFacets: SearchFacetsHook + } + } +} + + +export type GetAllFacetsOperation = { + data: { facets: T['facet'][] } + variables: { + ids?: string[] + first?: number + } +} + +export type GetFacetOperation = { + data: { facet?: T['facet'] } + variables: { code: string; } | { code?: never; } +} diff --git a/framework/commerce/types/product.ts b/framework/commerce/types/product.ts index 6a68d8ad1..ac7025158 100644 --- a/framework/commerce/types/product.ts +++ b/framework/commerce/types/product.ts @@ -1,3 +1,6 @@ +import { CurrencyCode, FacetValue } from './../../vendure/schema.d'; +import { FacetValueFilterInput, LogicalOperator, SearchResultSortParameter } from "@framework/schema" + export type ProductImage = { url: string alt?: string @@ -40,11 +43,27 @@ export type Product = { slug?: string path?: string images: ProductImage[] - variants: ProductVariant[] price: ProductPrice options: ProductOption[] } +export type ProductCard = { + id: string + name: string + slug?: string + imageSrc: string + price: number + currencyCode: CurrencyCode + oldPrice?: number + discount?: number + weight?: number + facetValueIds?: string[], + collectionIds?: string[], + // TODO: collection + category?: string, + isNotSell?: boolean +} + export type SearchProductsBody = { search?: string categoryId?: string | number @@ -79,17 +98,24 @@ export type ProductsSchema = { export type GetAllProductPathsOperation< T extends ProductTypes = ProductTypes -> = { - data: { products: Pick[] } - variables: { first?: number } -} + > = { + data: { products: Pick[] } + variables: { first?: number } + } export type GetAllProductsOperation = { data: { products: T['product'][] } variables: { - relevance?: 'featured' | 'best_selling' | 'newest' - ids?: string[] - first?: number + term?: String + facetValueIds?: string[] + facetValueOperator?: LogicalOperator + facetValueFilters?: FacetValueFilterInput[] + collectionId?: string + collectionSlug?: string + groupByProduct?: Boolean + take?: number + skip?: number + sort?: SearchResultSortParameter } } diff --git a/framework/vendure/api/index.ts b/framework/vendure/api/index.ts index 6762ee6aa..7e49d6c1f 100644 --- a/framework/vendure/api/index.ts +++ b/framework/vendure/api/index.ts @@ -1,15 +1,16 @@ -import type { APIProvider, CommerceAPIConfig } from '@commerce/api' +import type { CommerceAPIConfig } from '@commerce/api' import { CommerceAPI, getCommerceApi as commerceApi } from '@commerce/api' -import fetchGraphqlApi from './utils/fetch-graphql-api' - -import login from './operations/login' +import getAllFacets from './operations/get-all-facets' import getAllPages from './operations/get-all-pages' -import getPage from './operations/get-page' -import getSiteInfo from './operations/get-site-info' -import getCustomerWishlist from './operations/get-customer-wishlist' import getAllProductPaths from './operations/get-all-product-paths' import getAllProducts from './operations/get-all-products' +import getCustomerWishlist from './operations/get-customer-wishlist' +import getPage from './operations/get-page' import getProduct from './operations/get-product' +import getSiteInfo from './operations/get-site-info' +import login from './operations/login' +import fetchGraphqlApi from './utils/fetch-graphql-api' + export interface VendureConfig extends CommerceAPIConfig {} @@ -40,6 +41,7 @@ const operations = { getAllProductPaths, getAllProducts, getProduct, + getAllFacets, } export const provider = { config, operations } diff --git a/framework/vendure/api/operations/get-all-facets.ts b/framework/vendure/api/operations/get-all-facets.ts new file mode 100644 index 000000000..c4b002744 --- /dev/null +++ b/framework/vendure/api/operations/get-all-facets.ts @@ -0,0 +1,45 @@ +import { OperationContext } from '@commerce/api/operations' +import { Facet } from '@commerce/types/facet' +import { Provider, VendureConfig } from '../' +import { GetAllFacetsQuery } from '../../schema' +import { getAllFacetsQuery } from '../../utils/queries/get-all-facets-query' + +export type FacetVariables = { first?: number } + +export default function getAllFacetsOperation({ + commerce, +}: OperationContext) { + async function getAllFacets(opts?: { + variables?: FacetVariables + config?: Partial + preview?: boolean + }): Promise<{ facets: Facet[] }> + + async function getAllFacets({ + query = getAllFacetsQuery, + variables: { ...vars } = {}, + config: cfg, + }: { + query?: string + variables?: FacetVariables + config?: Partial + preview?: boolean + } = {}): Promise<{ facets: Facet[] | any[] }> { + const config = commerce.getConfig(cfg) + const variables = { + input: { + take: vars.first, + groupByFacet: true, + }, + } + const { data } = await config.fetch(query, { + variables, + }) + + return { + facets: data.facets.items, + } + } + + return getAllFacets +} diff --git a/framework/vendure/api/operations/get-all-products.ts b/framework/vendure/api/operations/get-all-products.ts index 68d4ce9b7..1f558a7cb 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 } +export type ProductVariables = { first?: number, facetValueIds?: string[] } export default function getAllProductsOperation({ commerce, @@ -30,6 +30,7 @@ export default function getAllProductsOperation({ const variables = { input: { take: vars.first, + facetValueIds: vars.facetValueIds, groupByProduct: true, }, } diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index b0b0170d7..c5c3e8e89 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -1,3 +1,4 @@ +import { FacetValue } from './schema.d'; export type Maybe = T | null export type Exact = { [K in keyof T]: T[K] @@ -93,6 +94,10 @@ export type QueryProductsArgs = { options?: Maybe } +export type QueryFacetsArgs = { + options?: Maybe +} + export type QuerySearchArgs = { input: SearchInput } @@ -2727,6 +2732,13 @@ export type ProductListOptions = { filter?: Maybe } +export type FacetListOptions = { + skip?: Maybe + take?: Maybe + sort?: Maybe + filter?: Maybe +} + export type UpdateOrderItemsResult = | Order | OrderModificationError @@ -2884,6 +2896,23 @@ export type ProductVariantSortParameter = { discountPrice?: Maybe } + +export type FacetFilterParameter = { + createdAt?: Maybe + updatedAt?: Maybe + languageCode?: Maybe + name?: Maybe + code?: Maybe +} + +export type FacetSortParameter = { + id?: Maybe + createdAt?: Maybe + updatedAt?: Maybe + name?: Maybe + code?: Maybe +} + export type CustomerFilterParameter = { createdAt?: Maybe updatedAt?: Maybe @@ -3008,7 +3037,9 @@ export type CartFragment = { __typename?: 'Order' } & Pick< export type SearchResultFragment = { __typename?: 'SearchResult' } & Pick< SearchResult, - 'productId' | 'productName' | 'description' | 'slug' | 'sku' | 'currencyCode' + 'productId' | 'sku' | 'productName' | 'description' | 'slug' | 'sku' | 'currencyCode' + | 'productAsset' | 'price' | 'priceWithTax' | 'currencyCode' + | 'collectionIds' | 'facetValueIds' | 'collectionIds' > & { productAsset?: Maybe< { __typename?: 'SearchResultAsset' } & Pick< @@ -3192,6 +3223,23 @@ export type GetAllProductsQuery = { __typename?: 'Query' } & { } } +export type GetAllFacetsQuery = { __typename?: 'Query' } & { + facets: { __typename?: 'FacetList' } & { + items: Array< + { __typename?: 'Facet' } & Pick< + Facet, + 'id' | 'name' | 'code' + > & { + parent?: Maybe<{ __typename?: 'Facet' } & Pick> + children?: Maybe< + Array<{ __typename?: 'Facet' } & Pick> + > + } + >, + 'totalItems' + } +} + export type ActiveOrderQueryVariables = Exact<{ [key: string]: never }> export type ActiveOrderQuery = { __typename?: 'Query' } & { diff --git a/framework/vendure/utils/fragments/search-result-fragment.ts b/framework/vendure/utils/fragments/search-result-fragment.ts index 6155b5b47..d2d82f42e 100644 --- a/framework/vendure/utils/fragments/search-result-fragment.ts +++ b/framework/vendure/utils/fragments/search-result-fragment.ts @@ -19,6 +19,8 @@ export const searchResultFragment = /* GraphQL */ ` min max } - } + }, + facetValueIds, + collectionIds, } ` diff --git a/framework/vendure/utils/normalize.ts b/framework/vendure/utils/normalize.ts index 09c1c6e42..a790aa8cd 100644 --- a/framework/vendure/utils/normalize.ts +++ b/framework/vendure/utils/normalize.ts @@ -1,22 +1,24 @@ -import { Product } from '@commerce/types/product' import { Cart } from '@commerce/types/cart' +import { ProductCard } from '@commerce/types/product' import { CartFragment, SearchResultFragment } from '../schema' -export function normalizeSearchResult(item: SearchResultFragment): Product { +export function normalizeSearchResult(item: SearchResultFragment): ProductCard { return { id: item.productId, name: item.productName, - description: item.description, slug: item.slug, - path: item.slug, - images: [{ url: item.productAsset?.preview + '?w=800&mode=crop' || '' }], - variants: [], - price: { - value: (item.priceWithTax as any).min / 100, - currencyCode: item.currencyCode, - }, - options: [], - sku: item.sku, + imageSrc: item.productAsset?.preview ? item.productAsset?.preview + '?w=800&mode=crop' : '', + price: (item.priceWithTax as any).min / 100, + currencyCode: item.currencyCode, + facetValueIds: item.facetValueIds, + collectionIds: item.collectionIds, + + // TODO: + // oldPrice: item.price + // discount + // isNotSell + // weight + // category } } diff --git a/framework/vendure/utils/queries/get-all-facets-query.ts b/framework/vendure/utils/queries/get-all-facets-query.ts new file mode 100644 index 000000000..906507c69 --- /dev/null +++ b/framework/vendure/utils/queries/get-all-facets-query.ts @@ -0,0 +1,17 @@ +export const getAllFacetsQuery = /* GraphQL */ ` +query facets ($options: FacetListOptions) { + facets (options: $options){ + totalItems, + items { + id + name + code + values { + id + name + code + } + } + } +} +` diff --git a/pages/index.tsx b/pages/index.tsx index 3fa86079d..589c7ae30 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,19 +1,34 @@ +import { ProductCard } from '@commerce/types/product'; +import { ProductVariables } from '@framework/api/operations/get-all-products'; +import { FacetValue } from '@framework/schema'; +import commerce from '@lib/api/commerce'; +import { GetStaticPropsContext } from 'next'; import { Layout } from 'src/components/common'; -import { FeaturedProductsCarousel, HomeBanner, HomeCategories, HomeCollection, HomeCTA, HomeFeature, HomeRecipe, HomeSubscribe, HomeVideo } from 'src/components/modules/home'; +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 { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED } from 'src/utils/constanst.utils'; +import { getAllFacetValueIdsByParentCode, getAllFacetValuesForFeatuedProducts, getFreshFacetId } from 'src/utils/funtion.utils'; -export default function Home() { +interface Props { + featuredAndDiscountFacetsValue: FacetValue[], + freshProducts: ProductCard[], + featuredProducts: ProductCard[], + +} +export default function Home({ featuredAndDiscountFacetsValue, + freshProducts, featuredProducts }: Props) { return ( <> + - - + + - + {/* // todo: uncomment @@ -22,4 +37,67 @@ export default function Home() { ) } + +export async function getStaticProps({ + preview, + locale, + locales, +}: GetStaticPropsContext) { + const config = { locale, locales } + const { facets } = await commerce.getAllFacets({ + variables: {}, + config, + preview, + }) + const featuredAndDiscountFacetsValue = getAllFacetValuesForFeatuedProducts(facets) + + + // fresh products + const freshProductvariables: ProductVariables = {} + const freshFacetId = getFreshFacetId(facets) + if (freshFacetId) { + freshProductvariables.facetValueIds = [freshFacetId] + } + const freshProductsPromise = commerce.getAllProducts({ + variables: freshProductvariables, + config, + preview, + }) + + // featured products + const allFeaturedFacetIds = getAllFacetValueIdsByParentCode(facets, CODE_FACET_FEATURED) + const allDiscountFacetIds = getAllFacetValueIdsByParentCode(facets, CODE_FACET_DISCOUNT) + const facetValueIdsForFeaturedProducts = [...allFeaturedFacetIds, ...allDiscountFacetIds] + const featuredProductsPromise = commerce.getAllProducts({ + variables: { + facetValueIds: facetValueIdsForFeaturedProducts + }, + config, + preview, + }) + + + try { + const rs = await Promise.all([ + freshProductsPromise, + featuredProductsPromise, + ]) + + return { + props: { + featuredAndDiscountFacetsValue, + freshProducts: freshFacetId ? rs[0].products : [], + featuredProducts: facetValueIdsForFeaturedProducts.length > 0 ? rs[1].products : [] + }, + revalidate: 60, + } + } catch (err) { + + } + + + +} + + Home.Layout = Layout diff --git a/pages/product/[slug].tsx b/pages/product/[slug].tsx index ab9a1c17c..a8e925df9 100644 --- a/pages/product/[slug].tsx +++ b/pages/product/[slug].tsx @@ -4,6 +4,7 @@ import { ProductInfoDetail, ReleventProducts, ViewedProducts } from 'src/compone import { BLOGS_DATA_TEST, INGREDIENT_DATA_TEST, RECIPE_DATA_TEST } from 'src/utils/demo-data' export default function Slug() { + return <> diff --git a/pages/test.tsx b/pages/test.tsx index b60fe63c7..6244c3dd6 100644 --- a/pages/test.tsx +++ b/pages/test.tsx @@ -1,18 +1,51 @@ -import { Layout } from 'src/components/common' -import { useMessage } from 'src/components/contexts' - -export default function Test() { - const { showMessageError } = useMessage() - - const handleClick = () => { - showMessageError("Create account successfully") - } +import commerce from '@lib/api/commerce'; +import { GetStaticPropsContext } from 'next'; +import { Layout } from 'src/components/common'; +interface Props { + products: any +} +export default function Home({ products }: Props) { return ( <> - +

+ TOTAL: {products?.length} +

+ {JSON.stringify(products[0])} ) } -Test.Layout = Layout + +export async function getServerSideProps({ + preview, + locale, + locales, +}: GetStaticPropsContext) { + const config = { locale, locales } + const productsPromise = commerce.getAllProducts({ + // const productsPromise = commerce.getAllFacets({ + variables: { + first: 70, + // filter: { + // name: { + // contains: 'ca' + // } + // } + }, + config, + preview, + // Saleor provider only + ...({ featured: true } as any), + }) + + const { products } = await productsPromise + + + return { + props: { products }, + } +} + + +Home.Layout = Layout diff --git a/public/assets/images/default_img.jpg b/public/assets/images/default_img.jpg new file mode 100644 index 000000000..f72d03596 Binary files /dev/null and b/public/assets/images/default_img.jpg differ diff --git a/src/components/common/FeaturedProductCard/FeaturedProductCard.module.scss b/src/components/common/FeaturedProductCard/FeaturedProductCard.module.scss index 036e84629..3f95f92da 100644 --- a/src/components/common/FeaturedProductCard/FeaturedProductCard.module.scss +++ b/src/components/common/FeaturedProductCard/FeaturedProductCard.module.scss @@ -21,6 +21,9 @@ width: 24rem; height: 24rem; } + img { + object-fit: contain; + } } .right{ margin-left: 1.2rem; diff --git a/src/components/common/FeaturedProductCard/FeaturedProductCard.tsx b/src/components/common/FeaturedProductCard/FeaturedProductCard.tsx index a82b6857b..23b9ac987 100644 --- a/src/components/common/FeaturedProductCard/FeaturedProductCard.tsx +++ b/src/components/common/FeaturedProductCard/FeaturedProductCard.tsx @@ -1,39 +1,55 @@ +import { ProductCard } from '@commerce/types/product' +import { Facet, FacetValue } from '@framework/schema' +import Link from 'next/link' import React from 'react' -import { FeaturedProductProps } from 'src/utils/types.utils' -import s from './FeaturedProductCard.module.scss' -import { LANGUAGE } from '../../../utils/language.utils' -import ButtonIconBuy from '../ButtonIconBuy/ButtonIconBuy' -import ButtonCommon from '../ButtonCommon/ButtonCommon' +import { ROUTE } from 'src/utils/constanst.utils' import { ImgWithLink } from '..' -export interface FeaturedProductCardProps extends FeaturedProductProps { - buttonText?: string +import { LANGUAGE } from '../../../utils/language.utils' +import ButtonCommon from '../ButtonCommon/ButtonCommon' +import ButtonIconBuy from '../ButtonIconBuy/ButtonIconBuy' +import s from './FeaturedProductCard.module.scss' +export interface FeaturedProductCardProps extends ProductCard { + buttonText?: string, + subText?: string, } const FeaturedProductCard = ({ imageSrc, - title, - subTitle, + name, + slug, price, - originPrice, + subText, + currencyCode, buttonText = LANGUAGE.BUTTON_LABEL.BUY_NOW, }: FeaturedProductCardProps) => { + + return (
- + + + + +
-
{title}
-
{subTitle}
+ + +
{name}
+
+ +
{subText}
-
{price}
-
{originPrice}
+
{price} {currencyCode}
+ {/* TODO: */} + {/*
{originPrice}
*/}
- +
{buttonText} diff --git a/src/components/common/ImgWithLink/ImgWithLink.tsx b/src/components/common/ImgWithLink/ImgWithLink.tsx index 4f61946e0..a31a14832 100644 --- a/src/components/common/ImgWithLink/ImgWithLink.tsx +++ b/src/components/common/ImgWithLink/ImgWithLink.tsx @@ -1,7 +1,7 @@ import React from 'react' import s from './ImgWithLink.module.scss' import Image from 'next/image' -import { BLUR_DATA_IMG } from 'src/utils/constanst.utils' +import { BLUR_DATA_IMG, DEFAULT_IMG } from 'src/utils/constanst.utils' export interface ImgWithLinkProps { src: string, @@ -12,7 +12,7 @@ export interface ImgWithLinkProps { const ImgWithLink = ({ src, alt, blurDataURL = BLUR_DATA_IMG }: ImgWithLinkProps) => { return (
- {alt}
- -
- -
+ + +
+ +
+
+ { + category &&
{category}
+ }
- -
{name}
+ + +
{name}
+
{weight}
-
{price}
+
{price} {currencyCode}
@@ -80,4 +89,4 @@ const ProductCard = ({ ) } -export default ProductCard +export default ProductCardComponent diff --git a/src/components/hooks/facets/index.ts b/src/components/hooks/facets/index.ts new file mode 100644 index 000000000..f039373e3 --- /dev/null +++ b/src/components/hooks/facets/index.ts @@ -0,0 +1,3 @@ +export { default as useFacets } from './useFacets' + + diff --git a/src/components/hooks/facets/useFacets.tsx b/src/components/hooks/facets/useFacets.tsx new file mode 100644 index 000000000..c9a4e85ab --- /dev/null +++ b/src/components/hooks/facets/useFacets.tsx @@ -0,0 +1,11 @@ +import { GetAllFacetsQuery, QueryFacetsArgs } from '@framework/schema' +import { getAllFacetsQuery } from '@framework/utils/queries/get-all-facets-query' +import gglFetcher from 'src/utils/gglFetcher' +import useSWR from 'swr' + +const useFacets = (options?: QueryFacetsArgs) => { + const { data, isValidating, ...rest } = useSWR([getAllFacetsQuery, options], gglFetcher) + return { items: data?.facets.items, totalItems: data?.facets.totalItems, loading: isValidating, ...rest } +} + +export default useFacets diff --git a/src/components/modules/home/FeaturedProductsCarousel/FeaturedProductsCarousel.tsx b/src/components/modules/home/FeaturedProductsCarousel/FeaturedProductsCarousel.tsx index 452427616..66865194b 100644 --- a/src/components/modules/home/FeaturedProductsCarousel/FeaturedProductsCarousel.tsx +++ b/src/components/modules/home/FeaturedProductsCarousel/FeaturedProductsCarousel.tsx @@ -1,92 +1,89 @@ -import React from 'react' +import { FacetValue } from '@framework/schema' +import React, { useMemo } from 'react' import { ResponsiveType } from 'react-multi-carousel' -import { CarouselCommon, FeaturedProductCard,HeadingCommon} from 'src/components/common' +import { CarouselCommon, FeaturedProductCard, HeadingCommon } from 'src/components/common' import { FeaturedProductCardProps } from 'src/components/common/FeaturedProductCard/FeaturedProductCard' +import { getFacetNamesFromIds } from 'src/utils/funtion.utils' import s from "./FeaturedProductsCarousel.module.scss" interface FeaturedProductsCarouselProps { - title?: string + data: FeaturedProductCardProps[] + featuredFacetsValue: FacetValue[], } -const dataDemo:FeaturedProductCardProps[] = [{ - title: "Sale 25% Coffee Bean", - subTitle: "50 first Orders within a day", - originPrice: "$20.00", - price: "$14.00", - imageSrc: "https://user-images.githubusercontent.com/76099413/133043628-db7813f9-1bb7-4ee1-b028-dc4295563494.png" -},{ - title: "Sale 20% Fruits", - subTitle: "50 first Orders within a day", - originPrice: "$20.00", - price: "$14.00", - imageSrc: "https://user-images.githubusercontent.com/76099413/133043630-07a353b9-573d-4c1d-b1de-2c932e3f14f7.png" -},{ - title: "Sale 25% Coffee Bean", - subTitle: "50 first Orders within a day", - originPrice: "$20.00", - price: "$14.00", - imageSrc: "https://user-images.githubusercontent.com/76099413/133043633-954c105b-c703-4e5c-8f5f-7943ad633ff0.png" -}] - const RESPONSIVE: ResponsiveType = { - hugeScreen: { - breakpoint: { max: 9999, min: 1500 }, - items: 2.25, - slidesToSlide: 1, // optional, default to 1. - }, - largeScreen: { - breakpoint: { max: 1500, min: 1440 }, - items: 2.075, - slidesToSlide: 1, // optional, default to 1. - }, - largeDesktop: { - breakpoint: { max: 1440, min: 1280 }, - items: 1.75, - slidesToSlide: 1, // optional, default to 1. - }, - desktop: { - breakpoint: { max: 1280, min: 1148 }, - items: 1.5, - slidesToSlide: 1, // optional, default to 1. - }, - smallDesktop: { - breakpoint: { max: 1148, min: 1024 }, - items: 1.375, - slidesToSlide: 1, // optional, default to 1. - }, - lap: { - breakpoint: { max: 1024, min: 968 }, - items: 1.7, - }, - tablet: { - breakpoint: { max: 968, min: 768 }, - items: 1.075, - }, - smallTablet: { - breakpoint: { max: 768, min: 640 }, - items: 1.25, - }, - largeMobile: { - breakpoint: { max: 640, min: 400 }, - items: 1.275, - }, - mobile: { - breakpoint: { max: 400, min: 300 }, - items: 1.1, - }, - smallMobile: { - breakpoint: { max: 300, min: 0 }, - items: 1, - }, - } +const RESPONSIVE: ResponsiveType = { + hugeScreen: { + breakpoint: { max: 9999, min: 1500 }, + items: 2.25, + slidesToSlide: 1, // optional, default to 1. + }, + largeScreen: { + breakpoint: { max: 1500, min: 1440 }, + items: 2.075, + slidesToSlide: 1, // optional, default to 1. + }, + largeDesktop: { + breakpoint: { max: 1440, min: 1280 }, + items: 1.75, + slidesToSlide: 1, // optional, default to 1. + }, + desktop: { + breakpoint: { max: 1280, min: 1148 }, + items: 1.5, + slidesToSlide: 1, // optional, default to 1. + }, + smallDesktop: { + breakpoint: { max: 1148, min: 1024 }, + items: 1.375, + slidesToSlide: 1, // optional, default to 1. + }, + lap: { + breakpoint: { max: 1024, min: 968 }, + items: 1.7, + }, + tablet: { + breakpoint: { max: 968, min: 768 }, + items: 1.075, + }, + smallTablet: { + breakpoint: { max: 768, min: 640 }, + items: 1.25, + }, + largeMobile: { + breakpoint: { max: 640, min: 400 }, + items: 1.275, + }, + mobile: { + breakpoint: { max: 400, min: 300 }, + items: 1.1, + }, + smallMobile: { + breakpoint: { max: 300, min: 0 }, + items: 1, + }, +} -const FeaturedProductsCarousel = ({title="Featured Products"}: FeaturedProductsCarouselProps) => { - return ( -
-
- {title} -
- data={dataDemo} Component={FeaturedProductCard} itemKey="featured-products" responsive={RESPONSIVE}/> -
- ) +const FeaturedProductsCarousel = ({ data, featuredFacetsValue }: FeaturedProductsCarouselProps) => { + const featuredProducts = useMemo(() => { + return data.map(item => { + return { + ...item, + subText: getFacetNamesFromIds(featuredFacetsValue, item.facetValueIds) + } + }) + }, [data, featuredFacetsValue]) + return ( +
+
+ Featured Products +
+ + data={featuredProducts} + defaultComponentProps={featuredFacetsValue} + Component={FeaturedProductCard} + itemKey="featured-products" + responsive={RESPONSIVE} /> +
+ ) } export default FeaturedProductsCarousel diff --git a/src/components/modules/home/FreshProducts/FreshProducts.tsx b/src/components/modules/home/FreshProducts/FreshProducts.tsx new file mode 100644 index 000000000..33b872032 --- /dev/null +++ b/src/components/modules/home/FreshProducts/FreshProducts.tsx @@ -0,0 +1,27 @@ +import { ProductCard } from '@commerce/types/product' +import { Product } from '@framework/schema' +import React from 'react' +import { CollectionCarcousel } from '..' +interface FreshProductsProps { + data: ProductCard[] +} + +const FreshProducts = ({ data }: FreshProductsProps) => { + if (data.length === 0) { + return null + } + return ( +
+ +
+ ) +} + +export default FreshProducts diff --git a/src/components/modules/home/HomeCollection/HomeCollection.tsx b/src/components/modules/home/HomeCollection/HomeCollection.tsx index bd1cd33d6..98ab5624a 100644 --- a/src/components/modules/home/HomeCollection/HomeCollection.tsx +++ b/src/components/modules/home/HomeCollection/HomeCollection.tsx @@ -95,14 +95,6 @@ const dataTest = [ const HomeCollection = (props: HomeCollectionProps) => { return (
- (arr: Array, value: T): Array { - const index = arr.indexOf(value); - if (index > -1) { - arr.splice(index, 1); - } - return [...arr]; +export function removeItem(arr: Array, value: T): Array { + const index = arr.indexOf(value); + if (index > -1) { + arr.splice(index, 1); + } + return [...arr]; +} + +function findFacetByCode(code: string, facets?: Facet) { + return facets?.values.find((item: FacetValue) => item.code === code) +} + +export function getFeaturedFacetId(facets: Facet[]) { + const featuredFacet = facets.find((item: Facet) => item.code === CODE_FACET_FEATURED) + return featuredFacet?.id +} + +export function getFreshFacetId(facets: Facet[]) { + const featuredFacet = facets.find((item: Facet) => item.code === CODE_FACET_FEATURED) + const freshFacetValue = findFacetByCode(CODE_FACET_FEATURED_VARIANT.FRESH, featuredFacet) + + return freshFacetValue?.id +} + +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) + + return rs || [] +} + +export function getAllFacetValuesForFeatuedProducts(facets: Facet[]) { + const facetsRs = facets.filter((item: Facet) => item.code === CODE_FACET_FEATURED || item.code === CODE_FACET_DISCOUNT) + let rs = [] as FacetValue[] + facetsRs.map((item: Facet) => { + rs = rs.concat(item.values) + return null + }) + return rs +} + +export function getFacetNamesFromIds(facets: FacetValue[], ids?: string[]): string { + if (!ids || ids?.length === 0) { + return '' + } + + const facetItems = facets.filter((item: FacetValue) => ids.includes(item.id)) + const names = facetItems.map((item: FacetValue) => item.name) + return names.join(", ") } \ No newline at end of file