diff --git a/commerce.config.json b/commerce.config.json
index ad72b58de..6fb526aaf 100644
--- a/commerce.config.json
+++ b/commerce.config.json
@@ -2,8 +2,8 @@
"features": {
"cart": true,
"search": true,
- "wishlist": false,
- "customerAuth": false,
- "customCheckout": false
+ "wishlist": true,
+ "customerAuth": true,
+ "customCheckout": true
}
}
diff --git a/framework/commerce/api/operations.ts b/framework/commerce/api/operations.ts
index 2910a2d82..ca9b325c2 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'
@@ -9,6 +10,7 @@ import type {
GetProductOperation,
} from '../types/product'
import type { APIProvider, CommerceAPI } from '.'
+import { GetAllCollectionsOperation } from '@commerce/types/collection';
const noop = () => {
throw new Error('Not implemented')
@@ -23,6 +25,9 @@ export const OPERATIONS = [
'getAllProductPaths',
'getAllProducts',
'getProduct',
+ 'getAllFacets',
+ 'getAllCollections',
+
] as const
export const defaultOperations = OPERATIONS.reduce((ops, k) => {
@@ -154,8 +159,43 @@ 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
+ }
+
+ getAllCollections: {
+ (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..3c7f05b7a 100644
--- a/framework/commerce/new-provider.md
+++ b/framework/commerce/new-provider.md
@@ -15,6 +15,8 @@ Adding a commerce provider means adding a new folder in `framework` with a folde
- useSearch
- getProduct
- getAllProducts
+ - getAllFacets
+ - getAllCollections
- `wishlist`
- useWishlist
- useAddItem
diff --git a/framework/commerce/types/collection.ts b/framework/commerce/types/collection.ts
new file mode 100644
index 000000000..3ccb72ea3
--- /dev/null
+++ b/framework/commerce/types/collection.ts
@@ -0,0 +1,54 @@
+import { Asset } from '../../vendure/schema.d';
+
+export type Collection = {
+ id: string
+ name: string
+ slug: string
+ description: string
+ featuredAsse: Asset
+ asset: Asset[]
+}
+
+export type SearchCollectionsBody = {
+ search?: string
+ sort?: string
+ locale?: string
+}
+
+export type CollectionTypes = {
+ collection: Collection
+ searchBody: SearchCollectionsBody
+}
+
+export type SearchCollectionsHook = {
+ data: {
+ collections: T['collection'][]
+ found: boolean
+ }
+ body: T['searchBody']
+ input: T['searchBody']
+ fetcherInput: T['searchBody']
+}
+
+export type CollectionsSchema = {
+ endpoint: {
+ options: {}
+ handlers: {
+ getCollections: SearchCollectionsHook
+ }
+ }
+}
+
+
+export type GetAllCollectionsOperation = {
+ data: { collections: T['collection'][] }
+ variables: {
+ ids?: string[]
+ first?: number
+ }
+}
+
+export type GetCollectionOperation = {
+ data: { collection?: T['collection'] }
+ variables: { code: string; } | { code?: never; }
+}
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..e1a8da200 100644
--- a/framework/commerce/types/product.ts
+++ b/framework/commerce/types/product.ts
@@ -1,3 +1,6 @@
+import { CurrencyCode } from './../../vendure/schema.d';
+import { FacetValueFilterInput, LogicalOperator, SearchResultSortParameter } from "@framework/schema"
+
export type ProductImage = {
url: string
alt?: string
@@ -40,11 +43,26 @@ 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[],
+ collection?: string,
+ isNotSell?: boolean
+}
+
export type SearchProductsBody = {
search?: string
categoryId?: string | number
@@ -79,17 +97,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..95ec47d66 100644
--- a/framework/vendure/api/index.ts
+++ b/framework/vendure/api/index.ts
@@ -1,15 +1,17 @@
-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 getAllCollections from './operations/get-all-collection'
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 +42,8 @@ const operations = {
getAllProductPaths,
getAllProducts,
getProduct,
+ getAllFacets,
+ getAllCollections,
}
export const provider = { config, operations }
diff --git a/framework/vendure/api/operations/get-all-collection.ts b/framework/vendure/api/operations/get-all-collection.ts
new file mode 100644
index 000000000..b7cc3a725
--- /dev/null
+++ b/framework/vendure/api/operations/get-all-collection.ts
@@ -0,0 +1,45 @@
+import { OperationContext } from '@commerce/api/operations'
+import { Collection } from '@commerce/types/collection'
+import { Provider, VendureConfig } from '..'
+import { GetAllCollectionsQuery } from '../../schema'
+import { getAllCollectionsQuery } from '../../utils/queries/get-all-collections-query'
+
+export type CollectionVariables = { first?: number }
+
+export default function getAllCollectionsOperation({
+ commerce,
+}: OperationContext) {
+ async function getAllCollections(opts?: {
+ variables?: CollectionVariables
+ config?: Partial
+ preview?: boolean
+ }): Promise<{ collections: Collection[] }>
+
+ async function getAllCollections({
+ query = getAllCollectionsQuery,
+ variables: { ...vars } = {},
+ config: cfg,
+ }: {
+ query?: string
+ variables?: CollectionVariables
+ config?: Partial
+ preview?: boolean
+ } = {}): Promise<{ collections: Collection[] | any[] }> {
+ const config = commerce.getConfig(cfg)
+ const variables = {
+ input: {
+ take: vars.first,
+ groupByCollection: true,
+ },
+ }
+ const { data } = await config.fetch(query, {
+ variables,
+ })
+
+ return {
+ collections: data.collections.items,
+ }
+ }
+
+ return getAllCollections
+}
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 91be7742d..709b1f48b 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
}
@@ -2730,6 +2735,13 @@ export type ProductListOptions = {
filter?: Maybe
}
+export type FacetListOptions = {
+ skip?: Maybe
+ take?: Maybe
+ sort?: Maybe
+ filter?: Maybe
+}
+
export type UpdateOrderItemsResult =
| Order
| OrderModificationError
@@ -2887,6 +2899,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
@@ -3011,7 +3040,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<
@@ -3195,6 +3226,40 @@ 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 GetAllCollectionsQuery = { __typename?: 'Query' } & {
+ collections: { __typename?: 'CollectionList' } & {
+ items: Array<
+ { __typename?: 'Collection' } & Pick<
+ Collection,
+ 'id' | 'name' | 'slug'
+ > & {
+ parent?: Maybe<{ __typename?: 'Collection' } & Pick>
+ children?: Maybe<
+ Array<{ __typename?: 'Collection' } & 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..cc76e5f97 100644
--- a/framework/vendure/utils/normalize.ts
+++ b/framework/vendure/utils/normalize.ts
@@ -1,22 +1,23 @@
-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
}
}
diff --git a/framework/vendure/utils/queries/get-all-collections-query.ts b/framework/vendure/utils/queries/get-all-collections-query.ts
new file mode 100644
index 000000000..359c81ea9
--- /dev/null
+++ b/framework/vendure/utils/queries/get-all-collections-query.ts
@@ -0,0 +1,12 @@
+export const getAllCollectionsQuery = /* GraphQL */ `
+query collections ($options: CollectionListOptions) {
+ collections (options: $options){
+ totalItems,
+ items {
+ id
+ name
+ slug
+ }
+ }
+}
+`
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..cac464a43 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -1,19 +1,37 @@
+import { ProductCard } from '@commerce/types/product';
+import { ProductVariables } from '@framework/api/operations/get-all-products';
+import { Collection, 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, getAllPromies, getFreshFacetId } from 'src/utils/funtion.utils';
+import { PromiseWithKey } from 'src/utils/types.utils';
-export default function Home() {
+interface Props {
+ featuredAndDiscountFacetsValue: FacetValue[],
+ freshProducts: ProductCard[],
+ featuredProducts: ProductCard[],
+ collections: Collection[]
+
+}
+export default function Home({ featuredAndDiscountFacetsValue,
+ freshProducts, featuredProducts,
+ collections }: Props) {
return (
<>
+
-
-
+
+
-
+
{/* // todo: uncomment
@@ -22,4 +40,76 @@ export default function Home() {
)
}
+
+export async function getStaticProps({
+ preview,
+ locale,
+ locales,
+}: GetStaticPropsContext) {
+ const config = { locale, locales }
+ let promisesWithKey = [] as PromiseWithKey[]
+ let props = {} as any
+
+ const { facets } = await commerce.getAllFacets({
+ variables: {},
+ config,
+ preview,
+ })
+ props.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,
+ })
+ promisesWithKey.push({ key: 'freshProducts', promise: freshProductsPromise, keyResult: 'products' })
+
+
+ // 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,
+ })
+ promisesWithKey.push({ key: 'featuredProducts', promise: featuredProductsPromise, keyResult: 'products' })
+
+ // collection
+ const collectionsPromise = commerce.getAllCollections({
+ variables: {},
+ config,
+ preview,
+ })
+ promisesWithKey.push({ key: 'collections', promise: collectionsPromise, keyResult: 'collections' })
+
+
+ try {
+ const promises = getAllPromies(promisesWithKey)
+ const rs = await Promise.all(promises)
+
+ promisesWithKey.map((item, index) => {
+ props[item.key] = item.keyResult ? rs[index][item.keyResult] : rs[index]
+ return null
+ })
+
+ return {
+ props,
+ 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 (
-
{
+ children?: React.ReactNode
size?: 'default' | 'large'
shape?: 'half' | 'round' | 'default'
type?: 'default' | 'discount' | 'waiting' | 'delivering' | 'delivered'
diff --git a/src/components/common/ProductCard/ProductCard.tsx b/src/components/common/ProductCard/ProductCard.tsx
index 715a30239..4761aac92 100644
--- a/src/components/common/ProductCard/ProductCard.tsx
+++ b/src/components/common/ProductCard/ProductCard.tsx
@@ -1,8 +1,8 @@
+import { ProductCard } from '@commerce/types/product'
import Link from 'next/link'
import React from 'react'
import { IconBuy } from 'src/components/icons'
import { ROUTE } from 'src/utils/constanst.utils'
-import { ProductProps } from 'src/utils/types.utils'
import { ImgWithLink } from '..'
import ButtonCommon from '../ButtonCommon/ButtonCommon'
import ButtonIconBuy from '../ButtonIconBuy/ButtonIconBuy'
@@ -11,16 +11,18 @@ import LabelCommon from '../LabelCommon/LabelCommon'
import s from './ProductCard.module.scss'
import ProductNotSell from './ProductNotSell/ProductNotSell'
-export interface ProductCardProps extends ProductProps {
+export interface ProductCardProps extends ProductCard {
buttonText?: string
isSingleButton?: boolean,
}
-const ProductCard = ({
- category,
+const ProductCardComponent = ({
+ collection,
name,
+ slug,
weight,
price,
+ currencyCode,
buttonText = 'Buy Now',
imageSrc,
isNotSell,
@@ -35,24 +37,31 @@ const ProductCard = ({
return (
-
-
+
+
+
+
+ {
+ collection &&
- {category}
+ {collection}
+ }
-
{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/CollectionCarcousel/CollectionCarcousel.tsx b/src/components/modules/home/CollectionCarcousel/CollectionCarcousel.tsx
index 3007624db..5dccb1052 100644
--- a/src/components/modules/home/CollectionCarcousel/CollectionCarcousel.tsx
+++ b/src/components/modules/home/CollectionCarcousel/CollectionCarcousel.tsx
@@ -12,7 +12,7 @@ interface ColectionCarcouselProps extends CollectionHeadingProps {
data: ProductCardProps[]
itemKey: string
viewAllLink?: string,
- category:string
+ category?: string
}
const ColectionCarcousel = ({
@@ -21,7 +21,8 @@ const ColectionCarcousel = ({
title,
subtitle,
type,
- category
+ category,
+ viewAllLink = ROUTE.PRODUCTS,
}: ColectionCarcouselProps) => {
return (
@@ -34,7 +35,7 @@ const ColectionCarcousel = ({
>
-
+
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..cf773d495
--- /dev/null
+++ b/src/components/modules/home/FreshProducts/FreshProducts.tsx
@@ -0,0 +1,47 @@
+import { ProductCard } from '@commerce/types/product'
+import { Collection } from '@framework/schema'
+import React, { useMemo } from 'react'
+import { OPTION_ALL, QUERY_KEY, ROUTE } from 'src/utils/constanst.utils'
+import { CollectionCarcousel } from '..'
+interface FreshProductsProps {
+ data: ProductCard[]
+ collections: Collection[]
+}
+
+const getCategoryNameFromCollectionId = (colelctions: Collection[], collectionId?: string ) => {
+ if (!collectionId) {
+ return ''
+ }
+
+ const collection = colelctions.find(item => item.id === collectionId)
+ return collection?.name || ''
+}
+
+const FreshProducts = ({ data, collections }: FreshProductsProps) => {
+ const dataWithCategory = useMemo(() => {
+ return data.map(item => {
+ return {
+ ...item,
+ collection: getCategoryNameFromCollectionId(collections, item.collectionIds ? item.collectionIds[0] : undefined)
+ }
+ })
+ }, [data, collections])
+
+ 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];
-}
\ No newline at end of file
+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(", ")
+}
+
+export function getAllPromies (promies: PromiseWithKey[]) {
+ return promies.map(item => item.promise)
+}
diff --git a/src/utils/types.utils.ts b/src/utils/types.utils.ts
index e2ce516d4..ca21b605f 100644
--- a/src/utils/types.utils.ts
+++ b/src/utils/types.utils.ts
@@ -50,4 +50,10 @@ export type filterContextType = {
visible: boolean;
open: () => void;
close: () => void;
-};
\ No newline at end of file
+};
+
+export type PromiseWithKey = {
+ key: string
+ promise: PromiseLike
+ keyResult?: string,
+}