@faststore/core 3.77.2 → 3.78.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.
Files changed (172) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +49 -49
  3. package/.next/cache/.tsbuildinfo +1 -1
  4. package/.next/cache/config.json +3 -3
  5. package/.next/cache/webpack/client-production/0.pack +0 -0
  6. package/.next/cache/webpack/client-production/index.pack +0 -0
  7. package/.next/cache/webpack/server-production/0.pack +0 -0
  8. package/.next/cache/webpack/server-production/index.pack +0 -0
  9. package/.next/prerender-manifest.js +1 -1
  10. package/.next/prerender-manifest.json +1 -1
  11. package/.next/react-loadable-manifest.json +71 -57
  12. package/.next/routes-manifest.json +1 -1
  13. package/.next/server/chunks/1270.js +1 -0
  14. package/.next/server/chunks/1911.js +1 -0
  15. package/.next/server/chunks/2430.js +1 -0
  16. package/.next/server/chunks/3006.js +1 -1
  17. package/.next/server/chunks/3836.js +1 -1
  18. package/.next/server/chunks/3945.js +1 -0
  19. package/.next/server/chunks/5402.js +1 -0
  20. package/.next/server/chunks/6698.js +1 -0
  21. package/.next/server/chunks/6789.js +1 -1
  22. package/.next/server/chunks/{7178.js → 8071.js} +1 -1
  23. package/.next/server/chunks/83.js +1 -1
  24. package/.next/server/chunks/831.js +1 -1
  25. package/.next/server/chunks/8474.js +9 -0
  26. package/.next/server/chunks/8563.js +1 -0
  27. package/.next/server/chunks/9088.js +1 -1
  28. package/.next/server/chunks/9117.js +1 -0
  29. package/.next/server/chunks/948.js +1 -1
  30. package/.next/server/chunks/9563.js +2 -2
  31. package/.next/server/chunks/9630.js +101 -4
  32. package/.next/server/chunks/9853.js +1 -1
  33. package/.next/server/chunks/UIBannerText.js +1 -1
  34. package/.next/server/chunks/UISKUMatrixSidebar.js +1 -1
  35. package/.next/server/middleware-build-manifest.js +1 -1
  36. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  37. package/.next/server/pages/404.js.nft.json +1 -1
  38. package/.next/server/pages/500.js.nft.json +1 -1
  39. package/.next/server/pages/[...slug].js +1 -1
  40. package/.next/server/pages/[...slug].js.nft.json +1 -1
  41. package/.next/server/pages/[slug]/p.js +1 -1
  42. package/.next/server/pages/[slug]/p.js.nft.json +1 -1
  43. package/.next/server/pages/_app.js.nft.json +1 -1
  44. package/.next/server/pages/_document.js.nft.json +1 -1
  45. package/.next/server/pages/_error.js.nft.json +1 -1
  46. package/.next/server/pages/account/403.js.nft.json +1 -1
  47. package/.next/server/pages/account/404.js.nft.json +1 -1
  48. package/.next/server/pages/account/[...unknown].js.nft.json +1 -1
  49. package/.next/server/pages/account/orders/[id].js.nft.json +1 -1
  50. package/.next/server/pages/account/orders.js +1 -1
  51. package/.next/server/pages/account/orders.js.nft.json +1 -1
  52. package/.next/server/pages/account/profile.js.nft.json +1 -1
  53. package/.next/server/pages/account/security.js.nft.json +1 -1
  54. package/.next/server/pages/account/user-details.js.nft.json +1 -1
  55. package/.next/server/pages/account.js.nft.json +1 -1
  56. package/.next/server/pages/api/graphql.js +2 -2
  57. package/.next/server/pages/api/graphql.js.nft.json +1 -1
  58. package/.next/server/pages/api/health/live.js.nft.json +1 -1
  59. package/.next/server/pages/api/health/ready.js.nft.json +1 -1
  60. package/.next/server/pages/api/preview.js.nft.json +1 -1
  61. package/.next/server/pages/checkout.js.nft.json +1 -1
  62. package/.next/server/pages/en-US/404.html +1 -1
  63. package/.next/server/pages/en-US/500.html +1 -1
  64. package/.next/server/pages/en-US/checkout.html +1 -1
  65. package/.next/server/pages/en-US/login.html +1 -1
  66. package/.next/server/pages/en-US/s.html +1 -1
  67. package/.next/server/pages/en-US.html +1 -1
  68. package/.next/server/pages/index.js.nft.json +1 -1
  69. package/.next/server/pages/login.js.nft.json +1 -1
  70. package/.next/server/pages/s.js +1 -1
  71. package/.next/server/pages/s.js.nft.json +1 -1
  72. package/.next/server/pages-manifest.json +1 -1
  73. package/.next/static/{SaRJjm44wxKaH0mGRECi2 → 6VSKTBCq7vRe86nXQK6nv}/_buildManifest.js +1 -1
  74. package/.next/static/chunks/3155.c3fa96f983101956.js +1 -0
  75. package/.next/static/chunks/3166-a1d98d71987c90d6.js +1 -0
  76. package/.next/static/chunks/3399.60aae5ddb9123ef5.js +1 -0
  77. package/.next/static/chunks/3836.a2f49cd66f78bcb2.js +1 -0
  78. package/.next/static/chunks/4836.ef87204971e182f4.js +1 -0
  79. package/.next/static/chunks/6789.634a5fcc1ed30b8d.js +1 -0
  80. package/.next/static/chunks/7026.e990acc86d95259d.js +1 -0
  81. package/.next/static/chunks/7191-2b424236f6799274.js +1 -0
  82. package/.next/static/chunks/7351.8ef7b6b1d6e1505a.js +1 -0
  83. package/.next/static/chunks/83.affac11ef34a0c11.js +1 -0
  84. package/.next/static/chunks/8325.b3ddbb43feda1a85.js +1 -0
  85. package/.next/static/chunks/8587.1d6d458c9b697351.js +1 -0
  86. package/.next/static/chunks/9173-acced9d62b9088c8.js +1 -0
  87. package/.next/static/chunks/9666-9be3f1e484eeb148.js +1 -0
  88. package/.next/static/chunks/{7351.e90a4cc21797c136.js → 9714.68af2d4bf27f560b.js} +1 -1
  89. package/.next/static/chunks/9781.dd4028663db7414b.js +1 -0
  90. package/.next/static/chunks/BannerNewsletter.d91d065d644d15f3.js +1 -0
  91. package/.next/static/chunks/BannerText.3bc2f0af3687e984.js +1 -0
  92. package/.next/static/chunks/CartSidebar.f2f885b6d9a227e2.js +1 -0
  93. package/.next/static/chunks/ProductShelf.dcdeffe85dca1ace.js +1 -0
  94. package/.next/static/chunks/ProductTiles.12e553830401871d.js +1 -0
  95. package/.next/static/chunks/RegionModal.0aff964cb36eb49a.js +1 -0
  96. package/.next/static/chunks/RegionSlider.cbf2ac28eeac8dbe.js +1 -0
  97. package/.next/static/chunks/Toast.c06d4e2e2e7913c5.js +1 -0
  98. package/.next/static/chunks/UIBannerText.08c65db460bd1695.js +1 -0
  99. package/.next/static/chunks/UIToast.55af19d2eba3d8a1.js +1 -0
  100. package/.next/static/chunks/pages/{[...slug]-b3a9bdfcf0127006.js → [...slug]-1e68a914dfca7da9.js} +1 -1
  101. package/.next/static/chunks/pages/[slug]/p-2c73921b1ab00c27.js +1 -0
  102. package/.next/static/chunks/pages/_app-57478e0d1d2ddf62.js +1 -0
  103. package/.next/static/chunks/pages/s-e7745eef6c834c3e.js +1 -0
  104. package/.next/static/chunks/webpack-d29ca7e9684f9a33.js +1 -0
  105. package/.next/static/css/{70353bf19c496790.css → 297be4be3be36ff0.css} +1 -1
  106. package/.next/static/css/{0a57ee6c7a57788c.css → 4b8252ed2f23ac67.css} +1 -1
  107. package/.next/static/css/{6831395ff5fd317a.css → 6d92375b6ee8276a.css} +1 -1
  108. package/.next/static/css/{9bdd3be2a41064c6.css → 8f6350925b347380.css} +1 -1
  109. package/.next/trace +136 -135
  110. package/.turbo/turbo-build.log +21 -21
  111. package/.turbo/turbo-test.log +5 -5
  112. package/@generated/gql.ts +20 -4
  113. package/@generated/graphql.ts +310 -6
  114. package/@generated/persisted-documents.json +6 -5
  115. package/@generated/schema.graphql +39 -1
  116. package/CHANGELOG.md +12 -0
  117. package/cms/faststore/sections.json +99 -0
  118. package/package.json +4 -4
  119. package/src/components/product/ProductCard/ProductCard.tsx +74 -35
  120. package/src/components/product/ProductGrid/ProductGrid.tsx +16 -0
  121. package/src/components/sections/ProductDetails/ProductDetails.tsx +4 -0
  122. package/src/components/sections/ProductGallery/DefaultComponents.ts +15 -0
  123. package/src/components/sections/ProductGallery/ProductGallery.tsx +1 -0
  124. package/src/components/sections/ProductGallery/section.module.scss +16 -3
  125. package/src/components/templates/SearchPage/SearchPage.tsx +3 -1
  126. package/src/components/templates/SearchPage/SearchWrapper.tsx +1 -1
  127. package/src/components/ui/ProductComparison/ProductComparisonSidebar.tsx +256 -0
  128. package/src/components/ui/ProductComparison/index.ts +1 -0
  129. package/src/components/ui/ProductGallery/ProductGallery.tsx +251 -173
  130. package/src/components/ui/ProductGallery/ProductGalleryPage.tsx +6 -0
  131. package/src/pages/s.tsx +8 -5
  132. package/src/sdk/product/usePageProductsQuery.ts +80 -64
  133. package/src/sdk/product/useProductsSelected.tsx +45 -0
  134. package/src/typings/overrides.ts +30 -1
  135. package/test/server/index.test.ts +1 -0
  136. package/.next/server/chunks/1333.js +0 -1
  137. package/.next/server/chunks/2295.js +0 -1
  138. package/.next/server/chunks/2778.js +0 -9
  139. package/.next/server/chunks/3918.js +0 -1
  140. package/.next/server/chunks/3963.js +0 -1
  141. package/.next/server/chunks/5607.js +0 -1
  142. package/.next/server/chunks/6335.js +0 -1
  143. package/.next/server/chunks/76.js +0 -1
  144. package/.next/server/chunks/7794.js +0 -1
  145. package/.next/server/chunks/839.js +0 -1
  146. package/.next/static/chunks/3155.243c7558a71f0695.js +0 -1
  147. package/.next/static/chunks/3166-e2e2d3255aa5f208.js +0 -1
  148. package/.next/static/chunks/3399.93804fb74f79436c.js +0 -1
  149. package/.next/static/chunks/3836.c0487aea7bd0c6f0.js +0 -1
  150. package/.next/static/chunks/5781.28d03feacead66ad.js +0 -1
  151. package/.next/static/chunks/6355.454b14737c2bf69c.js +0 -1
  152. package/.next/static/chunks/6857.b2c06171638955ea.js +0 -1
  153. package/.next/static/chunks/7191-a72fe20ee3eb28ec.js +0 -1
  154. package/.next/static/chunks/7481.3c4ad3642e346232.js +0 -1
  155. package/.next/static/chunks/7498-0dc4f9a9ed199d3a.js +0 -1
  156. package/.next/static/chunks/83.ee1fdbe283ac65b6.js +0 -1
  157. package/.next/static/chunks/9173-3a00edf7b695a319.js +0 -1
  158. package/.next/static/chunks/BannerNewsletter.fe0181162c046991.js +0 -1
  159. package/.next/static/chunks/BannerText.681f118e9f149f6c.js +0 -1
  160. package/.next/static/chunks/CartSidebar.55cc31a37ffa6ee6.js +0 -1
  161. package/.next/static/chunks/ProductShelf.b75a7ab8e313ea07.js +0 -1
  162. package/.next/static/chunks/ProductTiles.35cd23ada22f5a96.js +0 -1
  163. package/.next/static/chunks/RegionModal.04b02aafc0836d49.js +0 -1
  164. package/.next/static/chunks/RegionSlider.d063ccee38bdfdb7.js +0 -1
  165. package/.next/static/chunks/Toast.75a18f47eb23b703.js +0 -1
  166. package/.next/static/chunks/UIBannerText.f4167ceafb96cf67.js +0 -1
  167. package/.next/static/chunks/UIToast.a49584c87d3adc17.js +0 -1
  168. package/.next/static/chunks/pages/[slug]/p-73a253032aaf8ce2.js +0 -1
  169. package/.next/static/chunks/pages/_app-df4ba03d82beaf86.js +0 -1
  170. package/.next/static/chunks/pages/s-3197dfed5c06ad7b.js +0 -1
  171. package/.next/static/chunks/webpack-b6bad1900f53d6e6.js +0 -1
  172. /package/.next/static/{SaRJjm44wxKaH0mGRECi2 → 6VSKTBCq7vRe86nXQK6nv}/_ssgManifest.js +0 -0
