From 1546d5df4b129ce67756052b127e8a32882fe4d1 Mon Sep 17 00:00:00 2001 From: lytrankieio123 Date: Tue, 5 Oct 2021 10:30:39 +0700 Subject: [PATCH] :sparkles: feat: get all collection :%s --- commerce.config.json | 6 +-- framework/commerce/api/operations.ts | 18 +++++++ framework/commerce/new-provider.md | 1 + framework/commerce/types/collection.ts | 54 +++++++++++++++++++ framework/commerce/types/product.ts | 5 +- framework/vendure/api/index.ts | 2 + .../api/operations/get-all-collection.ts | 45 ++++++++++++++++ framework/vendure/schema.d.ts | 17 ++++++ framework/vendure/utils/normalize.ts | 1 - .../queries/get-all-collections-query.ts | 12 +++++ pages/index.tsx | 48 ++++++++++------- .../common/LabelCommon/LabelCommon.tsx | 1 + .../common/ProductCard/ProductCard.tsx | 6 +-- .../CollectionCarcousel.tsx | 7 +-- .../home/FreshProducts/FreshProducts.tsx | 30 +++++++++-- src/utils/funtion.utils.ts | 7 ++- src/utils/types.utils.ts | 8 ++- 17 files changed, 230 insertions(+), 38 deletions(-) create mode 100644 framework/commerce/types/collection.ts create mode 100644 framework/vendure/api/operations/get-all-collection.ts create mode 100644 framework/vendure/utils/queries/get-all-collections-query.ts 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 342d6bbc9..ca9b325c2 100644 --- a/framework/commerce/api/operations.ts +++ b/framework/commerce/api/operations.ts @@ -10,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') @@ -25,6 +26,7 @@ export const OPERATIONS = [ 'getAllProducts', 'getProduct', 'getAllFacets', + 'getAllCollections', ] as const @@ -174,6 +176,22 @@ export type Operations

