mirror of
https://github.com/vercel/commerce.git
synced 2025-07-23 04:36:49 +00:00
Merge branch 'feature/m2-featured-product' of github.com:KieIO/grocery-vercel-commerce into feature/m2-add-product-to-cart
This commit is contained in:
@@ -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<P extends APIProvider> = {
|
||||
} & OperationOptions
|
||||
): Promise<T['data']>
|
||||
}
|
||||
|
||||
getAllFacets: {
|
||||
<T extends GetAllFacetsOperation>(opts: {
|
||||
variables?: T['variables']
|
||||
config?: P['config']
|
||||
preview?: boolean
|
||||
}): Promise<T['data']>
|
||||
|
||||
<T extends GetAllFacetsOperation>(
|
||||
opts: {
|
||||
variables?: T['variables']
|
||||
config?: P['config']
|
||||
preview?: boolean
|
||||
} & OperationOptions
|
||||
): Promise<T['data']>
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
export type APIOperations<P extends APIProvider> = {
|
||||
[K in keyof Operations<P>]?: (ctx: OperationContext<P>) => Operations<P>[K]
|
||||
}
|
||||
|
@@ -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
|
||||
|
52
framework/commerce/types/facet.ts
Normal file
52
framework/commerce/types/facet.ts
Normal file
@@ -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<T extends FacetTypes = FacetTypes> = {
|
||||
data: {
|
||||
facets: T['facet'][]
|
||||
found: boolean
|
||||
}
|
||||
body: T['searchBody']
|
||||
input: T['searchBody']
|
||||
fetcherInput: T['searchBody']
|
||||
}
|
||||
|
||||
export type FacetsSchema<T extends FacetTypes = FacetTypes> = {
|
||||
endpoint: {
|
||||
options: {}
|
||||
handlers: {
|
||||
getFacets: SearchFacetsHook<T>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export type GetAllFacetsOperation<T extends FacetTypes = FacetTypes> = {
|
||||
data: { facets: T['facet'][] }
|
||||
variables: {
|
||||
ids?: string[]
|
||||
first?: number
|
||||
}
|
||||
}
|
||||
|
||||
export type GetFacetOperation<T extends FacetTypes = FacetTypes> = {
|
||||
data: { facet?: T['facet'] }
|
||||
variables: { code: string; } | { code?: never; }
|
||||
}
|
@@ -1,3 +1,5 @@
|
||||
import { FacetValueFilterInput, LogicalOperator, SearchResultSortParameter } from "@framework/schema"
|
||||
|
||||
export type ProductImage = {
|
||||
url: string
|
||||
alt?: string
|
||||
@@ -40,7 +42,6 @@ export type Product = {
|
||||
slug?: string
|
||||
path?: string
|
||||
images: ProductImage[]
|
||||
variants: ProductVariant[]
|
||||
price: ProductPrice
|
||||
options: ProductOption[]
|
||||
}
|
||||
@@ -87,9 +88,16 @@ export type GetAllProductPathsOperation<
|
||||
export type GetAllProductsOperation<T extends ProductTypes = ProductTypes> = {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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 }
|
||||
|
45
framework/vendure/api/operations/get-all-facets.ts
Normal file
45
framework/vendure/api/operations/get-all-facets.ts
Normal file
@@ -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<Provider>) {
|
||||
async function getAllFacets(opts?: {
|
||||
variables?: FacetVariables
|
||||
config?: Partial<VendureConfig>
|
||||
preview?: boolean
|
||||
}): Promise<{ facets: Facet[] }>
|
||||
|
||||
async function getAllFacets({
|
||||
query = getAllFacetsQuery,
|
||||
variables: { ...vars } = {},
|
||||
config: cfg,
|
||||
}: {
|
||||
query?: string
|
||||
variables?: FacetVariables
|
||||
config?: Partial<VendureConfig>
|
||||
preview?: boolean
|
||||
} = {}): Promise<{ facets: Facet[] | any[] }> {
|
||||
const config = commerce.getConfig(cfg)
|
||||
const variables = {
|
||||
input: {
|
||||
take: vars.first,
|
||||
groupByFacet: true,
|
||||
},
|
||||
}
|
||||
const { data } = await config.fetch<GetAllFacetsQuery>(query, {
|
||||
variables,
|
||||
})
|
||||
|
||||
return {
|
||||
facets: data.facets.items,
|
||||
}
|
||||
}
|
||||
|
||||
return getAllFacets
|
||||
}
|
@@ -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,
|
||||
},
|
||||
}
|
||||
|
49
framework/vendure/schema.d.ts
vendored
49
framework/vendure/schema.d.ts
vendored
@@ -93,6 +93,10 @@ export type QueryProductsArgs = {
|
||||
options?: Maybe<ProductListOptions>
|
||||
}
|
||||
|
||||
export type QueryFacetsArgs = {
|
||||
options?: Maybe<FacetListOptions>
|
||||
}
|
||||
|
||||
export type QuerySearchArgs = {
|
||||
input: SearchInput
|
||||
}
|
||||
@@ -2727,6 +2731,13 @@ export type ProductListOptions = {
|
||||
filter?: Maybe<ProductFilterParameter>
|
||||
}
|
||||
|
||||
export type FacetListOptions = {
|
||||
skip?: Maybe<Scalars['Int']>
|
||||
take?: Maybe<Scalars['Int']>
|
||||
sort?: Maybe<FacetSortParameter>
|
||||
filter?: Maybe<FacetFilterParameter>
|
||||
}
|
||||
|
||||
export type UpdateOrderItemsResult =
|
||||
| Order
|
||||
| OrderModificationError
|
||||
@@ -2884,6 +2895,23 @@ export type ProductVariantSortParameter = {
|
||||
discountPrice?: Maybe<SortOrder>
|
||||
}
|
||||
|
||||
|
||||
export type FacetFilterParameter = {
|
||||
createdAt?: Maybe<DateOperators>
|
||||
updatedAt?: Maybe<DateOperators>
|
||||
languageCode?: Maybe<StringOperators>
|
||||
name?: Maybe<StringOperators>
|
||||
code?: Maybe<StringOperators>
|
||||
}
|
||||
|
||||
export type FacetSortParameter = {
|
||||
id?: Maybe<SortOrder>
|
||||
createdAt?: Maybe<SortOrder>
|
||||
updatedAt?: Maybe<SortOrder>
|
||||
name?: Maybe<SortOrder>
|
||||
code?: Maybe<SortOrder>
|
||||
}
|
||||
|
||||
export type CustomerFilterParameter = {
|
||||
createdAt?: Maybe<DateOperators>
|
||||
updatedAt?: Maybe<DateOperators>
|
||||
@@ -3008,7 +3036,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'
|
||||
> & {
|
||||
productAsset?: Maybe<
|
||||
{ __typename?: 'SearchResultAsset' } & Pick<
|
||||
@@ -3192,6 +3222,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<Facet, 'id'>>
|
||||
children?: Maybe<
|
||||
Array<{ __typename?: 'Facet' } & Pick<Facet, 'id'>>
|
||||
>
|
||||
}
|
||||
>,
|
||||
'totalItems'
|
||||
}
|
||||
}
|
||||
|
||||
export type ActiveOrderQueryVariables = Exact<{ [key: string]: never }>
|
||||
|
||||
export type ActiveOrderQuery = { __typename?: 'Query' } & {
|
||||
|
@@ -3,18 +3,20 @@ import { Cart } from '@commerce/types/cart'
|
||||
import { CartFragment, SearchResultFragment } from '../schema'
|
||||
|
||||
export function normalizeSearchResult(item: SearchResultFragment): Product {
|
||||
const imageUrl = item.productAsset?.preview ? item.productAsset?.preview + '?w=800&mode=crop' : ''
|
||||
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: [],
|
||||
images: imageUrl ? [{ url: imageUrl }] : [],
|
||||
price: {
|
||||
// TODO: check price
|
||||
value: (item.priceWithTax as any).min / 100,
|
||||
currencyCode: item.currencyCode,
|
||||
},
|
||||
// TODO: check product option
|
||||
options: [],
|
||||
sku: item.sku,
|
||||
}
|
||||
|
17
framework/vendure/utils/queries/get-all-facets-query.ts
Normal file
17
framework/vendure/utils/queries/get-all-facets-query.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export const getAllFacetsQuery = /* GraphQL */ `
|
||||
query facets ($options: FacetListOptions) {
|
||||
facets (options: $options){
|
||||
totalItems,
|
||||
items {
|
||||
id
|
||||
name
|
||||
code
|
||||
values {
|
||||
id
|
||||
name
|
||||
code
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
@@ -1,8 +1,20 @@
|
||||
import { ProductVariables } from '@framework/api/operations/get-all-products';
|
||||
import { Product } 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 HomeSpice from 'src/components/modules/home/HomeSpice/HomeSpice';
|
||||
import { getAllFeaturedFacetId, getFreshProductFacetId } from 'src/utils/funtion.utils';
|
||||
|
||||
export default function Home() {
|
||||
interface Props {
|
||||
freshProducts: Product[],
|
||||
featuredProducts: Product[],
|
||||
|
||||
}
|
||||
export default function Home({ freshProducts, featuredProducts }: Props) {
|
||||
console.log("total: ", freshProducts.length, featuredProducts.length)
|
||||
console.log("rs: ", freshProducts, featuredProducts)
|
||||
return (
|
||||
<>
|
||||
<HomeBanner />
|
||||
@@ -22,4 +34,59 @@ 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 freshProductvariables: ProductVariables = {}
|
||||
const freshFacetId = getFreshProductFacetId(facets)
|
||||
|
||||
if (freshFacetId) {
|
||||
freshProductvariables.facetValueIds = [freshFacetId]
|
||||
}
|
||||
const freshProductsPromise = commerce.getAllProducts({
|
||||
variables: freshProductvariables,
|
||||
config,
|
||||
preview,
|
||||
})
|
||||
|
||||
const allFeaturedFacetId = getAllFeaturedFacetId(facets)
|
||||
const featuredProductsPromise = commerce.getAllProducts({
|
||||
variables: {
|
||||
facetValueIds: allFeaturedFacetId
|
||||
},
|
||||
config,
|
||||
preview,
|
||||
})
|
||||
|
||||
|
||||
try {
|
||||
const rs = await Promise.all([freshProductsPromise, featuredProductsPromise])
|
||||
|
||||
return {
|
||||
props: {
|
||||
freshProducts: rs[0].products,
|
||||
featuredProducts: rs[1].products
|
||||
},
|
||||
revalidate: 60,
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Home.Layout = Layout
|
||||
|
@@ -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 <>
|
||||
<ProductInfoDetail />
|
||||
<RecipeDetail ingredients={INGREDIENT_DATA_TEST} />
|
||||
|
@@ -1,18 +1,51 @@
|
||||
import { Layout } from 'src/components/common'
|
||||
import { useMessage } from 'src/components/contexts'
|
||||
import commerce from '@lib/api/commerce';
|
||||
import { GetStaticPropsContext } from 'next';
|
||||
import { Layout } from 'src/components/common';
|
||||
|
||||
export default function Test() {
|
||||
const { showMessageError } = useMessage()
|
||||
|
||||
const handleClick = () => {
|
||||
showMessageError("Create account successfully")
|
||||
interface Props {
|
||||
products: any
|
||||
}
|
||||
|
||||
export default function Home({ products }: Props) {
|
||||
return (
|
||||
<>
|
||||
<button onClick={handleClick}>Click me</button>
|
||||
<p>
|
||||
TOTAL: {products?.length}
|
||||
</p>
|
||||
{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
|
||||
|
3
src/components/hooks/facets/index.ts
Normal file
3
src/components/hooks/facets/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export { default as useFacets } from './useFacets'
|
||||
|
||||
|
11
src/components/hooks/facets/useFacets.tsx
Normal file
11
src/components/hooks/facets/useFacets.tsx
Normal file
@@ -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>([getAllFacetsQuery, options], gglFetcher)
|
||||
return { items: data?.facets.items, totalItems: data?.facets.totalItems, loading: isValidating, ...rest }
|
||||
}
|
||||
|
||||
export default useFacets
|
148
src/components/modules/home/FreshProducts/FreshProducts.tsx
Normal file
148
src/components/modules/home/FreshProducts/FreshProducts.tsx
Normal file
@@ -0,0 +1,148 @@
|
||||
import { Product } from '@framework/schema'
|
||||
import React from 'react'
|
||||
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 FreshProductsProps {
|
||||
data: Product[]
|
||||
}
|
||||
const dataTest = [
|
||||
{
|
||||
name: 'Tomato',
|
||||
weight: '250g',
|
||||
category: 'VEGGIE',
|
||||
price: 'Rp 27.500',
|
||||
imageSrc: image5.src,
|
||||
},
|
||||
{
|
||||
name: 'Cucumber',
|
||||
weight: '250g',
|
||||
category: 'VEGGIE',
|
||||
price: 'Rp 27.500',
|
||||
imageSrc: image6.src,
|
||||
},
|
||||
{
|
||||
name: 'Carrot',
|
||||
weight: '250g',
|
||||
category: 'VEGGIE',
|
||||
price: 'Rp 27.500',
|
||||
imageSrc: image7.src,
|
||||
},
|
||||
{
|
||||
name: 'Salad',
|
||||
weight: '250g',
|
||||
category: 'VEGGIE',
|
||||
price: 'Rp 27.500',
|
||||
imageSrc: image8.src,
|
||||
},
|
||||
{
|
||||
name: 'Tomato',
|
||||
weight: '250g',
|
||||
category: 'VEGGIE',
|
||||
price: 'Rp 27.500',
|
||||
imageSrc: image5.src,
|
||||
},
|
||||
{
|
||||
name: 'Cucumber',
|
||||
weight: '250g',
|
||||
category: 'VEGGIE',
|
||||
price: 'Rp 27.500',
|
||||
imageSrc: image6.src,
|
||||
},
|
||||
{
|
||||
name: 'Tomato',
|
||||
weight: '250g',
|
||||
category: 'VEGGIE',
|
||||
price: 'Rp 27.500',
|
||||
imageSrc: image5.src,
|
||||
},
|
||||
{
|
||||
name: 'Cucumber',
|
||||
weight: '250g',
|
||||
category: 'VEGGIE',
|
||||
price: 'Rp 27.500',
|
||||
imageSrc: image6.src,
|
||||
},
|
||||
{
|
||||
name: 'Carrot',
|
||||
weight: '250g',
|
||||
category: 'VEGGIE',
|
||||
price: 'Rp 27.500',
|
||||
imageSrc: image7.src,
|
||||
},
|
||||
{
|
||||
name: 'Salad',
|
||||
weight: '250g',
|
||||
category: 'VEGGIE',
|
||||
price: 'Rp 27.500',
|
||||
imageSrc: image8.src,
|
||||
},
|
||||
{
|
||||
name: 'Tomato',
|
||||
weight: '250g',
|
||||
category: 'VEGGIE',
|
||||
price: 'Rp 27.500',
|
||||
imageSrc: image5.src,
|
||||
},
|
||||
{
|
||||
name: 'Cucumber',
|
||||
weight: '250g',
|
||||
category: 'VEGGIE',
|
||||
price: 'Rp 27.500',
|
||||
imageSrc: image6.src,
|
||||
},
|
||||
]
|
||||
|
||||
const FreshProducts = ({data}: FreshProductsProps) => {
|
||||
return (
|
||||
<div className="w-full">
|
||||
<CollectionCarcousel
|
||||
type="highlight"
|
||||
data={data}
|
||||
itemKey="product-1"
|
||||
title="Fresh Products Today"
|
||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
||||
category={"veggie"}
|
||||
/>
|
||||
<CollectionCarcousel
|
||||
data={dataTest}
|
||||
itemKey="product-2"
|
||||
title="VEGGIE"
|
||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
||||
category={"veggie"}
|
||||
/>
|
||||
<CollectionCarcousel
|
||||
data={dataTest}
|
||||
itemKey="product-3"
|
||||
title="VEGGIE"
|
||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
||||
category={"veggie"}
|
||||
/>
|
||||
<CollectionCarcousel
|
||||
data={dataTest}
|
||||
itemKey="product-4"
|
||||
title="VEGGIE"
|
||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
||||
category={"veggie"}
|
||||
/>
|
||||
<CollectionCarcousel
|
||||
data={dataTest}
|
||||
itemKey="product-5"
|
||||
title="VEGGIE"
|
||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
||||
category={"veggie"}
|
||||
/>
|
||||
<CollectionCarcousel
|
||||
data={dataTest}
|
||||
itemKey="product-6"
|
||||
title="VEGGIE"
|
||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
||||
category={"veggie"}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default FreshProducts
|
@@ -4,6 +4,7 @@ export { default as HomeCategories } from './HomeCategories/HomeCategories'
|
||||
export { default as HomeCTA } from './HomeCTA/HomeCTA'
|
||||
export { default as HomeSubscribe } from './HomeSubscribe/HomeSubscribe'
|
||||
export { default as HomeVideo } from './HomeVideo/HomeVideo'
|
||||
export { default as FreshProducts } from './FreshProducts/FreshProducts'
|
||||
export { default as HomeCollection } from './HomeCollection/HomeCollection'
|
||||
export { default as HomeRecipe } from './HomeRecipe/HomeRecipe'
|
||||
export { default as FeaturedProductsCarousel } from './FeaturedProductsCarousel/FeaturedProductsCarousel'
|
||||
|
@@ -108,6 +108,14 @@ export const CATEGORY = [
|
||||
},
|
||||
]
|
||||
|
||||
export const FACET = {
|
||||
FEATURE: {
|
||||
PARENT_NAME: 'Featured',
|
||||
FRESH: 'Fresh',
|
||||
BEST_SELLERS: 'Best seller'
|
||||
}
|
||||
}
|
||||
|
||||
export const FEATURED = [
|
||||
{
|
||||
name: 'Best Sellers',
|
||||
@@ -141,3 +149,4 @@ export const STATE_OPTIONS = [
|
||||
value: 'Hà Nội',
|
||||
},
|
||||
]
|
||||
|
||||
|
@@ -1,3 +1,7 @@
|
||||
import { FacetValue } from './../../framework/vendure/schema.d';
|
||||
import { Facet } from "@commerce/types/facet";
|
||||
import { FACET } from "./constanst.utils";
|
||||
|
||||
export function isMobile() {
|
||||
return window.innerWidth < 768
|
||||
}
|
||||
@@ -9,3 +13,17 @@ export function removeItem<T>(arr: Array<T>, value: T): Array<T> {
|
||||
}
|
||||
return [...arr];
|
||||
}
|
||||
|
||||
export function getFreshProductFacetId(facets: Facet[]) {
|
||||
const featuredFacet = facets.find((item: Facet) => item.name === FACET.FEATURE.PARENT_NAME)
|
||||
const freshFacetValue = featuredFacet?.values.find((item: FacetValue) => item.name === FACET.FEATURE.FRESH)
|
||||
|
||||
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
|
||||
}
|
Reference in New Issue
Block a user