@@ -1,6 +1,6 @@
1
1
  import { NextSeo } from 'next-seo'
2
2
  import dynamic from 'next/dynamic'
3
- import { Suspense, lazy, type MouseEvent } from 'react'
3
+ import { Suspense, lazy, useState, type MouseEvent } from 'react'
4
4
 
5
5
  import { useSearch } from '@faststore/sdk'
6
6
  import { useUI } from '@faststore/ui'
@@ -22,6 +22,9 @@ import { useDelayedPagination } from 'src/sdk/search/useDelayedPagination'
22
22
  import { useFilter } from 'src/sdk/search/useFilter'
23
23
  import useScreenResize from 'src/sdk/ui/useScreenResize'
24
24
 
25
+ import styles from '../../sections/ProductGallery/section.module.scss'
26
+ import { useFormattedPrice } from 'src/sdk/product/useFormattedPrice'
27
+
25
28
  const ProductGalleryPage = lazy(() => import('./ProductGalleryPage'))
26
29
  const FilterSkeleton = dynamic(
27
30
  () =>
@@ -60,6 +63,29 @@ export interface ProductGalleryProps {
60
63
  alt: string
61
64
  }
62
65
  }
66
+ productComparison?: {
67
+ enabled?: boolean
68
+ labels?: {
69
+ compareButton: string
70
+ clearSelectionButton: string
71
+ selectionWarning: string
72
+ sidebarComponent?: {
73
+ title: string
74
+ sortLabel: string
75
+ filterLabel: string
76
+ productNameFilterLabel: string
77
+ preferencesLabel: string
78
+ toggleFieldLabel: string
79
+ cartButtonLabel: string
80
+ priceLabel: string
81
+ priceWithTaxLabel: string
82
+ }
83
+ technicalInformation?: {
84
+ title: string
85
+ description: string
86
+ }
87
+ }
88
+ }
63
89
  itemsPerPage?: number