= { ): Promise } + getAllCollections: { + (opts: { + variables?: T['variables'] + config?: P['config'] + preview?: boolean + }): Promise + + ( + opts: { + variables?: T['variables'] + config?: P['config'] + preview?: boolean + } & OperationOptions + ): Promise + } + } diff --git a/framework/commerce/new-provider.md b/framework/commerce/new-provider.md index a48e6961b..3c7f05b7a 100644 --- a/framework/commerce/new-provider.md +++ b/framework/commerce/new-provider.md @@ -16,6 +16,7 @@ Adding a commerce provider means adding a new folder in `framework` with a folde - 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/product.ts b/framework/commerce/types/product.ts index ac7025158..e1a8da200 100644 --- a/framework/commerce/types/product.ts +++ b/framework/commerce/types/product.ts @@ -1,4 +1,4 @@ -import { CurrencyCode, FacetValue } from './../../vendure/schema.d'; +import { CurrencyCode } from './../../vendure/schema.d'; import { FacetValueFilterInput, LogicalOperator, SearchResultSortParameter } from "@framework/schema" export type ProductImage = { @@ -59,8 +59,7 @@ export type ProductCard = { weight?: number facetValueIds?: string[], collectionIds?: string[], - // TODO: collection - category?: string, + collection?: string, isNotSell?: boolean } diff --git a/framework/vendure/api/index.ts b/framework/vendure/api/index.ts index 7e49d6c1f..95ec47d66 100644 --- a/framework/vendure/api/index.ts +++ b/framework/vendure/api/index.ts @@ -1,6 +1,7 @@ import type { CommerceAPIConfig } from '@commerce/api' import { CommerceAPI, getCommerceApi as commerceApi } from '@commerce/api' import getAllFacets from './operations/get-all-facets' +import getAllCollections from './operations/get-all-collection' import getAllPages from './operations/get-all-pages' import getAllProductPaths from './operations/get-all-product-paths' import getAllProducts from './operations/get-all-products' @@ -42,6 +43,7 @@ const operations = { 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/schema.d.ts b/framework/vendure/schema.d.ts index c5c3e8e89..ef667d9f3 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -3240,6 +3240,23 @@ export type GetAllFacetsQuery = { __typename?: 'Query' } & { } } +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/normalize.ts b/framework/vendure/utils/normalize.ts index a790aa8cd..cc76e5f97 100644 --- a/framework/vendure/utils/normalize.ts +++ b/framework/vendure/utils/normalize.ts @@ -18,7 +18,6 @@ export function normalizeSearchResult(item: SearchResultFragment): ProductCard { // discount // isNotSell // weight - // category } } 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/pages/index.tsx b/pages/index.tsx index 589c7ae30..cac464a43 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,28 +1,31 @@ import { ProductCard } from '@commerce/types/product'; import { ProductVariables } from '@framework/api/operations/get-all-products'; -import { FacetValue } from '@framework/schema'; +import { Collection, FacetValue } from '@framework/schema'; import commerce from '@lib/api/commerce'; 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 { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED } from 'src/utils/constanst.utils'; -import { getAllFacetValueIdsByParentCode, getAllFacetValuesForFeatuedProducts, getFreshFacetId } from 'src/utils/funtion.utils'; +import { getAllFacetValueIdsByParentCode, getAllFacetValuesForFeatuedProducts, getAllPromies, getFreshFacetId } from 'src/utils/funtion.utils'; +import { PromiseWithKey } from 'src/utils/types.utils'; interface Props { featuredAndDiscountFacetsValue: FacetValue[], freshProducts: ProductCard[], featuredProducts: ProductCard[], + collections: Collection[] } export default function Home({ featuredAndDiscountFacetsValue, - freshProducts, featuredProducts }: Props) { + freshProducts, featuredProducts, + collections }: Props) { return ( <> - + @@ -44,13 +47,15 @@ export async function getStaticProps({ locales, }: GetStaticPropsContext) { const config = { locale, locales } + let promisesWithKey = [] as PromiseWithKey[] + let props = {} as any + const { facets } = await commerce.getAllFacets({ variables: {}, config, preview, }) - const featuredAndDiscountFacetsValue = getAllFacetValuesForFeatuedProducts(facets) - + props.featuredAndDiscountFacetsValue = getAllFacetValuesForFeatuedProducts(facets) // fresh products const freshProductvariables: ProductVariables = {} @@ -63,6 +68,8 @@ export async function getStaticProps({ config, preview, }) + promisesWithKey.push({ key: 'freshProducts', promise: freshProductsPromise, keyResult: 'products' }) + // featured products const allFeaturedFacetIds = getAllFacetValueIdsByParentCode(facets, CODE_FACET_FEATURED) @@ -75,28 +82,33 @@ export async function getStaticProps({ 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 rs = await Promise.all([ - freshProductsPromise, - featuredProductsPromise, - ]) + 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: { - featuredAndDiscountFacetsValue, - freshProducts: freshFacetId ? rs[0].products : [], - featuredProducts: facetValueIdsForFeaturedProducts.length > 0 ? rs[1].products : [] - }, + props, revalidate: 60, } } catch (err) { } - - - } diff --git a/src/components/common/LabelCommon/LabelCommon.tsx b/src/components/common/LabelCommon/LabelCommon.tsx index fcb9b7eae..23f2d7d6a 100644 --- a/src/components/common/LabelCommon/LabelCommon.tsx +++ b/src/components/common/LabelCommon/LabelCommon.tsx @@ -2,6 +2,7 @@ import classNames from 'classnames' import React from 'react' import s from './LabelCommon.module.scss' interface LabelCommonProps extends React.HTMLAttributes { + 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 b9c351aab..4761aac92 100644 --- a/src/components/common/ProductCard/ProductCard.tsx +++ b/src/components/common/ProductCard/ProductCard.tsx @@ -17,7 +17,7 @@ export interface ProductCardProps extends ProductCard { } const ProductCardComponent = ({ - category, + collection, name, slug, weight, @@ -45,9 +45,9 @@ const ProductCardComponent = ({ { - category && + collection &&

- {category} + {collection}
} 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/FreshProducts/FreshProducts.tsx b/src/components/modules/home/FreshProducts/FreshProducts.tsx index 33b872032..cf773d495 100644 --- a/src/components/modules/home/FreshProducts/FreshProducts.tsx +++ b/src/components/modules/home/FreshProducts/FreshProducts.tsx @@ -1,12 +1,32 @@ import { ProductCard } from '@commerce/types/product' -import { Product } from '@framework/schema' -import React from 'react' +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 FreshProducts = ({ data }: FreshProductsProps) => { +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 } @@ -14,11 +34,11 @@ const FreshProducts = ({ data }: FreshProductsProps) => {
) diff --git a/src/utils/funtion.utils.ts b/src/utils/funtion.utils.ts index d486ca4d0..853b77108 100644 --- a/src/utils/funtion.utils.ts +++ b/src/utils/funtion.utils.ts @@ -1,6 +1,7 @@ import { Facet } from "@commerce/types/facet"; import { FacetValue } from './../../framework/vendure/schema.d'; import { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED, CODE_FACET_FEATURED_VARIANT } from "./constanst.utils"; +import { PromiseWithKey } from "./types.utils"; export function isMobile() { return window.innerWidth < 768 @@ -55,4 +56,8 @@ export function getFacetNamesFromIds(facets: FacetValue[], ids?: string[]): stri 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 +} + +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, +}