From a4c23a218151310f9c294f734cc671d81c53ea50 Mon Sep 17 00:00:00 2001 From: Tan Le Date: Thu, 30 Sep 2021 15:47:57 +0700 Subject: [PATCH 1/4] feat: getProductDetail --- framework/vendure/schema.d.ts | 2 +- next-env.d.ts | 3 -- src/components/hooks/product/index.tsx | 1 + .../hooks/product/useProductDetail.tsx | 31 +++++++++++++++++++ .../ProductImgItem/ProductImgItem.tsx | 8 ++--- .../components/ProductImgs/ProductImgs.tsx | 4 ++- .../components/ProductInfo/ProductInfo.tsx | 10 +++--- 7 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 src/components/hooks/product/index.tsx create mode 100644 src/components/hooks/product/useProductDetail.tsx diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index 9d6b53c52..b664d8fa1 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -3206,7 +3206,7 @@ export type GetProductQuery = { __typename?: 'Query' } & { variants: Array< { __typename?: 'ProductVariant' } & Pick< ProductVariant, - 'id' | 'priceWithTax' | 'currencyCode' + 'id' | 'priceWithTax' | 'currencyCode' | 'price' > & { options: Array< { __typename?: 'ProductOption' } & Pick< diff --git a/next-env.d.ts b/next-env.d.ts index 9bc3dd46b..c6643fda1 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,3 @@ /// /// /// - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/src/components/hooks/product/index.tsx b/src/components/hooks/product/index.tsx new file mode 100644 index 000000000..bfe1abac2 --- /dev/null +++ b/src/components/hooks/product/index.tsx @@ -0,0 +1 @@ +export { default as useProductDetail } from './useProductDetail' \ No newline at end of file diff --git a/src/components/hooks/product/useProductDetail.tsx b/src/components/hooks/product/useProductDetail.tsx new file mode 100644 index 000000000..6a147d263 --- /dev/null +++ b/src/components/hooks/product/useProductDetail.tsx @@ -0,0 +1,31 @@ +import { GetProductQuery } from '@framework/schema' +import { gql } from 'graphql-request' +import gglFetcher from 'src/utils/gglFetcher' +import useSWR from 'swr' + +const query = gql` + query GetProductDetail($slug: String! = "hand-trowel") { + product(slug: $slug) { + name + description + variants { + price + priceWithTax + } + assets { + preview + name + } + } +} +` +interface ProductDetail { + slug: string +} + +const useProductDetail = () => { + const { data, ...rest } = useSWR([query],gglFetcher) + return { productDetail: data?.product, ...rest } +} + +export default useProductDetail \ No newline at end of file diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgItem/ProductImgItem.tsx b/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgItem/ProductImgItem.tsx index 95236266c..931b0a36c 100644 --- a/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgItem/ProductImgItem.tsx +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgItem/ProductImgItem.tsx @@ -3,15 +3,15 @@ import { ImgWithLink } from 'src/components/common' import s from './ProductImgItem.module.scss' export interface ProductImgItemProps { - src: string - alt?: string + preview: string + name?: string } -const ProductImgItem = ({ src, alt }: ProductImgItemProps) => { +const ProductImgItem = ({ preview, name }: ProductImgItemProps) => { return (
- +
) } diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.tsx b/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.tsx index 475d0f22e..365faa73a 100644 --- a/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.tsx +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.tsx @@ -2,6 +2,7 @@ import React from 'react' import { ResponsiveType } from 'react-multi-carousel' import { CarouselCommon } from 'src/components/common' import ProductImgItem, { ProductImgItemProps } from '../ProductImgItem/ProductImgItem' +import { useProductDetail } from 'src/components/hooks/product' import s from './ProductImgs.module.scss' interface Props { @@ -32,10 +33,11 @@ const RESPONSIVE: ResponsiveType = { }, } const ProductImgs = ({ }: Props) => { + const { productDetail } = useProductDetail() return (
- data={DATA} + data={productDetail?.assets ?? []} itemKey="product-detail-img" Component={ProductImgItem} responsive={RESPONSIVE} diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx b/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx index 4abb62568..40779083c 100644 --- a/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx @@ -2,6 +2,7 @@ import React from 'react' import { ButtonCommon, LabelCommon, QuanittyInput } from 'src/components/common' import { IconBuy } from 'src/components/icons' import { LANGUAGE } from 'src/utils/language.utils' +import { useProductDetail } from 'src/components/hooks/product' import s from './ProductInfo.module.scss' interface Props { @@ -10,20 +11,21 @@ interface Props { } const ProductInfo = ({ }: Props) => { + const {productDetail} = useProductDetail() return (
SEAFOOD -

SeaPAk

+

{productDetail?.name}

- Rp 32.000 + Rp {productDetail?.variants[0].priceWithTax} -15%
-
Rp 27.500
+
Rp {productDetail?.variants[0].price}
- In a large non-reactive dish, mix together the orange juice, soy sauce, olive oil, lemon juice, parsley + {productDetail?.description}
From cf2260869a0c23dee4790b8632bb8b24eeb069de Mon Sep 17 00:00:00 2001 From: Tan Le Date: Thu, 30 Sep 2021 15:52:18 +0700 Subject: [PATCH 2/4] refactor: move query into get-product-query --- .../utils/queries/get-product-query.ts | 16 ++++++++++++++ .../hooks/product/useProductDetail.tsx | 21 +++---------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/framework/vendure/utils/queries/get-product-query.ts b/framework/vendure/utils/queries/get-product-query.ts index b2c502da9..82aa5dc41 100644 --- a/framework/vendure/utils/queries/get-product-query.ts +++ b/framework/vendure/utils/queries/get-product-query.ts @@ -39,3 +39,19 @@ export const getProductQuery = /* GraphQL */ ` } } ` +export const getProductDetailQuery = /* GraphQL */ ` + query GetProductDetail($slug: String! = "hand-trowel") { + product(slug: $slug) { + name + description + variants { + price + priceWithTax + } + assets { + preview + name + } + } +} +` \ No newline at end of file diff --git a/src/components/hooks/product/useProductDetail.tsx b/src/components/hooks/product/useProductDetail.tsx index 6a147d263..a68b1449d 100644 --- a/src/components/hooks/product/useProductDetail.tsx +++ b/src/components/hooks/product/useProductDetail.tsx @@ -1,30 +1,15 @@ import { GetProductQuery } from '@framework/schema' -import { gql } from 'graphql-request' +import { getProductDetailQuery } from '@framework/utils/queries/get-product-query'; import gglFetcher from 'src/utils/gglFetcher' import useSWR from 'swr' -const query = gql` - query GetProductDetail($slug: String! = "hand-trowel") { - product(slug: $slug) { - name - description - variants { - price - priceWithTax - } - assets { - preview - name - } - } -} -` + interface ProductDetail { slug: string } const useProductDetail = () => { - const { data, ...rest } = useSWR([query],gglFetcher) + const { data, ...rest } = useSWR([getProductDetailQuery],gglFetcher) return { productDetail: data?.product, ...rest } } From 8b5637a2471024369c30e76185bd3ccc175cfd16 Mon Sep 17 00:00:00 2001 From: Tan Le Date: Thu, 7 Oct 2021 10:46:20 +0700 Subject: [PATCH 3/4] push code to check --- .../vendure/api/operations/get-product.ts | 2 +- package.json | 2 + pages/test.tsx | 24 +++---- .../ProductInfoDetail/ProductInfoDetail.tsx | 69 ++++++++++++++++++- 4 files changed, 81 insertions(+), 16 deletions(-) diff --git a/framework/vendure/api/operations/get-product.ts b/framework/vendure/api/operations/get-product.ts index 4ab9ed2d9..592086c13 100644 --- a/framework/vendure/api/operations/get-product.ts +++ b/framework/vendure/api/operations/get-product.ts @@ -2,7 +2,7 @@ import { Product } from '@commerce/types/product' import { OperationContext } from '@commerce/api/operations' import { Provider, VendureConfig } from '../' import { GetProductQuery } from '../../schema' -import { getProductQuery } from '../../utils/queries/get-product-query' +import { getProductQuery, getProductDetailQuery } from '../../utils/queries/get-product-query' export default function getProductOperation({ commerce, diff --git a/package.json b/package.json index 84a77cf71..8474be667 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "body-scroll-lock": "^3.1.5", "classnames": "^2.3.1", "cookie": "^0.4.1", + "dns": "^0.2.2", "email-validator": "^2.0.4", "eslint": "^7.32.0", "eslint-config-next": "^11.1.2", @@ -35,6 +36,7 @@ "lodash.debounce": "^4.0.8", "lodash.random": "^3.2.0", "lodash.throttle": "^4.1.1", + "net": "^1.0.2", "next": "^11.0.0", "next-seo": "^4.26.0", "next-themes": "^0.0.14", diff --git a/pages/test.tsx b/pages/test.tsx index 6244c3dd6..debfe2398 100644 --- a/pages/test.tsx +++ b/pages/test.tsx @@ -1,17 +1,17 @@ import commerce from '@lib/api/commerce'; import { GetStaticPropsContext } from 'next'; import { Layout } from 'src/components/common'; - +import { ProductCard } from '@commerce/types/product'; interface Props { - products: any + productDetail: ProductCard[], } -export default function Home({ products }: Props) { +export default function Home({ productDetail }: Props) { return ( <>

- TOTAL: {products?.length} + TOTAL: {productDetail}

- {JSON.stringify(products[0])} + {/* {JSON.stringify(productDetail)} */} ) } @@ -23,10 +23,11 @@ export async function getServerSideProps({ locales, }: GetStaticPropsContext) { const config = { locale, locales } - const productsPromise = commerce.getAllProducts({ + + const productsPromise = commerce.getProduct({ // const productsPromise = commerce.getAllFacets({ variables: { - first: 70, + slug: "hand-trowel" // filter: { // name: { // contains: 'ca' @@ -34,16 +35,15 @@ export async function getServerSideProps({ // } }, config, - preview, + // preview, // Saleor provider only ...({ featured: true } as any), }) - const { products } = await productsPromise - - + const { product } = await productsPromise + const productDetail = JSON.stringify(product) return { - props: { products }, + props: { productDetail }, } } diff --git a/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx index d1047bd3a..2578a865f 100644 --- a/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx +++ b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx @@ -2,13 +2,19 @@ import React from 'react' import ProductImgs from './components/ProductImgs/ProductImgs' import ProductInfo from './components/ProductInfo/ProductInfo' import s from './ProductInfoDetail.module.scss' +import { GetStaticPropsContext, GetStaticPathsContext, InferGetStaticPropsType } from 'next' +import commerce from '@lib/api/commerce' +import { PromiseWithKey } from 'src/utils/types.utils' +import { getAllPromies } from 'src/utils/funtion.utils' +import { ProductCard } from '@commerce/types/product'; +import { useRouter } from 'next/router' interface Props { - className?: string - children?: any + productDetail: ProductCard[], } -const ProductInfoDetail = ({ }: Props) => { +const ProductInfoDetail = ({ product }: InferGetStaticPropsType) => { + console.log(product) return (
@@ -17,4 +23,61 @@ const ProductInfoDetail = ({ }: Props) => { ) } +export async function getStaticProps({ + params, + locale, + locales, + preview, + }: GetStaticPropsContext<{ slug: string }>) { + const config = { locale, locales } + const pagesPromise = commerce.getAllPages({ config, preview }) + const siteInfoPromise = commerce.getSiteInfo({ config, preview }) + const productPromise = commerce.getProduct({ + variables: { slug: params!.slug }, + config, + preview, + }) + + // const allProductsPromise = commerce.getAllProducts({ + // variables: { first: 4 }, + // config, + // preview, + // }) + const { pages } = await pagesPromise + const { categories } = await siteInfoPromise + const { product } = await productPromise + // const { products: relatedProducts } = await allProductsPromise + + if (!product) { + throw new Error(`Product with slug '${params!.slug}' not found`) + } + + return { + props: { + pages, + product, + // relatedProducts, + categories, + }, + revalidate: 200, + } + } + +// export async function getStaticPaths({ locales }: GetStaticPathsContext) { +// const { products } = await commerce.getAllProductPaths() + +// return { +// paths: locales +// ? locales.reduce((arr, locale) => { +// // Add a product path for every locale +// products.forEach((product: any) => { +// arr.push(`/${locale}/product${product.path}`) +// }) +// return arr +// }, []) +// : products.map((product: any) => `/product${product.path}`), +// fallback: 'blocking', +// } +// } + export default ProductInfoDetail From 148326c7ef32f475784b9720f11dd8052e27a455 Mon Sep 17 00:00:00 2001 From: Tan Le Date: Thu, 7 Oct 2021 16:16:24 +0700 Subject: [PATCH 4/4] feat: get-product-detail --- framework/commerce/types/product.ts | 2 + .../vendure/api/operations/get-product.ts | 3 +- .../utils/queries/get-product-query.ts | 3 + pages/product/[slug].tsx | 2 +- .../ProductInfoDetail/ProductInfoDetail.tsx | 85 ++++--------------- .../ProductImgItem/ProductImgItem.tsx | 8 +- .../components/ProductImgs/ProductImgs.tsx | 24 +----- .../components/ProductInfo/ProductInfo.tsx | 19 ++--- .../ReleventProducts/ReleventProducts.tsx | 1 - 9 files changed, 40 insertions(+), 107 deletions(-) diff --git a/framework/commerce/types/product.ts b/framework/commerce/types/product.ts index e02113814..ddf51c518 100644 --- a/framework/commerce/types/product.ts +++ b/framework/commerce/types/product.ts @@ -47,6 +47,8 @@ export type Product = { currencyCode: CurrencyCode options: ProductOption[] facetValueIds?: string[] + collectionIds?: string[] + collection?: string, } export type ProductCard = { diff --git a/framework/vendure/api/operations/get-product.ts b/framework/vendure/api/operations/get-product.ts index 38eca93b4..0aa761ab0 100644 --- a/framework/vendure/api/operations/get-product.ts +++ b/framework/vendure/api/operations/get-product.ts @@ -53,7 +53,8 @@ export default function getProductOperation({ displayName: og.name, values: og.options.map((o) => ({ label: o.name })), })), - facetValueIds: product.facetValues.map(item=> item.id) + facetValueIds: product.facetValues.map(item=> item.id), + collectionIds: product.collections.map(item => item.id) } as Product } diff --git a/framework/vendure/utils/queries/get-product-query.ts b/framework/vendure/utils/queries/get-product-query.ts index 3d2742383..6db960a96 100644 --- a/framework/vendure/utils/queries/get-product-query.ts +++ b/framework/vendure/utils/queries/get-product-query.ts @@ -39,6 +39,9 @@ export const getProductQuery = /* GraphQL */ ` facetValues { id } + collections { + id + } } } ` diff --git a/pages/product/[slug].tsx b/pages/product/[slug].tsx index 24901277e..2da14a995 100644 --- a/pages/product/[slug].tsx +++ b/pages/product/[slug].tsx @@ -12,7 +12,7 @@ import { PromiseWithKey } from 'src/utils/types.utils' export default function Slug({ product, relevantProducts, collections }: InferGetStaticPropsType) { return <> - + diff --git a/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx index 2578a865f..072c1fd56 100644 --- a/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx +++ b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx @@ -1,83 +1,28 @@ -import React from 'react' +import React, { useMemo } from 'react'; import ProductImgs from './components/ProductImgs/ProductImgs' import ProductInfo from './components/ProductInfo/ProductInfo' import s from './ProductInfoDetail.module.scss' -import { GetStaticPropsContext, GetStaticPathsContext, InferGetStaticPropsType } from 'next' -import commerce from '@lib/api/commerce' -import { PromiseWithKey } from 'src/utils/types.utils' -import { getAllPromies } from 'src/utils/funtion.utils' -import { ProductCard } from '@commerce/types/product'; -import { useRouter } from 'next/router' +import { Product } from '@commerce/types/product' +import { Collection } from '@framework/schema' +import { getCategoryNameFromCollectionId } from 'src/utils/funtion.utils'; interface Props { - productDetail: ProductCard[], + productDetail: Product, + collections: Collection[] } -const ProductInfoDetail = ({ product }: InferGetStaticPropsType) => { - console.log(product) +const ProductInfoDetail = ({ productDetail, collections }: Props) => { + const dataWithCategoryName = useMemo(() => { + return { + ...productDetail, + collection: getCategoryNameFromCollectionId(collections, productDetail.collectionIds ? productDetail.collectionIds[0] : undefined) + } + }, [productDetail, collections]) return (
- - + +
) } - -export async function getStaticProps({ - params, - locale, - locales, - preview, - }: GetStaticPropsContext<{ slug: string }>) { - const config = { locale, locales } - const pagesPromise = commerce.getAllPages({ config, preview }) - const siteInfoPromise = commerce.getSiteInfo({ config, preview }) - const productPromise = commerce.getProduct({ - variables: { slug: params!.slug }, - config, - preview, - }) - - // const allProductsPromise = commerce.getAllProducts({ - // variables: { first: 4 }, - // config, - // preview, - // }) - const { pages } = await pagesPromise - const { categories } = await siteInfoPromise - const { product } = await productPromise - // const { products: relatedProducts } = await allProductsPromise - - if (!product) { - throw new Error(`Product with slug '${params!.slug}' not found`) - } - - return { - props: { - pages, - product, - // relatedProducts, - categories, - }, - revalidate: 200, - } - } - -// export async function getStaticPaths({ locales }: GetStaticPathsContext) { -// const { products } = await commerce.getAllProductPaths() - -// return { -// paths: locales -// ? locales.reduce((arr, locale) => { -// // Add a product path for every locale -// products.forEach((product: any) => { -// arr.push(`/${locale}/product${product.path}`) -// }) -// return arr -// }, []) -// : products.map((product: any) => `/product${product.path}`), -// fallback: 'blocking', -// } -// } - export default ProductInfoDetail diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgItem/ProductImgItem.tsx b/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgItem/ProductImgItem.tsx index 931b0a36c..bebee187c 100644 --- a/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgItem/ProductImgItem.tsx +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgItem/ProductImgItem.tsx @@ -3,15 +3,15 @@ import { ImgWithLink } from 'src/components/common' import s from './ProductImgItem.module.scss' export interface ProductImgItemProps { - preview: string - name?: string + url: string + alt?: string } -const ProductImgItem = ({ preview, name }: ProductImgItemProps) => { +const ProductImgItem = ({ url, alt }: ProductImgItemProps) => { return (
- +
) } diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.tsx b/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.tsx index 365faa73a..c5624dc52 100644 --- a/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.tsx +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.tsx @@ -2,28 +2,13 @@ import React from 'react' import { ResponsiveType } from 'react-multi-carousel' import { CarouselCommon } from 'src/components/common' import ProductImgItem, { ProductImgItemProps } from '../ProductImgItem/ProductImgItem' -import { useProductDetail } from 'src/components/hooks/product' import s from './ProductImgs.module.scss' +import { ProductImage } from '@commerce/types/product'; interface Props { - className?: string - children?: any, + productImage: ProductImage[] } -const DATA = [ - { - src: 'https://user-images.githubusercontent.com/76729908/133026929-199799fc-bd75-4445-a24d-15c0e41796eb.png', - alt: 'Meat', - }, - { - src: 'https://user-images.githubusercontent.com/76729908/130574371-3b75fa72-9552-4605-aba9-a4b31cd9dce7.png', - alt: 'Broccoli', - }, - { - src: 'https://user-images.githubusercontent.com/76729908/130574371-3b75fa72-9552-4605-aba9-a4b31cd9dce7.png', - alt: 'Broccoli', - } -] const RESPONSIVE: ResponsiveType = { desktop: { @@ -32,12 +17,11 @@ const RESPONSIVE: ResponsiveType = { slidesToSlide: 1, // optional, default to 1. }, } -const ProductImgs = ({ }: Props) => { - const { productDetail } = useProductDetail() +const ProductImgs = ({ productImage }: Props) => { return (
- data={productDetail?.assets ?? []} + data={productImage} itemKey="product-detail-img" Component={ProductImgItem} responsive={RESPONSIVE} diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx b/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx index 40779083c..c3e51d46d 100644 --- a/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx @@ -1,31 +1,30 @@ +import { Product } from '@commerce/types/product' import React from 'react' import { ButtonCommon, LabelCommon, QuanittyInput } from 'src/components/common' import { IconBuy } from 'src/components/icons' import { LANGUAGE } from 'src/utils/language.utils' -import { useProductDetail } from 'src/components/hooks/product' import s from './ProductInfo.module.scss' interface Props { - className?: string - children?: any, + productInfoDetail: Product } -const ProductInfo = ({ }: Props) => { - const {productDetail} = useProductDetail() +const ProductInfo = ({ productInfoDetail }: Props) => { + console.log(productInfoDetail) return (
- SEAFOOD -

{productDetail?.name}

+ {productInfoDetail.collection} +

{productInfoDetail.name}

- Rp {productDetail?.variants[0].priceWithTax} + Rp {productInfoDetail.price} -15%
-
Rp {productDetail?.variants[0].price}
+
Rp {productInfoDetail.price}
- {productDetail?.description} + {productInfoDetail.description}
diff --git a/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx b/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx index 147115dc2..d1afde538 100644 --- a/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx +++ b/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx @@ -23,7 +23,6 @@ const ReleventProducts = ({ data, collections }: Props) => { if (data.length === 0) { return null } - return (