64
90
  loadMorePageButton?: {
65
91
  label?: string
@@ -82,6 +108,7 @@ function ProductGallery({
82
108
  loadMorePageButton,
83
109
  sortBySelector,
84
110
  productCard,
111
+ productComparison,
85
112
  }: ProductGalleryProps) {
86
113
  const {
87
114
  FilterButtonSkeleton,
@@ -92,8 +119,12 @@ function ProductGallery({
92
119
  PrevIcon,
93
120
  ResultsCountSkeleton,
94
121
  SortSkeleton,
122
+ ToggleField,
123
+ ProductComparison,
124
+ ProductComparisonToolbar,
95
125
  __experimentalFilterDesktop: FilterDesktop,
96
126
  __experimentalFilterSlider: FilterSlider,
127
+ __experimentalProductComparisonSidebar: ProductComparisonSidebar,
97
128
  } = useOverrideComponents<'ProductGallery'>()
98
129
 
99
130
  const { openFilter, filter: displayFilter } = useUI()
@@ -102,11 +133,15 @@ function ProductGallery({
102
133
  const data = context?.data
103
134
  const facets = useDelayedFacets(data) ?? []
104
135
  const { next, prev } = useDelayedPagination(totalCount)
105
- const { isDesktop } = useScreenResize()
136
+
137
+ const [showComparisonProducts, setShowComparisonProducts] =
138
+ useState<boolean>(false)
106
139
 
107
140
  useProductsPrefetch(prev ? prev.cursor : null)
108
141
  useProductsPrefetch(next ? next.cursor : null)
109
142
 
143
+ const { isDesktop } = useScreenResize()
144
+
110
145
  const hasFacetsLoaded = Boolean(data?.search?.facets)
111
146
  const hasProductsLoaded = Boolean(data?.search?.products)
112
147
  const initialSelectedFacets =
@@ -125,184 +160,227 @@ function ProductGallery({
125
160
  </h1>
126
161
  </header>
127
162
  )}
128
- <div
129
- data-fs-product-listing-content-grid
130
- data-fs-content="product-gallery"
131
- >
132
- {isDesktop && (
133
- <div data-fs-product-listing-filters>
134
- <FilterSkeleton loading={!hasFacetsLoaded}>
163
+ <ProductComparison.Component>
164
+ <div
165
+ data-fs-product-listing-content-grid
166
+ data-fs-content="product-gallery"
167
+ >
168
+ {isDesktop && (
169
+ <div data-fs-product-listing-filters>
170
+ <FilterSkeleton loading={!hasFacetsLoaded}>
171
+ {hasFacetsLoaded && facets?.length > 0 && (
172
+ <div className="hidden-mobile">
173
+ <FilterDesktop.Component
174
+ {...FilterDesktop.props}
175
+ {...filter}
176
+ title={filterCmsData?.title}
177
+ />
178
+ </div>
179
+ )}
180
+ </FilterSkeleton>
181
+ </div>
182
+ )}
183
+ {!isDesktop && displayFilter && (
184
+ <div data-fs-product-listing-filters>
185
+ <FilterSlider.Component
186
+ {...FilterSlider.props}
187
+ {...filter}
188
+ title={filterCmsData?.title}
189
+ clearButtonLabel={filterCmsData?.mobileOnly?.clearButtonLabel}
190
+ applyButtonLabel={filterCmsData?.mobileOnly?.applyButtonLabel}
191
+ />
192
+ </div>
193
+ )}
194
+ <div data-fs-product-listing-results-count data-count={totalCount}>
195
+ <ResultsCountSkeleton.Component
196
+ data-fs-product-listing-results-count-skeleton
197
+ size={{ width: '100%', height: '1.5rem' }}
198
+ {...ResultsCountSkeleton.props}
199
+ // Dynamic props shouldn't be overridable
200
+ // This decision can be reviewed later if needed
201
+ loading={!hasProductsLoaded}
202
+ >
203
+ <h2 data-testid="total-product-count">
204
+ {totalCount} {totalCountLabel}
205
+ </h2>
206
+ </ResultsCountSkeleton.Component>
207
+ {productComparison?.enabled && (
208
+ <ToggleField.Component
209
+ id="toggle-field-comparison"
210
+ label={productComparison?.labels?.compareButton}
211
+ checked={showComparisonProducts}
212
+ onChange={() =>
213
+ setShowComparisonProducts(!showComparisonProducts)
214
+ }
215
+ {...ToggleField.props}
216
+ />
217
+ )}
218
+ </div>
219
+
220
+ <div data-fs-product-listing-sort>
221
+ <SortSkeleton.Component
222
+ data-fs-product-listing-sort-skeleton
223
+ size={{ width: 'auto', height: '1.5rem' }}
224
+ {...SortSkeleton.props}
225
+ // Dynamic props shouldn't be overridable
226
+ // This decision can be reviewed later if needed
227
+ loading={!hasProductsLoaded}
228
+ >
229
+ <Sort
230
+ label={sortBySelector?.label}
231
+ options={sortBySelector?.options}
232
+ />
233
+ </SortSkeleton.Component>
234
+ <FilterButtonSkeleton.Component
235
+ data-fs-product-listing-filter-button-skeleton
236
+ size={{ width: '6rem', height: '1.5rem' }}
237
+ {...FilterButtonSkeleton.props}
238
+ // Dynamic props shouldn't be overridable
239
+ // This decision can be reviewed later if needed
240
+ loading={!hasFacetsLoaded}
241
+ >
135
242
  {hasFacetsLoaded && facets?.length > 0 && (
136
- <div className="hidden-mobile">
137
- <FilterDesktop.Component
138
- {...FilterDesktop.props}
139
- {...filter}
140
- title={filterCmsData?.title}
141
- />
142
- </div>
243
+ <MobileFilterButton.Component
244
+ variant="tertiary"
245
+ data-testid="open-filter-button"
246
+ icon={
247
+ <FilterIcon.Component
248
+ width={16}
249
+ height={16}
250
+ {...FilterIcon.props}
251
+ name={
252
+ filterCmsData?.mobileOnly?.filterButton?.icon?.icon ??
253
+ FilterIcon.props.name
254
+ }
255
+ aria-label={
256
+ filterCmsData?.mobileOnly?.filterButton?.icon?.alt ??
257
+ FilterIcon.props['aria-label']
258
+ }
259
+ />
260
+ }
261
+ iconPosition="left"
262
+ {...MobileFilterButton.props}
263
+ // Dynamic props shouldn't be overridable
264
+ // This decision can be reviewed later if needed
265
+ onClick={openFilter}
266
+ >
267
+ {filterCmsData?.mobileOnly?.filterButton?.label}
268
+ </MobileFilterButton.Component>
143
269
  )}
144
- </FilterSkeleton>
270
+ </FilterButtonSkeleton.Component>
145
271
  </div>
146
- )}
147
- {!isDesktop && displayFilter && (
148
- <div data-fs-product-listing-filters>
149
- <FilterSlider.Component
150
- {...FilterSlider.props}
151
- {...filter}
152
- title={filterCmsData?.title}
153
- clearButtonLabel={filterCmsData?.mobileOnly?.clearButtonLabel}
154
- applyButtonLabel={filterCmsData?.mobileOnly?.applyButtonLabel}
155
- />
156
- </div>
157
- )}
158
- <div data-fs-product-listing-results-count data-count={totalCount}>
159
- <ResultsCountSkeleton.Component
160
- data-fs-product-listing-results-count-skeleton
161
- size={{ width: '100%', height: '1.5rem' }}
162
- {...ResultsCountSkeleton.props}
163
- // Dynamic props shouldn't be overridable
164
- // This decision can be reviewed later if needed
165
- loading={!hasProductsLoaded}
166
- >
167
- <h2 data-testid="total-product-count">
168
- {totalCount} {totalCountLabel}
169
- </h2>
170
- </ResultsCountSkeleton.Component>
171
- </div>
172
- <div data-fs-product-listing-sort>
173
- <SortSkeleton.Component
174
- data-fs-product-listing-sort-skeleton
175
- size={{ width: 'auto', height: '1.5rem' }}
176
- {...SortSkeleton.props}
177
- // Dynamic props shouldn't be overridable
178
- // This decision can be reviewed later if needed
179
- loading={!hasProductsLoaded}
180
- >
181
- <Sort
182
- label={sortBySelector?.label}
183
- options={sortBySelector?.options}
184
- />
185
- </SortSkeleton.Component>
186
- <FilterButtonSkeleton.Component
187
- data-fs-product-listing-filter-button-skeleton
188
- size={{ width: '6rem', height: '1.5rem' }}
189
- {...FilterButtonSkeleton.props}
190
- // Dynamic props shouldn't be overridable
191
- // This decision can be reviewed later if needed
192
- loading={!hasFacetsLoaded}
193
- >
194
- {hasFacetsLoaded && facets?.length > 0 && (
195
- <MobileFilterButton.Component
196
- variant="tertiary"
197
- data-testid="open-filter-button"
198
- icon={
199
- <FilterIcon.Component
200
- width={16}
201
- height={16}
202
- {...FilterIcon.props}
203
- name={
204
- filterCmsData?.mobileOnly?.filterButton?.icon?.icon ??
205
- FilterIcon.props.name
206
- }
207
- aria-label={
208
- filterCmsData?.mobileOnly?.filterButton?.icon?.alt ??
209
- FilterIcon.props['aria-label']
210
- }
211
- />
212
- }
213
- iconPosition="left"
214
- {...MobileFilterButton.props}
215
- // Dynamic props shouldn't be overridable
216
- // This decision can be reviewed later if needed
217
- onClick={openFilter}
218
- >
219
- {filterCmsData?.mobileOnly?.filterButton?.label}
220
- </MobileFilterButton.Component>
272
+ <div data-fs-product-listing-results>
273
+ {/* Add link to previous page. This helps on SEO */}
274
+ {!!prev && (
275
+ <div data-fs-product-listing-pagination="top">
276
+ <NextSeo
277
+ additionalLinkTags={[{ rel: 'prev', href: prev.link }]}
278
+ />
279
+ <LinkButtonPrev.Component
280
+ rel="prev"
281
+ variant="secondary"
282
+ iconPosition="left"
283
+ icon={
284
+ <PrevIcon.Component
285
+ width={16}
286
+ height={16}
287
+ weight="bold"
288
+ {...PrevIcon.props}
289
+ name={
290
+ previousPageButton?.icon?.icon ?? PrevIcon.props.name
291
+ }
292
+ aria-label={
293
+ previousPageButton?.icon?.alt ??
294
+ previousPageButton?.label ??
295
+ PrevIcon.props['aria-label']
296
+ }
297
+ />
298
+ }
299
+ {...LinkButtonPrev.props}
300
+ // Dynamic props shouldn't be overridable
301
+ // This decision can be reviewed later if needed
302
+ onClick={(e: MouseEvent<HTMLElement>) => {
303
+ e.currentTarget.blur()
304
+ e.preventDefault()
305
+ addPrevPage()
306
+ }}
307
+ href={prev.link}
308
+ >
309
+ {previousPageButton?.label}
310
+ </LinkButtonPrev.Component>
311
+ </div>
221
312
  )}
222
- </FilterButtonSkeleton.Component>
223
- </div>
224
- <div data-fs-product-listing-results>
225
- {/* Add link to previous page. This helps on SEO */}
226
- {prev !== false && (
227
- <div data-fs-product-listing-pagination="top">
228
- <NextSeo
229
- additionalLinkTags={[{ rel: 'prev', href: prev.link }]}
230
- />
231
- <LinkButtonPrev.Component
232
- rel="prev"
233
- variant="secondary"
234
- iconPosition="left"
235
- icon={
236
- <PrevIcon.Component
237
- width={16}
238
- height={16}
239
- weight="bold"
240
- {...PrevIcon.props}
241
- name={previousPageButton?.icon?.icon ?? PrevIcon.props.name}
242
- aria-label={
243
- previousPageButton?.icon?.alt ??
244
- previousPageButton?.label ??
245
- PrevIcon.props['aria-label']
246
- }
313
+ {/* Render ALL products */}
314
+ {hasProductsLoaded ? (
315
+ <Suspense fallback={GalleryPageSkeleton}>
316
+ {pages.map((page) => (
317
+ <ProductGalleryPage
318
+ key={`gallery-page-${page}`}
319
+ page={page}
320
+ title={title}
321
+ productCard={productCard}
322
+ itemsPerPage={itemsPerPage}
323
+ firstPage={pages[0]}
324
+ shouldShowComparison={showComparisonProducts}
325
+ compareLabel={productComparison?.labels?.compareButton}
247
326
  />
248
- }
249
- {...LinkButtonPrev.props}
250
- // Dynamic props shouldn't be overridable
251
- // This decision can be reviewed later if needed
252
- onClick={(e: MouseEvent<HTMLElement>) => {
253
- e.currentTarget.blur()
254
- e.preventDefault()
255
- addPrevPage()
256
- }}
257
- href={prev.link}
258
- >
259
- {previousPageButton?.label}
260
- </LinkButtonPrev.Component>
261
- </div>
262
- )}
263
- {/* Render ALL products */}
264
- {hasProductsLoaded ? (
265
- <Suspense fallback={GalleryPageSkeleton}>
266
- {pages.map((page) => (
267
- <ProductGalleryPage
268
- key={`gallery-page-${page}`}
269
- page={page}
270
- title={title}
271
- productCard={productCard}
272
- itemsPerPage={itemsPerPage}
273
- firstPage={pages[0]}
327
+ ))}
328
+ </Suspense>
329
+ ) : (
330
+ GalleryPageSkeleton
331
+ )}
332
+ {/* Add link to next page. This helps on SEO */}
333
+ {next !== false && (
334
+ <div data-fs-product-listing-pagination="bottom">
335
+ <NextSeo
336
+ additionalLinkTags={[{ rel: 'next', href: next.link }]}
274
337
  />
275
- ))}
276
- </Suspense>
277
- ) : (
278
- GalleryPageSkeleton
279
- )}
280
- {/* Add link to next page. This helps on SEO */}
281
- {next !== false && (
282
- <div data-fs-product-listing-pagination="bottom">
283
- <NextSeo
284
- additionalLinkTags={[{ rel: 'next', href: next.link }]}
285
- />
286
- <LinkButtonNext.Component
287
- testId="show-more"
288
- rel="next"
289
- variant="secondary"
290
- {...LinkButtonNext.props}
291
- // Dynamic props shouldn't be overridable
292
- // This decision can be reviewed later if needed
293
- onClick={(e: MouseEvent<HTMLElement>) => {
294
- e.currentTarget.blur()
295
- e.preventDefault()
296
- addNextPage()
297
- }}
298
- href={next.link}
299
- >
300
- {loadMorePageButton?.label}
301
- </LinkButtonNext.Component>
302
- </div>
303
- )}
338
+ <LinkButtonNext.Component
339
+ testId="show-more"
340
+ rel="next"
341
+ variant="secondary"
342
+ {...LinkButtonNext.props}
343
+ // Dynamic props shouldn't be overridable
344
+ // This decision can be reviewed later if needed
345
+ onClick={(e: MouseEvent<HTMLElement>) => {
346
+ e.currentTarget.blur()
347
+ e.preventDefault()
348
+ addNextPage()
349
+ }}
350
+ href={next.link}
351
+ >
352
+ {loadMorePageButton?.label}
353
+ </LinkButtonNext.Component>
354
+ </div>
355
+ )}
356
+ </div>
304
357
  </div>
305
- </div>
358
+ {showComparisonProducts && (
359
+ <>
360
+ <ProductComparisonSidebar.Component
361
+ direction="rightSide"
362
+ size="partial"
363
+ priceFormatter={useFormattedPrice}
364
+ technicalInformation={{
365
+ title: productComparison?.labels?.technicalInformation?.title,
366
+ description:
367
+ productComparison?.labels?.technicalInformation?.description,
368
+ }}
369
+ overlayProps={{ className: styles.section }}
370
+ {...productComparison.labels.sidebarComponent}
371
+ />
372
+ <ProductComparisonToolbar.Component
373
+ selectionWarningLabel={
374
+ productComparison?.labels?.selectionWarning
375
+ }
376
+ clearSelectionButtonLabel={
377
+ productComparison?.labels?.clearSelectionButton
378
+ }
379
+ compareButtonLabel={productComparison?.labels?.compareButton}
380
+ />
381
+ </>
382
+ )}
383
+ </ProductComparison.Component>
306
384
  </section>
307
385
  )
308
386
  }
@@ -14,6 +14,8 @@ interface Props {
14
14
  >
15
15
  itemsPerPage: number
16
16
  firstPage: number
17
+ shouldShowComparison?: boolean
18
+ compareLabel?: string
17
19
  }
18
20
 
19
21
  function ProductGalleryPage({
@@ -22,6 +24,8 @@ function ProductGalleryPage({
22
24
  productCard,
23
25
  itemsPerPage,
24
26
  firstPage,
27
+ shouldShowComparison,
28
+ compareLabel,
25
29
  }: Props) {
26
30
  const { data } = useGalleryPage(page)
27
31
 
@@ -35,6 +39,8 @@ function ProductGalleryPage({
35
39
  title={title}
36
40
  >
37
41
  <ProductGrid
42
+ shouldShowComparison={shouldShowComparison}
43
+ compareLabel={compareLabel}
38
44
  products={products}
39
45
  page={page}
40
46
  pageSize={itemsPerPage}
package/src/pages/s.tsx CHANGED
@@ -98,8 +98,9 @@ function generateSEOData(storeConfig: StoreConfig, searchTerm?: string) {
98
98
  function Page({
99
99
  page: searchContentType,
100
100
  globalSections: globalSectionsProp,
101
- searchTerm,
101
+ searchTerm: serverSearchTerm,
102
102
  }: SearchPageProps) {
103
+ const router = useRouter()
103
104
  const { sections: globalSections, settings: globalSettings } =
104
105
  globalSectionsProp ?? {}
105
106
  const { settings } = searchContentType
@@ -109,6 +110,11 @@ function Page({
109
110
  })
110
111
 
111
112
  const itemsPerPage = settings?.productGallery?.itemsPerPage ?? ITEMS_PER_PAGE
113
+ const searchTerm =
114
+ serverSearchTerm ??
115
+ (router.query?.q as string) ??
116
+ searchParams.term ??
117
+ undefined
112
118
 
113
119
  if (!searchParams) {
114
120
  return null
@@ -144,10 +150,7 @@ function Page({
144
150
  <SearchWrapper
145
151
  itemsPerPage={itemsPerPage}
146
152
  searchContentType={searchContentType}
147
- serverData={{
148
- title: seoData.title,
149
- searchTerm: searchTerm ?? searchParams.term ?? undefined,
150
- }}
153
+ serverData={{ title: seoData.title, searchTerm }}
151
154
  globalSections={globalSections}
152
155
  globalSettings={globalSettings}
153
156
  />