@faststore/core 2.1.83 → 2.2.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +9 -7
- package/.turbo/turbo-test.log +25 -0
- package/@generated/graphql/index.ts +183 -79
- package/@generated/graphql/persisted.json +5 -5
- package/@generated/graphql/schema.graphql +1053 -0
- package/api/index.ts +15 -0
- package/codegen.yml +2 -1
- package/generate.sh +71 -0
- package/index.ts +15 -0
- package/jest.config.js +6 -0
- package/package.json +33 -18
- package/src/components/ThirdPartyScripts/ThirdPartyScripts.tsx +1 -2
- package/src/components/cms/RenderSections.tsx +4 -5
- package/src/components/product/ProductGrid/ProductGrid.tsx +4 -3
- package/src/components/sections/Breadcrumb/Breadcrumb.tsx +17 -22
- package/src/components/sections/CrossSellingShelf/CrossSellingShelf.tsx +8 -6
- package/src/components/sections/ProductDetails/ProductDetails.tsx +23 -33
- package/src/components/sections/ProductGallery/ProductGallery.tsx +15 -26
- package/src/components/sections/ProductShelf/ProductShelf.tsx +1 -1
- package/src/components/sections/ProductTiles/ProductTiles.tsx +4 -3
- package/src/components/templates/ProductListingPage/ProductListing.tsx +95 -0
- package/src/components/templates/ProductListingPage/ProductListingPage.tsx +34 -68
- package/src/components/templates/SearchPage/SearchPage.tsx +81 -0
- package/src/components/templates/SearchPage/index.ts +2 -0
- package/src/components/ui/ProductGallery/ProductGallery.tsx +24 -16
- package/src/components/ui/ProductGallery/ProductGalleryPage.tsx +8 -7
- package/src/components/ui/ProductGallery/useDelayedFacets.ts +3 -3
- package/src/components/ui/ProductShelf/ProductShelf.tsx +3 -2
- package/src/customizations/GlobalOverrides.tsx +0 -2
- package/src/customizations/fragments/ClientProduct.ts +9 -0
- package/src/customizations/fragments/ClientProductGallery.ts +19 -0
- package/src/customizations/fragments/ClientProducts.ts +19 -0
- package/src/customizations/fragments/ServerCollectionPage.ts +9 -0
- package/src/customizations/fragments/ServerProductPage.ts +9 -0
- package/src/customizations/graphql/thirdParty/resolvers/index.ts +3 -0
- package/src/customizations/graphql/vtex/resolvers/index.ts +3 -0
- package/src/pages/[...slug].tsx +5 -3
- package/src/pages/[slug]/p.tsx +38 -18
- package/src/pages/s.tsx +22 -34
- package/src/sdk/graphql/useQuery.ts +17 -13
- package/src/sdk/overrides/PageProvider.tsx +78 -0
- package/src/sdk/product/useLocalizedVariables.ts +33 -0
- package/src/sdk/product/usePageProductsQuery.ts +139 -0
- package/src/{components/sections/ProductGallery/useGalleryQuery.ts → sdk/product/useProductGalleryQuery.ts} +12 -13
- package/src/sdk/product/{useProduct.ts → useProductQuery.ts} +10 -7
- package/src/sdk/product/useProductsPrefetch.ts +72 -0
- package/src/sdk/product/useProductsQuery.ts +17 -63
- package/src/server/generator/generateGraphQLSchemaFile.ts +3 -0
- package/src/server/generator/schema.ts +82 -0
- package/src/server/index.ts +34 -21
- package/src/server/options.ts +16 -0
- package/test/server/index.test.ts +146 -0
- package/.next/BUILD_ID +0 -1
- package/.next/build-manifest.json +0 -129
- package/.next/cache/.tsbuildinfo +0 -1
- package/.next/cache/config.json +0 -7
- package/.next/cache/eslint/.cache_1gneedd +0 -1
- package/.next/cache/next-server.js.nft.json +0 -1
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/export-marker.json +0 -1
- package/.next/images-manifest.json +0 -1
- package/.next/next-server.js.nft.json +0 -1
- package/.next/package.json +0 -1
- package/.next/prerender-manifest.json +0 -1
- package/.next/react-loadable-manifest.json +0 -44
- package/.next/required-server-files.json +0 -1
- package/.next/routes-manifest.json +0 -1
- package/.next/server/chunks/143.js +0 -106
- package/.next/server/chunks/177.js +0 -120
- package/.next/server/chunks/183.js +0 -94
- package/.next/server/chunks/184.js +0 -61
- package/.next/server/chunks/186.js +0 -113
- package/.next/server/chunks/289.js +0 -239
- package/.next/server/chunks/312.js +0 -697
- package/.next/server/chunks/350.js +0 -143
- package/.next/server/chunks/483.js +0 -650
- package/.next/server/chunks/487.js +0 -9142
- package/.next/server/chunks/53.js +0 -61
- package/.next/server/chunks/530.js +0 -626
- package/.next/server/chunks/576.js +0 -94
- package/.next/server/chunks/650.js +0 -9142
- package/.next/server/chunks/676.js +0 -32
- package/.next/server/chunks/693.js +0 -58
- package/.next/server/chunks/71.js +0 -1254
- package/.next/server/chunks/74.js +0 -4054
- package/.next/server/chunks/753.js +0 -509
- package/.next/server/chunks/779.js +0 -58
- package/.next/server/chunks/825.js +0 -4039
- package/.next/server/chunks/854.js +0 -72
- package/.next/server/chunks/859.js +0 -959
- package/.next/server/chunks/907.js +0 -1911
- package/.next/server/chunks/933.js +0 -517
- package/.next/server/chunks/98.js +0 -124
- package/.next/server/chunks/988.js +0 -211
- package/.next/server/chunks/font-manifest.json +0 -1
- package/.next/server/font-manifest.json +0 -1
- package/.next/server/middleware-build-manifest.js +0 -1
- package/.next/server/middleware-manifest.json +0 -6
- package/.next/server/middleware-react-loadable-manifest.js +0 -1
- package/.next/server/pages/404.js +0 -386
- package/.next/server/pages/404.js.nft.json +0 -1
- package/.next/server/pages/500.js +0 -388
- package/.next/server/pages/500.js.nft.json +0 -1
- package/.next/server/pages/[...slug].js +0 -1005
- package/.next/server/pages/[...slug].js.nft.json +0 -1
- package/.next/server/pages/[slug]/p.js +0 -2269
- package/.next/server/pages/[slug]/p.js.nft.json +0 -1
- package/.next/server/pages/_app.js +0 -280
- package/.next/server/pages/_app.js.nft.json +0 -1
- package/.next/server/pages/_document.js +0 -374
- package/.next/server/pages/_document.js.nft.json +0 -1
- package/.next/server/pages/_error.js +0 -164
- package/.next/server/pages/_error.js.nft.json +0 -1
- package/.next/server/pages/account.js +0 -363
- package/.next/server/pages/account.js.nft.json +0 -1
- package/.next/server/pages/api/graphql.js +0 -365
- package/.next/server/pages/api/graphql.js.nft.json +0 -1
- package/.next/server/pages/api/health/live.js +0 -31
- package/.next/server/pages/api/health/live.js.nft.json +0 -1
- package/.next/server/pages/api/health/ready.js +0 -31
- package/.next/server/pages/api/health/ready.js.nft.json +0 -1
- package/.next/server/pages/api/preview.js +0 -148
- package/.next/server/pages/api/preview.js.nft.json +0 -1
- package/.next/server/pages/checkout.js +0 -363
- package/.next/server/pages/checkout.js.nft.json +0 -1
- package/.next/server/pages/en-US/404.html +0 -81
- package/.next/server/pages/en-US/404.json +0 -1
- package/.next/server/pages/en-US/500.html +0 -81
- package/.next/server/pages/en-US/500.json +0 -1
- package/.next/server/pages/en-US/account.html +0 -81
- package/.next/server/pages/en-US/account.json +0 -1
- package/.next/server/pages/en-US/checkout.html +0 -81
- package/.next/server/pages/en-US/checkout.json +0 -1
- package/.next/server/pages/en-US/login.html +0 -81
- package/.next/server/pages/en-US/login.json +0 -1
- package/.next/server/pages/en-US/s.html +0 -81
- package/.next/server/pages/en-US/s.json +0 -1
- package/.next/server/pages/en-US.html +0 -81
- package/.next/server/pages/en-US.json +0 -1
- package/.next/server/pages/index.js +0 -439
- package/.next/server/pages/index.js.nft.json +0 -1
- package/.next/server/pages/login.js +0 -368
- package/.next/server/pages/login.js.nft.json +0 -1
- package/.next/server/pages/s.js +0 -466
- package/.next/server/pages/s.js.nft.json +0 -1
- package/.next/server/pages-manifest.json +0 -18
- package/.next/server/webpack-api-runtime.js +0 -229
- package/.next/server/webpack-runtime.js +0 -229
- package/.next/static/chunks/143.dd8a556e6957baa1.js +0 -1
- package/.next/static/chunks/148.3bb7e05cc5d1c1c4.js +0 -1
- package/.next/static/chunks/238-e5e4b2094f0e1df8.js +0 -1
- package/.next/static/chunks/243-8f5650ed908aa75c.js +0 -1
- package/.next/static/chunks/530.848b014622932b93.js +0 -1
- package/.next/static/chunks/548-ab84e9e8b49413ab.js +0 -1
- package/.next/static/chunks/603-d1c069aa8a349c86.js +0 -1
- package/.next/static/chunks/651.7142f31ce1e052b3.js +0 -1
- package/.next/static/chunks/709.7bc5a25ce30abda6.js +0 -1
- package/.next/static/chunks/738-67a288ca3569cdbb.js +0 -1
- package/.next/static/chunks/741.52f7fb873418346f.js +0 -1
- package/.next/static/chunks/98.97381d2021f86cd9.js +0 -1
- package/.next/static/chunks/988.d10040040cdfebbb.js +0 -1
- package/.next/static/chunks/framework-dfd14d7ce6600b03.js +0 -1
- package/.next/static/chunks/main-fd466221927468fd.js +0 -1
- package/.next/static/chunks/pages/404-af78f7cd1d3c1f60.js +0 -1
- package/.next/static/chunks/pages/500-f6346ca5f9dc4fef.js +0 -1
- package/.next/static/chunks/pages/[...slug]-ca533c74c22cb787.js +0 -1
- package/.next/static/chunks/pages/[slug]/p-7bb760bb3fcfc0bb.js +0 -1
- package/.next/static/chunks/pages/_app-895781b1c7b5bf56.js +0 -1
- package/.next/static/chunks/pages/_error-a7a0c1d9bfbb4f38.js +0 -1
- package/.next/static/chunks/pages/account-05bd79fb78365e88.js +0 -1
- package/.next/static/chunks/pages/checkout-c973786e68f25a39.js +0 -1
- package/.next/static/chunks/pages/index-d521ce4f4e2b89a6.js +0 -1
- package/.next/static/chunks/pages/login-8deb9243376b6aa1.js +0 -1
- package/.next/static/chunks/pages/s-0e516ab36bb49c99.js +0 -1
- package/.next/static/chunks/polyfills-c67a75d1b6f99dc8.js +0 -1
- package/.next/static/chunks/webpack-062512aedeb4b39e.js +0 -1
- package/.next/static/css/0d056c673d2869bb.css +0 -1
- package/.next/static/css/4b7138899cd07c63.css +0 -1
- package/.next/static/css/527e334fa69cf40a.css +0 -1
- package/.next/static/css/6e1a7434f061d0ef.css +0 -1
- package/.next/static/css/9e76fef1c9ca89af.css +0 -1
- package/.next/static/css/a2eefb25a4608343.css +0 -1
- package/.next/static/css/cb7d1fcea42fab9c.css +0 -1
- package/.next/static/css/df588bb98c0b0ca6.css +0 -1
- package/.next/static/css/e3b039e8f5daf95f.css +0 -1
- package/.next/static/css/f0e2d1b8832e935d.css +0 -1
- package/.next/static/jxv75E0IlXYBYk71TulQP/_buildManifest.js +0 -1
- package/.next/static/jxv75E0IlXYBYk71TulQP/_ssgManifest.js +0 -1
- package/.next/trace +0 -80
- package/public/~partytown/debug/partytown-atomics.js +0 -556
- package/public/~partytown/debug/partytown-media.js +0 -374
- package/public/~partytown/debug/partytown-sandbox-sw.js +0 -543
- package/public/~partytown/debug/partytown-sw.js +0 -59
- package/public/~partytown/debug/partytown-ww-atomics.js +0 -1789
- package/public/~partytown/debug/partytown-ww-sw.js +0 -1781
- package/public/~partytown/debug/partytown.js +0 -72
- package/public/~partytown/partytown-atomics.js +0 -2
- package/public/~partytown/partytown-media.js +0 -2
- package/public/~partytown/partytown-sw.js +0 -2
- package/public/~partytown/partytown.js +0 -2
- package/src/components/ui/ProductGallery/usePageProducts.ts +0 -48
- package/src/customizations/components/overrides/ThirdPartyScripts.tsx +0 -9
- package/src/customizations/scripts/ThirdPartyScripts.tsx +0 -8
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { ServerCollectionPageQueryQuery } from '@generated/graphql'
|
|
2
|
+
import Breadcrumb from 'src/components/sections/Breadcrumb'
|
|
3
|
+
import Hero from 'src/components/sections/Hero'
|
|
4
|
+
import ProductGallery from 'src/components/sections/ProductGallery'
|
|
5
|
+
import ProductShelf from 'src/components/sections/ProductShelf'
|
|
6
|
+
import ScrollToTopButton from 'src/components/sections/ScrollToTopButton'
|
|
7
|
+
import { ITEMS_PER_PAGE } from 'src/constants'
|
|
8
|
+
import deepmerge from 'deepmerge'
|
|
9
|
+
import { useSearch } from '@faststore/sdk'
|
|
10
|
+
|
|
11
|
+
import type { ComponentType } from 'react'
|
|
12
|
+
import RenderSections from 'src/components/cms/RenderSections'
|
|
13
|
+
import CUSTOM_COMPONENTS from 'src/customizations/components'
|
|
14
|
+
import { PLPContentType } from 'src/server/cms'
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
useCreateUseGalleryPage,
|
|
18
|
+
UseGalleryPageContext,
|
|
19
|
+
} from 'src/sdk/product/usePageProductsQuery'
|
|
20
|
+
import { useProductGalleryQuery } from 'src/sdk/product/useProductGalleryQuery'
|
|
21
|
+
import PageProvider, { PLPContext } from 'src/sdk/overrides/PageProvider'
|
|
22
|
+
|
|
23
|
+
export type ProductListingPageProps = {
|
|
24
|
+
data: ServerCollectionPageQueryQuery
|
|
25
|
+
page: PLPContentType
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Sections: Components imported from each store's custom components and '../components/sections' only.
|
|
30
|
+
* Do not import or render components from any other folder in here.
|
|
31
|
+
*/
|
|
32
|
+
const COMPONENTS: Record<string, ComponentType<any>> = {
|
|
33
|
+
Breadcrumb,
|
|
34
|
+
Hero,
|
|
35
|
+
ProductGallery,
|
|
36
|
+
ProductShelf,
|
|
37
|
+
...CUSTOM_COMPONENTS,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Array merging strategy from deepmerge that makes client arrays overwrite server array
|
|
41
|
+
// https://www.npmjs.com/package/deepmerge
|
|
42
|
+
const overwriteMerge = (_, sourceArray) => sourceArray
|
|
43
|
+
|
|
44
|
+
export default function ProductListing({
|
|
45
|
+
page: { sections, settings },
|
|
46
|
+
data: server,
|
|
47
|
+
}: ProductListingPageProps) {
|
|
48
|
+
const {
|
|
49
|
+
state: { sort, term, selectedFacets },
|
|
50
|
+
} = useSearch()
|
|
51
|
+
const itemsPerPage = settings?.productGallery?.itemsPerPage ?? ITEMS_PER_PAGE
|
|
52
|
+
|
|
53
|
+
const { data: pageProductGalleryData } = useProductGalleryQuery({
|
|
54
|
+
term,
|
|
55
|
+
sort,
|
|
56
|
+
selectedFacets,
|
|
57
|
+
itemsPerPage,
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const { pages, useGalleryPage } = useCreateUseGalleryPage()
|
|
61
|
+
|
|
62
|
+
const context = {
|
|
63
|
+
data: {
|
|
64
|
+
...deepmerge(
|
|
65
|
+
{ ...server },
|
|
66
|
+
{ ...pageProductGalleryData },
|
|
67
|
+
{ arrayMerge: overwriteMerge }
|
|
68
|
+
),
|
|
69
|
+
pages,
|
|
70
|
+
},
|
|
71
|
+
} as PLPContext
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<>
|
|
75
|
+
{/*
|
|
76
|
+
WARNING: Do not import or render components from any
|
|
77
|
+
other folder than '../components/sections' in here.
|
|
78
|
+
|
|
79
|
+
This is necessary to keep the integration with the CMS
|
|
80
|
+
easy and consistent, enabling the change and reorder
|
|
81
|
+
of elements on this page.
|
|
82
|
+
|
|
83
|
+
If needed, wrap your component in a <Section /> component
|
|
84
|
+
(not the HTML tag) before rendering it here.
|
|
85
|
+
*/}
|
|
86
|
+
<PageProvider context={context}>
|
|
87
|
+
<UseGalleryPageContext.Provider value={useGalleryPage}>
|
|
88
|
+
<RenderSections sections={sections} components={COMPONENTS} />
|
|
89
|
+
</UseGalleryPageContext.Provider>
|
|
90
|
+
</PageProvider>
|
|
91
|
+
|
|
92
|
+
<ScrollToTopButton />
|
|
93
|
+
</>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
@@ -9,38 +9,21 @@ import { useRouter } from 'next/router'
|
|
|
9
9
|
import { useMemo } from 'react'
|
|
10
10
|
|
|
11
11
|
import type { ServerCollectionPageQueryQuery } from '@generated/graphql'
|
|
12
|
-
import Breadcrumb from 'src/components/sections/Breadcrumb'
|
|
13
|
-
import Hero from 'src/components/sections/Hero'
|
|
14
|
-
import ProductGallery from 'src/components/sections/ProductGallery'
|
|
15
|
-
import ProductShelf from 'src/components/sections/ProductShelf'
|
|
16
|
-
import ScrollToTopButton from 'src/components/sections/ScrollToTopButton'
|
|
17
12
|
import { ITEMS_PER_PAGE } from 'src/constants'
|
|
18
13
|
import { useApplySearchState } from 'src/sdk/search/state'
|
|
19
14
|
|
|
20
|
-
import type { ComponentType } from 'react'
|
|
21
|
-
import RenderSections from 'src/components/cms/RenderSections'
|
|
22
|
-
import CUSTOM_COMPONENTS from 'src/customizations/components'
|
|
23
15
|
import { PLPContentType } from 'src/server/cms'
|
|
24
16
|
|
|
25
17
|
import storeConfig from '../../../../faststore.config'
|
|
18
|
+
import ProductListing from './ProductListing'
|
|
26
19
|
|
|
27
|
-
export type ProductListingPageProps =
|
|
20
|
+
export type ProductListingPageProps = {
|
|
21
|
+
data: ServerCollectionPageQueryQuery
|
|
28
22
|
page: PLPContentType
|
|
29
23
|
}
|
|
30
24
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
* Do not import or render components from any other folder in here.
|
|
34
|
-
*/
|
|
35
|
-
const COMPONENTS: Record<string, ComponentType<any>> = {
|
|
36
|
-
Breadcrumb,
|
|
37
|
-
Hero,
|
|
38
|
-
ProductGallery,
|
|
39
|
-
ProductShelf,
|
|
40
|
-
...CUSTOM_COMPONENTS,
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
type UseSearchParams = ServerCollectionPageQueryQuery & {
|
|
25
|
+
type UseSearchParams = {
|
|
26
|
+
collection: ServerCollectionPageQueryQuery['collection']
|
|
44
27
|
sort: SearchState['sort']
|
|
45
28
|
}
|
|
46
29
|
const useSearchParams = ({
|
|
@@ -71,14 +54,15 @@ const useSearchParams = ({
|
|
|
71
54
|
}
|
|
72
55
|
|
|
73
56
|
export default function ProductListingPage({
|
|
74
|
-
page:
|
|
75
|
-
|
|
57
|
+
page: plpContentType,
|
|
58
|
+
data: server,
|
|
76
59
|
}: ProductListingPageProps) {
|
|
77
|
-
const {
|
|
60
|
+
const { settings } = plpContentType
|
|
61
|
+
const collection = server.collection
|
|
78
62
|
const router = useRouter()
|
|
79
63
|
const applySearchState = useApplySearchState()
|
|
80
64
|
const searchParams = useSearchParams({
|
|
81
|
-
|
|
65
|
+
collection,
|
|
82
66
|
sort: settings?.productGallery?.sortBySelection as SearchState['sort'],
|
|
83
67
|
})
|
|
84
68
|
|
|
@@ -90,49 +74,31 @@ export default function ProductListingPage({
|
|
|
90
74
|
const sortQuery = !!sort ? `${separator}sort=${sort}` : ''
|
|
91
75
|
const [pathname] = router.asPath.split('?')
|
|
92
76
|
const canonical = `${storeConfig.storeUrl}${pathname}${pageQuery}${sortQuery}`
|
|
77
|
+
const itemsPerPage = settings?.productGallery?.itemsPerPage ?? ITEMS_PER_PAGE
|
|
93
78
|
|
|
94
79
|
return (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
WARNING: Do not import or render components from any
|
|
119
|
-
other folder than '../components/sections' in here.
|
|
120
|
-
|
|
121
|
-
This is necessary to keep the integration with the CMS
|
|
122
|
-
easy and consistent, enabling the change and reorder
|
|
123
|
-
of elements on this page.
|
|
124
|
-
|
|
125
|
-
If needed, wrap your component in a <Section /> component
|
|
126
|
-
(not the HTML tag) before rendering it here.
|
|
127
|
-
*/}
|
|
128
|
-
<RenderSections
|
|
129
|
-
context={collection}
|
|
130
|
-
sections={sections}
|
|
131
|
-
components={COMPONENTS}
|
|
132
|
-
/>
|
|
133
|
-
|
|
134
|
-
<ScrollToTopButton />
|
|
135
|
-
</SearchProvider>
|
|
136
|
-
</>
|
|
80
|
+
<SearchProvider
|
|
81
|
+
onChange={applySearchState}
|
|
82
|
+
itemsPerPage={itemsPerPage}
|
|
83
|
+
{...searchParams}
|
|
84
|
+
>
|
|
85
|
+
{/* SEO */}
|
|
86
|
+
<NextSeo
|
|
87
|
+
title={title}
|
|
88
|
+
description={description}
|
|
89
|
+
titleTemplate={storeConfig.seo.titleTemplate}
|
|
90
|
+
canonical={canonical}
|
|
91
|
+
openGraph={{
|
|
92
|
+
type: 'website',
|
|
93
|
+
title,
|
|
94
|
+
description,
|
|
95
|
+
}}
|
|
96
|
+
/>
|
|
97
|
+
<BreadcrumbJsonLd
|
|
98
|
+
itemListElements={collection?.breadcrumbList.itemListElement ?? []}
|
|
99
|
+
/>
|
|
100
|
+
|
|
101
|
+
<ProductListing page={plpContentType} data={server} />
|
|
102
|
+
</SearchProvider>
|
|
137
103
|
)
|
|
138
104
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { useSearch } from '@faststore/sdk'
|
|
2
|
+
import type { ComponentType } from 'react'
|
|
3
|
+
|
|
4
|
+
import Breadcrumb from 'src/components/sections/Breadcrumb'
|
|
5
|
+
import ProductGallery from 'src/components/sections/ProductGallery'
|
|
6
|
+
import { ITEMS_PER_PAGE } from 'src/constants'
|
|
7
|
+
import CUSTOM_COMPONENTS from 'src/customizations/components'
|
|
8
|
+
import RenderSections from 'src/components/cms/RenderSections'
|
|
9
|
+
import { SearchContentType } from 'src/server/cms'
|
|
10
|
+
import { useProductGalleryQuery } from 'src/sdk/product/useProductGalleryQuery'
|
|
11
|
+
import PageProvider, { SearchPageContext } from 'src/sdk/overrides/PageProvider'
|
|
12
|
+
import {
|
|
13
|
+
useCreateUseGalleryPage,
|
|
14
|
+
UseGalleryPageContext,
|
|
15
|
+
} from 'src/sdk/product/usePageProductsQuery'
|
|
16
|
+
import { SearchPageContextType } from 'src/pages/s'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Sections: Components imported from each store's custom components and '../components/sections' only.
|
|
20
|
+
* Do not import or render components from any other folder in here.
|
|
21
|
+
*/
|
|
22
|
+
const COMPONENTS: Record<string, ComponentType<any>> = {
|
|
23
|
+
Breadcrumb,
|
|
24
|
+
ProductGallery,
|
|
25
|
+
...CUSTOM_COMPONENTS,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type SearchPageProps = {
|
|
29
|
+
data: SearchPageContextType
|
|
30
|
+
page: SearchContentType
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function SearchPage({
|
|
34
|
+
page: { sections, settings },
|
|
35
|
+
data: server,
|
|
36
|
+
}: SearchPageProps) {
|
|
37
|
+
const {
|
|
38
|
+
state: { sort, term, selectedFacets },
|
|
39
|
+
} = useSearch()
|
|
40
|
+
const itemsPerPage = settings?.productGallery?.itemsPerPage ?? ITEMS_PER_PAGE
|
|
41
|
+
|
|
42
|
+
const { data: pageProductGalleryData } = useProductGalleryQuery({
|
|
43
|
+
term,
|
|
44
|
+
sort,
|
|
45
|
+
selectedFacets,
|
|
46
|
+
itemsPerPage,
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const { pages, useGalleryPage } = useCreateUseGalleryPage()
|
|
50
|
+
|
|
51
|
+
const context = {
|
|
52
|
+
data: {
|
|
53
|
+
...server,
|
|
54
|
+
...pageProductGalleryData,
|
|
55
|
+
pages,
|
|
56
|
+
},
|
|
57
|
+
} as SearchPageContext
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<>
|
|
61
|
+
{/*
|
|
62
|
+
WARNING: Do not import or render components from any
|
|
63
|
+
other folder than '../components/sections' in here.
|
|
64
|
+
|
|
65
|
+
This is necessary to keep the integration with the CMS
|
|
66
|
+
easy and consistent, enabling the change and reorder
|
|
67
|
+
of elements on this page.
|
|
68
|
+
|
|
69
|
+
If needed, wrap your component in a <Section /> component
|
|
70
|
+
(not the HTML tag) before rendering it here.
|
|
71
|
+
*/}
|
|
72
|
+
<PageProvider context={context}>
|
|
73
|
+
<UseGalleryPageContext.Provider value={useGalleryPage}>
|
|
74
|
+
<RenderSections sections={sections} components={COMPONENTS} />
|
|
75
|
+
</UseGalleryPageContext.Provider>
|
|
76
|
+
</PageProvider>
|
|
77
|
+
</>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default SearchPage
|
|
@@ -9,31 +9,34 @@ import Sort from 'src/components/search/Sort'
|
|
|
9
9
|
import FilterSkeleton from 'src/components/skeletons/FilterSkeleton'
|
|
10
10
|
import ProductGridSkeleton from 'src/components/skeletons/ProductGridSkeleton'
|
|
11
11
|
|
|
12
|
-
import { ProductGalleryQueryQuery } from '@generated/graphql'
|
|
13
12
|
import { ProductCardProps } from 'src/components/product/ProductCard'
|
|
14
13
|
import { FilterSliderProps } from 'src/components/search/Filter/FilterSlider'
|
|
15
14
|
import { SortProps } from 'src/components/search/Sort/Sort'
|
|
16
|
-
import { useDelayedFacets } from './useDelayedFacets'
|
|
17
|
-
import { useDelayedPagination } from './useDelayedPagination'
|
|
18
|
-
import { useProductsPrefetch } from './usePageProducts'
|
|
19
15
|
import {
|
|
20
|
-
|
|
16
|
+
FilterButtonSkeleton,
|
|
21
17
|
FilterIcon,
|
|
18
|
+
LinkButtonNext,
|
|
19
|
+
LinkButtonPrev,
|
|
20
|
+
MobileFilterButton,
|
|
22
21
|
PrevIcon,
|
|
23
22
|
ResultsCountSkeleton,
|
|
24
23
|
SortSkeleton,
|
|
25
|
-
FilterButtonSkeleton,
|
|
26
|
-
LinkButtonPrev,
|
|
27
|
-
LinkButtonNext,
|
|
28
24
|
} from 'src/components/sections/ProductGallery/Overrides'
|
|
25
|
+
import { useDelayedFacets } from './useDelayedFacets'
|
|
26
|
+
import { useDelayedPagination } from './useDelayedPagination'
|
|
27
|
+
import {
|
|
28
|
+
PLPContext,
|
|
29
|
+
SearchPageContext,
|
|
30
|
+
usePage,
|
|
31
|
+
} from 'src/sdk/overrides/PageProvider'
|
|
32
|
+
import { useProductsPrefetch } from 'src/sdk/product/useProductsPrefetch'
|
|
29
33
|
|
|
30
|
-
const
|
|
34
|
+
const ProductGalleryPage = lazy(() => import('./ProductGalleryPage'))
|
|
31
35
|
const GalleryPageSkeleton = <ProductGridSkeleton loading />
|
|
32
36
|
|
|
33
37
|
export interface ProductGalleryProps {
|
|
34
38
|
title?: string
|
|
35
39
|
searchTerm?: string
|
|
36
|
-
productGalleryData?: ProductGalleryQueryQuery
|
|
37
40
|
totalCount?: number
|
|
38
41
|
searchTermLabel?: string
|
|
39
42
|
totalCountLabel?: string
|
|
@@ -69,7 +72,6 @@ export interface ProductGalleryProps {
|
|
|
69
72
|
function ProductGallery({
|
|
70
73
|
title,
|
|
71
74
|
searchTerm,
|
|
72
|
-
productGalleryData,
|
|
73
75
|
totalCount,
|
|
74
76
|
searchTermLabel,
|
|
75
77
|
totalCountLabel,
|
|
@@ -80,13 +82,18 @@ function ProductGallery({
|
|
|
80
82
|
productCard,
|
|
81
83
|
}: ProductGalleryProps) {
|
|
82
84
|
const { openFilter } = useUI()
|
|
83
|
-
const { pages, addNextPage, addPrevPage } = useSearch()
|
|
84
|
-
const
|
|
85
|
+
const { pages, addNextPage, addPrevPage, itemsPerPage } = useSearch()
|
|
86
|
+
const context = usePage<SearchPageContext | PLPContext>()
|
|
87
|
+
const data = context?.data
|
|
88
|
+
const facets = useDelayedFacets(data) ?? []
|
|
85
89
|
const { next, prev } = useDelayedPagination(totalCount)
|
|
86
90
|
|
|
87
91
|
useProductsPrefetch(prev ? prev.cursor : null)
|
|
88
92
|
useProductsPrefetch(next ? next.cursor : null)
|
|
89
93
|
|
|
94
|
+
const hasFacets =
|
|
95
|
+
Boolean(data?.search?.facets) && data.search.facets.length > 0
|
|
96
|
+
|
|
90
97
|
return (
|
|
91
98
|
<section data-testid="product-gallery" data-fs-product-listing>
|
|
92
99
|
{searchTerm && (
|
|
@@ -115,7 +122,7 @@ function ProductGallery({
|
|
|
115
122
|
{...ResultsCountSkeleton.props}
|
|
116
123
|
// Dynamic props shouldn't be overridable
|
|
117
124
|
// This decision can be reviewed later if needed
|
|
118
|
-
loading={!
|
|
125
|
+
loading={!data?.search}
|
|
119
126
|
>
|
|
120
127
|
<h2 data-testid="total-product-count">
|
|
121
128
|
{totalCount} {totalCountLabel}
|
|
@@ -212,14 +219,15 @@ function ProductGallery({
|
|
|
212
219
|
</div>
|
|
213
220
|
)}
|
|
214
221
|
{/* Render ALL products */}
|
|
215
|
-
{
|
|
222
|
+
{hasFacets ? (
|
|
216
223
|
<Suspense fallback={GalleryPageSkeleton}>
|
|
217
224
|
{pages.map((page) => (
|
|
218
|
-
<
|
|
225
|
+
<ProductGalleryPage
|
|
219
226
|
key={`gallery-page-${page}`}
|
|
220
227
|
page={page}
|
|
221
228
|
title={title}
|
|
222
229
|
productCard={productCard}
|
|
230
|
+
itemsPerPage={itemsPerPage}
|
|
223
231
|
/>
|
|
224
232
|
))}
|
|
225
233
|
</Suspense>
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import { useSearch } from '@faststore/sdk'
|
|
2
|
-
|
|
3
1
|
import ProductGrid from 'src/components/product/ProductGrid'
|
|
4
2
|
import Sentinel from 'src/sdk/search/Sentinel'
|
|
5
3
|
|
|
6
4
|
import { ProductCardProps } from 'src/components/product/ProductCard'
|
|
7
|
-
import {
|
|
5
|
+
import { memo } from 'react'
|
|
6
|
+
import { useGalleryPage } from 'src/sdk/product/usePageProductsQuery'
|
|
8
7
|
|
|
9
8
|
interface Props {
|
|
10
9
|
page: number
|
|
11
10
|
title: string
|
|
12
11
|
productCard?: Pick<ProductCardProps, 'showDiscountBadge' | 'bordered'>
|
|
12
|
+
itemsPerPage: number
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
function
|
|
16
|
-
const
|
|
17
|
-
|
|
15
|
+
function ProductGalleryPage({ page, title, productCard, itemsPerPage }: Props) {
|
|
16
|
+
const { data } = useGalleryPage(page)
|
|
17
|
+
|
|
18
|
+
const products = data?.search?.products?.edges ?? []
|
|
18
19
|
|
|
19
20
|
return (
|
|
20
21
|
<>
|
|
@@ -34,4 +35,4 @@ function GalleryPage({ page, title, productCard }: Props) {
|
|
|
34
35
|
)
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
export default
|
|
38
|
+
export default memo(ProductGalleryPage)
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { useMemo, useRef } from 'react'
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
|
+
ClientProductGalleryQueryQuery,
|
|
4
5
|
Filter_FacetsFragment,
|
|
5
|
-
ProductGalleryQueryQuery,
|
|
6
6
|
} from '@generated/graphql'
|
|
7
7
|
|
|
8
|
-
export const useDelayedFacets = (data?:
|
|
8
|
+
export const useDelayedFacets = (data?: ClientProductGalleryQueryQuery) => {
|
|
9
9
|
const facets = useRef<Filter_FacetsFragment[]>([])
|
|
10
10
|
|
|
11
11
|
return useMemo(() => {
|
|
12
12
|
if (data) {
|
|
13
|
-
facets.current = data.search
|
|
13
|
+
facets.current = data.search?.facets
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
return facets.current
|
|
@@ -45,12 +45,13 @@ function ProductShelf({
|
|
|
45
45
|
bordered = ProductCard.props.bordered,
|
|
46
46
|
showDiscountBadge = ProductCard.props.showDiscountBadge,
|
|
47
47
|
} = {},
|
|
48
|
-
...
|
|
48
|
+
...otherProps
|
|
49
49
|
}: ProductShelfProps) {
|
|
50
50
|
const titleId = textToKebabCase(title)
|
|
51
51
|
const id = useId()
|
|
52
52
|
const viewedOnce = useRef(false)
|
|
53
|
-
const
|
|
53
|
+
const data = useProductsQuery(otherProps)
|
|
54
|
+
const products = data?.search?.products
|
|
54
55
|
const productEdges = products?.edges ?? []
|
|
55
56
|
const aspectRatio = 1
|
|
56
57
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import WebFontsOverrides from 'src/customizations/components/overrides/WebFonts'
|
|
2
2
|
import { default as CoreWebFonts } from 'src/fonts/WebFonts'
|
|
3
|
-
import ThirdPartyScriptsOverrides from 'src/customizations/components/overrides/ThirdPartyScripts'
|
|
4
3
|
|
|
5
4
|
const Components = {
|
|
6
5
|
WebFonts: CoreWebFonts,
|
|
7
6
|
...WebFontsOverrides.components,
|
|
8
|
-
...ThirdPartyScriptsOverrides.components,
|
|
9
7
|
}
|
|
10
8
|
|
|
11
9
|
export const WebFonts = Components.WebFonts
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { gql } from '@faststore/graphql-utils'
|
|
2
|
+
|
|
3
|
+
export const fragment = gql`
|
|
4
|
+
fragment ClientProductGallery on Query {
|
|
5
|
+
search(
|
|
6
|
+
first: $first
|
|
7
|
+
after: $after
|
|
8
|
+
sort: $sort
|
|
9
|
+
term: $term
|
|
10
|
+
selectedFacets: $selectedFacets
|
|
11
|
+
) {
|
|
12
|
+
products {
|
|
13
|
+
pageInfo {
|
|
14
|
+
totalCount
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
`
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { gql } from '@faststore/graphql-utils'
|
|
2
|
+
|
|
3
|
+
export const fragment = gql`
|
|
4
|
+
fragment ClientProducts on Query {
|
|
5
|
+
search(
|
|
6
|
+
first: $first
|
|
7
|
+
after: $after
|
|
8
|
+
sort: $sort
|
|
9
|
+
term: $term
|
|
10
|
+
selectedFacets: $selectedFacets
|
|
11
|
+
) {
|
|
12
|
+
products {
|
|
13
|
+
pageInfo {
|
|
14
|
+
totalCount
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
`
|
package/src/pages/[...slug].tsx
CHANGED
|
@@ -29,10 +29,11 @@ type BaseProps = {
|
|
|
29
29
|
|
|
30
30
|
type Props = BaseProps &
|
|
31
31
|
(
|
|
32
|
-
|
|
|
32
|
+
| {
|
|
33
33
|
type: 'plp'
|
|
34
34
|
page: PLPContentType
|
|
35
|
-
|
|
35
|
+
data: ServerCollectionPageQueryQuery
|
|
36
|
+
}
|
|
36
37
|
| {
|
|
37
38
|
type: 'page'
|
|
38
39
|
page: PageContentType
|
|
@@ -52,6 +53,7 @@ function Page({ globalSections, type, ...otherProps }: Props) {
|
|
|
52
53
|
|
|
53
54
|
const query = gql`
|
|
54
55
|
query ServerCollectionPageQuery($slug: String!) {
|
|
56
|
+
...ServerCollectionPage
|
|
55
57
|
collection(slug: $slug) {
|
|
56
58
|
seo {
|
|
57
59
|
title
|
|
@@ -123,7 +125,7 @@ export const getStaticProps: GetStaticProps<
|
|
|
123
125
|
|
|
124
126
|
return {
|
|
125
127
|
props: {
|
|
126
|
-
|
|
128
|
+
data,
|
|
127
129
|
page,
|
|
128
130
|
globalSections: await globalSectionsPromise,
|
|
129
131
|
type: 'plp',
|