@faststore/core 3.66.0 → 3.68.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 (251) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +74 -74
  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 +87 -72
  12. package/.next/routes-manifest.json +1 -1
  13. package/.next/server/chunks/1333.js +1 -0
  14. package/.next/server/chunks/2778.js +2 -2
  15. package/.next/server/chunks/2792.js +1 -1
  16. package/.next/server/chunks/3006.js +1 -1
  17. package/.next/server/chunks/3836.js +1 -1
  18. package/.next/server/chunks/3918.js +1 -1
  19. package/.next/server/chunks/3963.js +1 -1
  20. package/.next/server/chunks/6789.js +1 -1
  21. package/.next/server/chunks/7178.js +1 -1
  22. package/.next/server/chunks/7228.js +1 -1
  23. package/.next/server/chunks/7794.js +1 -1
  24. package/.next/server/chunks/83.js +1 -1
  25. package/.next/server/chunks/831.js +1 -1
  26. package/.next/server/chunks/839.js +1 -0
  27. package/.next/server/chunks/8569.js +1 -1
  28. package/.next/server/chunks/8687.js +1 -1
  29. package/.next/server/chunks/948.js +2 -2
  30. package/.next/server/chunks/9563.js +2 -2
  31. package/.next/server/chunks/9630.js +4 -4
  32. package/.next/server/chunks/UIBannerText.js +1 -1
  33. package/.next/server/functions-config-manifest.json +1 -1
  34. package/.next/server/middleware-build-manifest.js +1 -1
  35. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  36. package/.next/server/pages/404.js +1 -1
  37. package/.next/server/pages/404.js.nft.json +1 -1
  38. package/.next/server/pages/500.js +1 -1
  39. package/.next/server/pages/500.js.nft.json +1 -1
  40. package/.next/server/pages/[...slug].js +1 -1
  41. package/.next/server/pages/[...slug].js.nft.json +1 -1
  42. package/.next/server/pages/[slug]/p.js +1 -1
  43. package/.next/server/pages/[slug]/p.js.nft.json +1 -1
  44. package/.next/server/pages/_app.js.nft.json +1 -1
  45. package/.next/server/pages/_document.js.nft.json +1 -1
  46. package/.next/server/pages/_error.js.nft.json +1 -1
  47. package/.next/server/pages/account/403.js +1 -1
  48. package/.next/server/pages/account/403.js.nft.json +1 -1
  49. package/.next/server/pages/account/404.js +1 -1
  50. package/.next/server/pages/account/404.js.nft.json +1 -1
  51. package/.next/server/pages/account/[...unknown].js.nft.json +1 -1
  52. package/.next/server/pages/account/orders/[id].js +1 -1
  53. package/.next/server/pages/account/orders/[id].js.nft.json +1 -1
  54. package/.next/server/pages/account/orders.js +1 -1
  55. package/.next/server/pages/account/orders.js.nft.json +1 -1
  56. package/.next/server/pages/account/profile.js +1 -1
  57. package/.next/server/pages/account/profile.js.nft.json +1 -1
  58. package/.next/server/pages/account/security.js +1 -1
  59. package/.next/server/pages/account/security.js.nft.json +1 -1
  60. package/.next/server/pages/account/user-details.js +1 -1
  61. package/.next/server/pages/account/user-details.js.nft.json +1 -1
  62. package/.next/server/pages/account.js.nft.json +1 -1
  63. package/.next/server/pages/api/graphql.js +2 -2
  64. package/.next/server/pages/api/graphql.js.nft.json +1 -1
  65. package/.next/server/pages/api/health/live.js.nft.json +1 -1
  66. package/.next/server/pages/api/health/ready.js.nft.json +1 -1
  67. package/.next/server/pages/api/preview.js +1 -1
  68. package/.next/server/pages/api/preview.js.nft.json +1 -1
  69. package/.next/server/pages/checkout.js +1 -1
  70. package/.next/server/pages/checkout.js.nft.json +1 -1
  71. package/.next/server/pages/en-US/404.html +1 -1
  72. package/.next/server/pages/en-US/500.html +1 -1
  73. package/.next/server/pages/en-US/checkout.html +1 -1
  74. package/.next/server/pages/en-US/login.html +1 -1
  75. package/.next/server/pages/en-US/s.html +1 -1
  76. package/.next/server/pages/en-US.html +1 -1
  77. package/.next/server/pages/index.js +1 -1
  78. package/.next/server/pages/index.js.nft.json +1 -1
  79. package/.next/server/pages/login.js +1 -1
  80. package/.next/server/pages/login.js.nft.json +1 -1
  81. package/.next/server/pages/s.js +1 -1
  82. package/.next/server/pages/s.js.nft.json +1 -1
  83. package/.next/server/pages-manifest.json +1 -1
  84. package/.next/static/chunks/2284.6dd050e60172189a.js +1 -0
  85. package/.next/static/chunks/3155.243c7558a71f0695.js +1 -0
  86. package/.next/static/chunks/3166-6af5e854c2f2913a.js +1 -0
  87. package/.next/static/chunks/3399.93804fb74f79436c.js +1 -0
  88. package/.next/static/chunks/353.7f2181843462717d.js +1 -0
  89. package/.next/static/chunks/4803.412bf2a7e15626a6.js +1 -0
  90. package/.next/static/chunks/5781.28d03feacead66ad.js +1 -0
  91. package/.next/static/chunks/6355.57d1a07f50ee6cc9.js +1 -0
  92. package/.next/static/chunks/{6393.361c44eb0818eb7e.js → 6393.53e9ea4f29d1bf23.js} +1 -1
  93. package/.next/static/chunks/6700.f046aa86e2c83b53.js +1 -0
  94. package/.next/static/chunks/6857.b2c06171638955ea.js +1 -0
  95. package/.next/static/chunks/7191-9bdd5f0c18fbd942.js +1 -0
  96. package/.next/static/chunks/{6410.bd3fa399df59cc80.js → 7351.e90a4cc21797c136.js} +1 -1
  97. package/.next/static/chunks/7481.3c4ad3642e346232.js +1 -0
  98. package/.next/static/chunks/7498-0dc4f9a9ed199d3a.js +1 -0
  99. package/.next/static/chunks/83.ee1fdbe283ac65b6.js +1 -0
  100. package/.next/static/chunks/9173-88b7ddf38554a5cf.js +1 -0
  101. package/.next/static/chunks/BannerNewsletter.a9ea51c53885c80f.js +1 -0
  102. package/.next/static/chunks/{BannerText.695d4d4b6a3f7309.js → BannerText.21f106b180339df1.js} +1 -1
  103. package/.next/static/chunks/CartSidebar.55cc31a37ffa6ee6.js +1 -0
  104. package/.next/static/chunks/{Footer.5ed205d931401110.js → Footer.09dddd47ce6c816f.js} +1 -1
  105. package/.next/static/chunks/Newsletter.2c79d1813e9f9c95.js +1 -0
  106. package/.next/static/chunks/ProductShelf.299d0989eea49a79.js +1 -0
  107. package/.next/static/chunks/ProductTiles.ab99b919f3c0215f.js +1 -0
  108. package/.next/static/chunks/RegionModal.503f063f2e19b936.js +1 -0
  109. package/.next/static/chunks/RegionSlider.00de4571775d04cc.js +1 -0
  110. package/.next/static/chunks/Toast.75a18f47eb23b703.js +1 -0
  111. package/.next/static/chunks/UIBannerText.f4167ceafb96cf67.js +1 -0
  112. package/.next/static/chunks/UISKUMatrixSidebar.8b6fac58c48f999c.js +1 -0
  113. package/.next/static/chunks/UIToast.a49584c87d3adc17.js +1 -0
  114. package/.next/static/chunks/pages/{404-3582ed9196afdf1e.js → 404-dca50618ea3e6fb6.js} +1 -1
  115. package/.next/static/chunks/pages/{500-1b4eca062588da7f.js → 500-ae6697c7631fb07a.js} +1 -1
  116. package/.next/static/chunks/pages/[...slug]-debd8b208a0e3d02.js +1 -0
  117. package/.next/static/chunks/pages/[slug]/p-d782ecb21200f200.js +1 -0
  118. package/.next/static/chunks/pages/_app-728289774860e9d9.js +1 -0
  119. package/.next/static/chunks/pages/account/{403-c791997011f970b6.js → 403-a3d8b31b4e9ee8a6.js} +1 -1
  120. package/.next/static/chunks/pages/account/{404-74e64bb12e8f5a68.js → 404-22b789f04fcdce39.js} +1 -1
  121. package/.next/static/chunks/pages/account/orders/[id]-a2f44ba3963b81cd.js +1 -0
  122. package/.next/static/chunks/pages/account/orders-ec040e06c4b516d0.js +1 -0
  123. package/.next/static/chunks/pages/account/profile-29f93f4c5a55bd87.js +1 -0
  124. package/.next/static/chunks/pages/account/security-94874fc477520f74.js +1 -0
  125. package/.next/static/chunks/pages/account/{user-details-6f9fe72e02f5c5df.js → user-details-143cb45d5080d1d9.js} +1 -1
  126. package/.next/static/chunks/pages/checkout-b0637ee59b1cdca8.js +1 -0
  127. package/.next/static/chunks/pages/index-b45c9535696b5ab1.js +1 -0
  128. package/.next/static/chunks/pages/login-bae3a4cdaaed110c.js +1 -0
  129. package/.next/static/chunks/pages/s-011eedb19dcdccc6.js +1 -0
  130. package/.next/static/chunks/webpack-8b6c086380cf1398.js +1 -0
  131. package/.next/static/css/{74e963fcd3434141.css → 118f0b6523312556.css} +1 -1
  132. package/.next/static/css/{e4b714970415f2eb.css → 2a4b7072e47636f1.css} +1 -1
  133. package/.next/static/css/{8a3f440e0ff9cd8e.css → 3d41485722b4e3f5.css} +1 -1
  134. package/.next/static/css/{2841bab51b99dd53.css → 92960607d6088082.css} +1 -1
  135. package/.next/static/css/d26cb0a54378b3d9.css +1 -0
  136. package/.next/static/css/f93cf36b16950027.css +1 -0
  137. package/.next/static/pRYrZEXsDEpvxbtvEobPH/_buildManifest.js +1 -0
  138. package/.next/trace +135 -132
  139. package/.turbo/turbo-build.log +36 -33
  140. package/.turbo/turbo-test.log +5 -5
  141. package/@generated/gql.ts +8 -0
  142. package/@generated/graphql.ts +83 -0
  143. package/@generated/persisted-documents.json +1 -0
  144. package/@generated/schema.graphql +51 -0
  145. package/CHANGELOG.md +12 -0
  146. package/cms/faststore/content-types.json +238 -1
  147. package/cms/faststore/sections.json +34 -33
  148. package/cypress/integration/plp.test.js +2 -2
  149. package/index.ts +9 -0
  150. package/package.json +6 -6
  151. package/src/components/cms/GlobalSections.tsx +1 -0
  152. package/src/components/cms/RenderSections.tsx +8 -4
  153. package/src/components/cms/global/Components.ts +8 -0
  154. package/src/components/common/PreviewTag/section.module.scss +2 -2
  155. package/src/components/navigation/Navbar/Navbar.tsx +5 -6
  156. package/src/components/navigation/NavbarLinks/NavbarLinks.tsx +23 -4
  157. package/src/components/region/RegionBar/RegionBar.tsx +48 -12
  158. package/src/components/region/RegionFilterButton/RegionFilterButton.tsx +57 -0
  159. package/src/components/region/RegionFilterButton/index.ts +1 -0
  160. package/src/components/region/RegionModal/RegionModal.tsx +26 -16
  161. package/src/components/region/RegionModal/useRegion.ts +12 -11
  162. package/src/components/region/RegionPopover/RegionPopover.tsx +37 -22
  163. package/src/components/region/RegionSlider/RegionSlider.tsx +407 -0
  164. package/src/components/region/RegionSlider/index.ts +1 -0
  165. package/src/components/region/RegionSlider/section.module.scss +72 -0
  166. package/src/components/search/Filter/FilterDeliveryMethodFacet.tsx +68 -0
  167. package/src/components/search/Filter/FilterDesktop.tsx +148 -90
  168. package/src/components/search/Filter/FilterSlider.tsx +193 -104
  169. package/src/components/search/Filter/section.module.scss +2 -0
  170. package/src/components/sections/ProductGallery/section.module.scss +2 -0
  171. package/src/components/sections/RegionBar/DefaultComponents.ts +1 -0
  172. package/src/components/sections/RegionBar/RegionBar.tsx +2 -1
  173. package/src/components/templates/LandingPage/LandingPage.tsx +6 -3
  174. package/src/components/templates/ProductListingPage/ProductListing.tsx +4 -1
  175. package/src/components/templates/ProductListingPage/ProductListingPage.tsx +3 -0
  176. package/src/components/templates/SearchPage/SearchPage.tsx +3 -0
  177. package/src/components/templates/SearchPage/SearchWrapper.tsx +15 -7
  178. package/src/components/ui/PickupPoints/PickupPointCard.tsx +39 -0
  179. package/src/components/ui/PickupPoints/PickupPointCards.tsx +102 -0
  180. package/src/components/ui/PickupPoints/index.ts +5 -0
  181. package/src/components/ui/ProductGallery/ProductGallery.tsx +6 -9
  182. package/src/experimental/index.ts +6 -0
  183. package/src/pages/404.tsx +15 -6
  184. package/src/pages/500.tsx +15 -6
  185. package/src/pages/[...slug].tsx +14 -5
  186. package/src/pages/[slug]/p.tsx +6 -3
  187. package/src/pages/_app.tsx +15 -10
  188. package/src/pages/account/403.tsx +30 -27
  189. package/src/pages/account/404.tsx +27 -20
  190. package/src/pages/account/orders/[id].tsx +22 -19
  191. package/src/pages/account/orders/index.tsx +25 -22
  192. package/src/pages/account/profile.tsx +27 -23
  193. package/src/pages/account/security.tsx +28 -23
  194. package/src/pages/account/user-details.tsx +20 -17
  195. package/src/pages/checkout.tsx +11 -8
  196. package/src/pages/index.tsx +7 -4
  197. package/src/pages/login.tsx +16 -7
  198. package/src/pages/s.tsx +5 -2
  199. package/src/sdk/deliveryPromise/index.ts +22 -0
  200. package/src/sdk/deliveryPromise/provider.tsx +119 -0
  201. package/src/sdk/deliveryPromise/queries.ts +80 -0
  202. package/src/sdk/deliveryPromise/reducer.ts +137 -0
  203. package/src/sdk/deliveryPromise/useDeliveryPromise.ts +419 -0
  204. package/src/sdk/overrides/PageProvider.tsx +9 -4
  205. package/src/sdk/product/useLocalizedVariables.ts +20 -6
  206. package/src/sdk/search/useFilter.ts +12 -1
  207. package/src/server/cms/index.ts +2 -0
  208. package/src/typings/overrides.ts +2 -1
  209. package/src/utils/globalSettings.ts +74 -0
  210. package/src/utils/utilities.ts +5 -0
  211. package/test/server/index.test.ts +1 -0
  212. package/.next/server/chunks/6272.js +0 -1
  213. package/.next/static/chunks/2284.1b43aea18c23c79e.js +0 -1
  214. package/.next/static/chunks/3155.ea52e06317dab557.js +0 -1
  215. package/.next/static/chunks/3166-50d81179a0f5a894.js +0 -1
  216. package/.next/static/chunks/3399.13a97fefb512c902.js +0 -1
  217. package/.next/static/chunks/3465.af28497e8069330f.js +0 -1
  218. package/.next/static/chunks/4803.de5b14237d616808.js +0 -1
  219. package/.next/static/chunks/4949.ea0775ca3029fb98.js +0 -1
  220. package/.next/static/chunks/6355.f1b1feefc0c84a2a.js +0 -1
  221. package/.next/static/chunks/6700.4e9426fe8b826dab.js +0 -1
  222. package/.next/static/chunks/7191-2a7b8ddbd07128b6.js +0 -1
  223. package/.next/static/chunks/7498-5246b607527180dd.js +0 -1
  224. package/.next/static/chunks/83.b87d797323ff2034.js +0 -1
  225. package/.next/static/chunks/9173-c1819846b9006c7a.js +0 -1
  226. package/.next/static/chunks/9540.69781e999f27cc05.js +0 -1
  227. package/.next/static/chunks/BannerNewsletter.7c592f132e7048e5.js +0 -1
  228. package/.next/static/chunks/CartSidebar.a00083c44c87c268.js +0 -1
  229. package/.next/static/chunks/Newsletter.1004055f09f76d3c.js +0 -1
  230. package/.next/static/chunks/ProductShelf.d51ba3e6a1b4a57d.js +0 -1
  231. package/.next/static/chunks/ProductTiles.77284431e2b8c898.js +0 -1
  232. package/.next/static/chunks/RegionModal.f61aa62e0a09182a.js +0 -1
  233. package/.next/static/chunks/Toast.6116bc845cd67f49.js +0 -1
  234. package/.next/static/chunks/UIBannerText.6cc5c00d4ba9b64e.js +0 -1
  235. package/.next/static/chunks/UISKUMatrixSidebar.782c55a97889e84a.js +0 -1
  236. package/.next/static/chunks/UIToast.494d0b0ce2c6106a.js +0 -1
  237. package/.next/static/chunks/pages/[...slug]-0db18c1c0920e8d2.js +0 -1
  238. package/.next/static/chunks/pages/[slug]/p-a255e4a7352455df.js +0 -1
  239. package/.next/static/chunks/pages/_app-1885a948b243078c.js +0 -1
  240. package/.next/static/chunks/pages/account/orders/[id]-b9feb0c860ff1cec.js +0 -1
  241. package/.next/static/chunks/pages/account/orders-1d8409a8b4b0e581.js +0 -1
  242. package/.next/static/chunks/pages/account/profile-5a919fa02b76a422.js +0 -1
  243. package/.next/static/chunks/pages/account/security-b5ab3d1ecbbea9d9.js +0 -1
  244. package/.next/static/chunks/pages/checkout-3a4983b22625c4e3.js +0 -1
  245. package/.next/static/chunks/pages/index-6e68be53d1fef20e.js +0 -1
  246. package/.next/static/chunks/pages/login-de3dd10c6b35159a.js +0 -1
  247. package/.next/static/chunks/pages/s-9b0f606f120d66b0.js +0 -1
  248. package/.next/static/chunks/webpack-a24b8ac1ca628dfe.js +0 -1
  249. package/.next/static/css/202a74b80e6ce63f.css +0 -1
  250. package/.next/static/pub-GYCLSosy4MirjEMnD/_buildManifest.js +0 -1
  251. /package/.next/static/{pub-GYCLSosy4MirjEMnD → pRYrZEXsDEpvxbtvEobPH}/_ssgManifest.js +0 -0
@@ -0,0 +1,419 @@
1
+ import deepEquals from 'fast-deep-equal'
2
+ import { useCallback, useEffect, useMemo } from 'react'
3
+
4
+ import {
5
+ createStore,
6
+ toggleFacets,
7
+ useSearch,
8
+ type SearchState,
9
+ type Session,
10
+ } from '@faststore/sdk'
11
+ import type { Filter_FacetsFragment } from '@generated/graphql'
12
+
13
+ import type { useFilter } from 'src/sdk/search/useFilter'
14
+ import { useSession } from 'src/sdk/session'
15
+ import type { GlobalCmsData } from 'src/utils/globalSettings'
16
+
17
+ import { deliveryPromise as deliveryPromiseConfig } from 'discovery.config'
18
+ import {
19
+ initialPickupPointsSimulation,
20
+ useDeliveryPromiseContext,
21
+ type PickupPointsSimulation,
22
+ } from '.'
23
+
24
+ export const PICKUP_POINT_FACET_KEY = 'pickupPoint' as const
25
+ export const SHIPPING_FACET_KEY = 'shipping' as const
26
+ export const PICKUP_IN_POINT_FACET_VALUE = 'pickup-in-point' as const
27
+ export const ALL_DELIVERY_METHODS_FACET_VALUE = 'all-delivery-methods' as const
28
+ export const PICKUP_ALL_FACET_VALUE = 'pickup-all' as const
29
+
30
+ type Facet = SearchState['selectedFacets'][number]
31
+
32
+ export type PickupPoint = {
33
+ id: string
34
+ name?: string
35
+ address?: {
36
+ street?: string
37
+ number?: string
38
+ postalCode?: string
39
+ city?: string
40
+ state?: string
41
+ }
42
+ distance?: number
43
+ totalItems?: number
44
+ }
45
+
46
+ export type DeliveryPromiseStore = {
47
+ pickupPoints?: PickupPoint[]
48
+ defaultPickupPoint?: PickupPoint | null
49
+ globalPickupPoint?: PickupPoint | null
50
+ shouldUpdatePickupPoints?: boolean
51
+ simulatePickupPoints?: boolean
52
+ pickupPointsSimulation?: PickupPointsSimulation
53
+ }
54
+
55
+ const baseStore = createStore<DeliveryPromiseStore>(
56
+ {
57
+ pickupPoints: [],
58
+ defaultPickupPoint: null,
59
+ globalPickupPoint: null,
60
+ shouldUpdatePickupPoints: false,
61
+ pickupPointsSimulation: undefined,
62
+ simulatePickupPoints: false,
63
+ },
64
+ 'fs::deliveryPromise'
65
+ )
66
+
67
+ export const deliveryPromiseStore = {
68
+ ...baseStore,
69
+ set: (state: Partial<DeliveryPromiseStore>) => {
70
+ const oldState = baseStore.read()
71
+ const newState = { ...oldState, ...state }
72
+
73
+ if (!deepEquals(oldState, newState)) {
74
+ baseStore.set(newState)
75
+ }
76
+ },
77
+ }
78
+
79
+ type Props = {
80
+ deliveryPromiseSettings?: GlobalCmsData['deliveryPromise']
81
+ allFacets?: ReturnType<typeof useFilter>['facets']
82
+ fallbackToFirstPickupPoint?: boolean
83
+ selectedFilterFacets?: Facet[]
84
+ }
85
+
86
+ /**
87
+ * @param fallbackToFirstPickupPoint When true, the first available pickup point will be used as the pickup-in-point facet
88
+ * when the shopper has not yet explicitly chosen a pickup point.
89
+ */
90
+ export function useDeliveryPromise({
91
+ allFacets,
92
+ selectedFilterFacets = undefined,
93
+ deliveryPromiseSettings,
94
+ fallbackToFirstPickupPoint = true,
95
+ }: Props = {}) {
96
+ const { postalCode } = useSession()
97
+ const { state: searchState, setState: setSearchState } = useSearch()
98
+ const {
99
+ pickupPoints,
100
+ defaultPickupPoint,
101
+ globalPickupPoint,
102
+ pickupPointsSimulation,
103
+ dispatchDeliveryPromiseAction,
104
+ shouldUpdatePickupPoints,
105
+ } = useDeliveryPromiseContext()
106
+
107
+ const isDeliveryPromiseEnabled = deliveryPromiseConfig.enabled
108
+
109
+ const selectedFacets = useMemo(
110
+ () => selectedFilterFacets ?? searchState.selectedFacets,
111
+ [selectedFilterFacets, searchState.selectedFacets]
112
+ )
113
+ const selectedPickupPointFacet = useMemo(
114
+ () =>
115
+ selectedFacets.find(({ key }) => key === PICKUP_POINT_FACET_KEY)?.value,
116
+ [selectedFacets]
117
+ )
118
+
119
+ // Update Delivery Promise global state after store changes
120
+ useEffect(() => {
121
+ const unsubscribers = [
122
+ deliveryPromiseStore.subscribe((storeValue) => {
123
+ dispatchDeliveryPromiseAction({
124
+ type: 'updateDeliveryPromiseState',
125
+ payload: storeValue,
126
+ })
127
+ }),
128
+ ]
129
+
130
+ return () => {
131
+ unsubscribers.forEach((unsub) => unsub())
132
+ }
133
+ }, [])
134
+
135
+ // Set the default selected pickup point based on pickup points list
136
+ useEffect(() => {
137
+ if (pickupPoints.length === 0) return
138
+
139
+ deliveryPromiseStore.set({
140
+ defaultPickupPoint: pickupPointByID(selectedPickupPointFacet),
141
+ })
142
+ }, [pickupPoints, selectedPickupPointFacet])
143
+
144
+ // Validate if should select the global pickup point facet in the first load
145
+ useEffect(() => {
146
+ const hasShippingFacetSelected = selectedFacets.some(
147
+ ({ key }) => key === SHIPPING_FACET_KEY
148
+ )
149
+ const shouldSelectGlobalPickupPoint =
150
+ !!globalPickupPoint && !hasShippingFacetSelected
151
+
152
+ if (shouldSelectGlobalPickupPoint) {
153
+ setSearchState({
154
+ selectedFacets: toggleFacets(
155
+ selectedFacets,
156
+ [
157
+ { key: SHIPPING_FACET_KEY, value: PICKUP_IN_POINT_FACET_VALUE },
158
+ {
159
+ key: PICKUP_POINT_FACET_KEY,
160
+ value: globalPickupPoint.id,
161
+ },
162
+ ],
163
+ true
164
+ ),
165
+ page: 0,
166
+ })
167
+ }
168
+ }, [])
169
+
170
+ const pickupPointByID = useCallback(
171
+ (pickupPointId: string) => {
172
+ if (!pickupPoints?.length) return
173
+
174
+ const preferredPickupPoint =
175
+ pickupPoints?.find(({ id }) => id === pickupPointId) ??
176
+ defaultPickupPoint ??
177
+ globalPickupPoint
178
+
179
+ if (fallbackToFirstPickupPoint && !preferredPickupPoint) {
180
+ return pickupPoints[0]
181
+ }
182
+
183
+ return preferredPickupPoint
184
+ },
185
+ [pickupPoints, defaultPickupPoint, globalPickupPoint]
186
+ )
187
+
188
+ const pickupInPointFacet = useMemo(
189
+ () => ({
190
+ value: PICKUP_IN_POINT_FACET_VALUE,
191
+ label: defaultPickupPoint?.name ?? defaultPickupPoint?.address.street,
192
+ selected: selectedFacets?.some(
193
+ ({ key, value }) =>
194
+ value === PICKUP_IN_POINT_FACET_VALUE ||
195
+ key === PICKUP_POINT_FACET_KEY
196
+ ),
197
+ quantity: defaultPickupPoint?.totalItems,
198
+ }),
199
+ [defaultPickupPoint, selectedFacets]
200
+ )
201
+
202
+ const allDeliveryMethodsFacet = useMemo(
203
+ () => ({
204
+ value: ALL_DELIVERY_METHODS_FACET_VALUE,
205
+ label:
206
+ deliveryPromiseSettings?.deliveryMethods?.allDeliveryMethods ??
207
+ 'All delivery methods',
208
+ selected:
209
+ !selectedFacets.some((facet) => facet.key === SHIPPING_FACET_KEY) ||
210
+ selectedFacets?.some(
211
+ (facet) =>
212
+ facet.key === SHIPPING_FACET_KEY &&
213
+ facet.value === ALL_DELIVERY_METHODS_FACET_VALUE
214
+ ),
215
+ quantity: 0,
216
+ }),
217
+ [selectedFacets, deliveryPromiseSettings, pickupInPointFacet]
218
+ )
219
+
220
+ const onDeliveryFacetChange = useCallback(
221
+ ({
222
+ facet = null,
223
+ facets = [],
224
+ filterDispatch,
225
+ }: {
226
+ facet?: Facet
227
+ facets?: Facet[]
228
+ filterDispatch?: ReturnType<typeof useFilter>['dispatch']
229
+ }) => {
230
+ let unique = true
231
+ const facetsToToggle: Facet[] = facets?.length !== 0 ? facets : [facet]
232
+ let currentSelectedFacets = selectedFacets
233
+
234
+ // Toggle `pickup-in-point` and `pickupPoint` facets
235
+ if (facet?.value === PICKUP_IN_POINT_FACET_VALUE) {
236
+ facetsToToggle.push({
237
+ key: PICKUP_POINT_FACET_KEY,
238
+ value: defaultPickupPoint?.id,
239
+ })
240
+ } else {
241
+ // Toggle previously selected pickupPoint facet
242
+ unique = isRadioFacet(facet?.key)
243
+ currentSelectedFacets = currentSelectedFacets.filter(
244
+ ({ key }) => key !== PICKUP_POINT_FACET_KEY
245
+ )
246
+ facetsToToggle.concat(currentSelectedFacets)
247
+ }
248
+
249
+ // Filter Slider should dispatch filter actions
250
+ if (filterDispatch) {
251
+ filterDispatch({
252
+ type: 'toggleFacets',
253
+ payload: { unique, facets: facetsToToggle },
254
+ })
255
+
256
+ return
257
+ }
258
+
259
+ setSearchState({
260
+ selectedFacets: toggleFacets(
261
+ currentSelectedFacets,
262
+ facetsToToggle,
263
+ unique
264
+ ),
265
+ page: 0,
266
+ })
267
+ },
268
+ [selectedFacets, defaultPickupPoint]
269
+ )
270
+
271
+ const facets = useMemo(() => {
272
+ if (!allFacets) return []
273
+
274
+ return !isDeliveryPromiseEnabled || !postalCode
275
+ ? allFacets.filter(({ key }) => key !== SHIPPING_FACET_KEY)
276
+ : allFacets.map((facet) => {
277
+ if (
278
+ facet.key !== SHIPPING_FACET_KEY ||
279
+ facet.__typename !== 'StoreFacetBoolean'
280
+ )
281
+ return facet
282
+
283
+ facet.values = withUniqueFacet(facet.values, allDeliveryMethodsFacet)
284
+ const pickupInPointFacetIndex = facet.values.findIndex(
285
+ (item) => item?.value === PICKUP_IN_POINT_FACET_VALUE
286
+ )
287
+
288
+ // Remove old pickup `pickup in point` facet from list and search state
289
+ if (pickupInPointFacetIndex !== -1 && !defaultPickupPoint) {
290
+ const selectedShippingFacet = selectedFacets.find(
291
+ ({ key }) => key === SHIPPING_FACET_KEY
292
+ )
293
+
294
+ if (selectedShippingFacet) {
295
+ const selectedPickupInPointFacets = selectedFacets.filter(
296
+ ({ key, value }) =>
297
+ value === PICKUP_IN_POINT_FACET_VALUE ||
298
+ key === PICKUP_POINT_FACET_KEY
299
+ )
300
+
301
+ selectedPickupInPointFacets.length
302
+ ? onDeliveryFacetChange({ facets: selectedPickupInPointFacets })
303
+ : onDeliveryFacetChange({ facet: selectedShippingFacet })
304
+ }
305
+
306
+ // Removes pickupInPointIndex from array
307
+ facet.values = facet.values.filter(
308
+ (_, index) => index !== pickupInPointFacetIndex
309
+ )
310
+ }
311
+ // Prevent multiple `pickup in point` facet
312
+ else if (pickupInPointFacetIndex === -1 && defaultPickupPoint) {
313
+ facet.values.push(pickupInPointFacet)
314
+ }
315
+ // Replace current `pickup-in-point` facet with the updated one
316
+ else if (
317
+ facet.values[pickupInPointFacetIndex] &&
318
+ facet.values[pickupInPointFacetIndex]?.label !==
319
+ pickupInPointFacet.label
320
+ ) {
321
+ facet.values[pickupInPointFacetIndex] = pickupInPointFacet
322
+ }
323
+
324
+ facet.values = facet.values.sort((a, b) =>
325
+ (a.value ?? '').localeCompare(b.value ?? '')
326
+ )
327
+
328
+ return facet
329
+ })
330
+ }, [
331
+ allDeliveryMethodsFacet,
332
+ pickupInPointFacet,
333
+ allFacets,
334
+ defaultPickupPoint,
335
+ globalPickupPoint,
336
+ pickupPoints,
337
+ selectedFacets,
338
+ onDeliveryFacetChange,
339
+ selectedPickupPointFacet,
340
+ ])
341
+
342
+ const onPostalCodeChange = useCallback(
343
+ ({
344
+ simulatePickupPoints = false,
345
+ validatedSession = null,
346
+ }: { simulatePickupPoints?: boolean; validatedSession?: Session } = {}) => {
347
+ const partialSession = {
348
+ country: validatedSession?.country,
349
+ postalCode: validatedSession?.postalCode,
350
+ geoCoordinates: validatedSession?.geoCoordinates,
351
+ }
352
+
353
+ dispatchDeliveryPromiseAction({
354
+ type: 'onPostalCodeChange',
355
+ ...(simulatePickupPoints
356
+ ? {
357
+ payload: {
358
+ simulatePickupPoints,
359
+ validatedSession: { ...partialSession },
360
+ },
361
+ }
362
+ : undefined),
363
+ })
364
+ },
365
+ []
366
+ )
367
+
368
+ const clearPickupPointsSimulation = useCallback(
369
+ () =>
370
+ deliveryPromiseStore.set({
371
+ pickupPointsSimulation: initialPickupPointsSimulation,
372
+ }),
373
+ []
374
+ )
375
+
376
+ return {
377
+ mandatory: deliveryPromiseConfig.mandatory,
378
+ isEnabled: isDeliveryPromiseEnabled,
379
+ pickupPoints,
380
+ defaultPickupPoint,
381
+ selectedPickupPointFacet,
382
+ pickupPointsSimulation,
383
+ clearPickupPointsSimulation,
384
+ fetchingPickupPoints: shouldUpdatePickupPoints,
385
+ changePickupPoint: (pickupPoint: PickupPoint) => {
386
+ deliveryPromiseStore.set({ defaultPickupPoint: pickupPoint })
387
+ },
388
+ globalPickupPoint,
389
+ changeGlobalPickupPoint: (pickupPoint: PickupPoint) => {
390
+ deliveryPromiseStore.set({ globalPickupPoint: pickupPoint })
391
+ },
392
+ pickupPointByID,
393
+ facets,
394
+ onPostalCodeChange,
395
+ onDeliveryFacetChange,
396
+ deliveryLabel:
397
+ deliveryPromiseSettings?.deliveryMethods?.title ?? 'Delivery',
398
+ isPickupAllEnabled:
399
+ pickupPoints?.length > 0 &&
400
+ (deliveryPromiseSettings?.deliveryMethods?.pickupAll?.enabled ?? false),
401
+ shouldDisplayDeliveryButton: isDeliveryPromiseEnabled && !postalCode,
402
+ }
403
+ }
404
+
405
+ type BoleanFacet = Extract<
406
+ Filter_FacetsFragment,
407
+ { __typename: 'StoreFacetBoolean' }
408
+ >['values'][number]
409
+
410
+ function withUniqueFacet(facets: Array<BoleanFacet>, facet: BoleanFacet) {
411
+ return facets.filter((item) => item.value !== facet.value).concat([facet])
412
+ }
413
+
414
+ const RADIO_FACETS = ['shipping', 'pickupPoint'] as const
415
+ function isRadioFacet(facet: unknown): facet is (typeof RADIO_FACETS)[number] {
416
+ if (typeof facet !== 'string') return false
417
+
418
+ return RADIO_FACETS.some((el) => el === facet)
419
+ }
@@ -9,26 +9,30 @@ import type { PropsWithChildren } from 'react'
9
9
  import { createContext, useContext, useMemo } from 'react'
10
10
  import type { SearchPageContextType } from 'src/pages/s'
11
11
 
12
- export interface PDPContext {
12
+ interface PageGlobalContext {
13
+ globalSettings?: Record<string, unknown>
14
+ }
15
+
16
+ export interface PDPContext extends PageGlobalContext {
13
17
  data?: ServerProductQueryQuery &
14
18
  ClientProductQueryQuery['product'] & { isValidating?: boolean }
15
19
  }
16
20
 
17
- export interface PLPContext {
21
+ export interface PLPContext extends PageGlobalContext {
18
22
  data?: ServerCollectionPageQueryQuery &
19
23
  ClientProductGalleryQueryQuery & {
20
24
  pages: ClientManyProductsQueryQuery[]
21
25
  }
22
26
  }
23
27
 
24
- export interface SearchPageContext {
28
+ export interface SearchPageContext extends PageGlobalContext {
25
29
  data?: SearchPageContextType &
26
30
  ClientProductGalleryQueryQuery & {
27
31
  pages: ClientManyProductsQueryQuery[]
28
32
  }
29
33
  }
30
34
 
31
- export interface DynamicContent<T> {
35
+ export interface DynamicContent<T> extends PageGlobalContext {
32
36
  data?: T
33
37
  }
34
38
 
@@ -37,6 +41,7 @@ export interface PageProviderContextValue {
37
41
  }
38
42
 
39
43
  type PageProviderContext =
44
+ | PageGlobalContext
40
45
  | PDPContext
41
46
  | PLPContext
42
47
  | SearchPageContext
@@ -1,11 +1,18 @@
1
- import type { ClientManyProductsQueryQueryVariables } from '@generated/graphql'
2
1
  import { useMemo } from 'react'
2
+ import deepmerge from 'deepmerge'
3
+
4
+ import { useSearch, type SearchState } from '@faststore/sdk'
5
+ import type { ClientManyProductsQueryQueryVariables } from '@generated/graphql'
6
+
7
+ import { useSession } from 'src/sdk/session'
3
8
  import { ITEMS_PER_SECTION } from 'src/constants'
4
- import { useSession } from '../session'
5
9
 
6
10
  const toArray = <T>(x: T[] | T | undefined) =>
7
11
  Array.isArray(x) ? x : x ? [x] : []
8
12
 
13
+ // Array merging strategy from deepmerge that makes client arrays overwrite server array
14
+ const overwriteMerge = (_: any[], clientArray: any[]) => clientArray
15
+
9
16
  export const useLocalizedVariables = ({
10
17
  first,
11
18
  after,
@@ -15,24 +22,31 @@ export const useLocalizedVariables = ({
15
22
  sponsoredCount,
16
23
  }: Partial<ClientManyProductsQueryQueryVariables>) => {
17
24
  const { channel, locale } = useSession()
25
+ const { state: searchState } = useSearch()
18
26
 
19
- return useMemo(() => {
20
- const facets = toArray(selectedFacets)
27
+ const mergedSelectedFacets = deepmerge(
28
+ selectedFacets as SearchState['selectedFacets'],
29
+ searchState.selectedFacets,
30
+ {
31
+ arrayMerge: overwriteMerge,
32
+ }
33
+ )
21
34
 
35
+ return useMemo(() => {
22
36
  return {
23
37
  first: first ?? ITEMS_PER_SECTION,
24
38
  after: after ?? '0',
25
39
  sort: sort ?? ('score_desc' as const),
26
40
  term: term ?? '',
27
41
  selectedFacets: [
28
- ...facets,
42
+ ...mergedSelectedFacets,
29
43
  { key: 'channel', value: channel ?? '' },
30
44
  { key: 'locale', value: locale },
31
45
  ],
32
46
  sponsoredCount: sponsoredCount ?? 3,
33
47
  }
34
48
  }, [
35
- selectedFacets,
49
+ mergedSelectedFacets,
36
50
  first,
37
51
  after,
38
52
  sort,
@@ -1,4 +1,4 @@
1
- import { setFacet, toggleFacet, useSearch } from '@faststore/sdk'
1
+ import { setFacet, toggleFacet, toggleFacets, useSearch } from '@faststore/sdk'
2
2
  import { useEffect, useMemo, useReducer } from 'react'
3
3
  import type { IStoreSelectedFacet } from '@faststore/api'
4
4
 
@@ -22,6 +22,10 @@ type Action =
22
22
  type: 'toggleFacet'
23
23
  payload: IStoreSelectedFacet
24
24
  }
25
+ | {
26
+ type: 'toggleFacets'
27
+ payload: { facets: IStoreSelectedFacet[]; unique?: boolean }
28
+ }
25
29
  | {
26
30
  type: 'setFacet'
27
31
  payload: { facet: IStoreSelectedFacet; unique?: boolean }
@@ -63,6 +67,13 @@ const reducer = (state: State, action: Action) => {
63
67
  }
64
68
  }
65
69
 
70
+ case 'toggleFacets': {
71
+ return {
72
+ ...state,
73
+ selected: toggleFacets(state.selected, payload.facets, payload.unique),
74
+ }
75
+ }
76
+
66
77
  case 'setFacet': {
67
78
  return {
68
79
  ...state,
@@ -2,6 +2,7 @@ import type { ContentData, ContentTypeOptions, Locator } from '@vtex/client-cms'
2
2
  import ClientCMS from '@vtex/client-cms'
3
3
 
4
4
  import MultipleContentError from 'src/sdk/error/MultipleContentError'
5
+ import { sanitizeHost } from 'src/utils/utilities'
5
6
  import config from '../../../discovery.config'
6
7
 
7
8
  export type Options =
@@ -65,6 +66,7 @@ export const isLocator = (x: any): x is Locator =>
65
66
  export const clientCMS = new ClientCMS({
66
67
  workspace: config.api.workspace,
67
68
  tenant: config.api.storeId,
69
+ host: sanitizeHost(config.storeUrl),
68
70
  })
69
71
 
70
72
  export const getCMSPage = async (
@@ -361,10 +361,11 @@ export type SectionsOverrides = {
361
361
  components: {
362
362
  RegionBar: ComponentOverrideDefinition<
363
363
  RegionBarProps,
364
- Omit<RegionBarProps, 'onButtonClick' | 'postalCode'>
364
+ Omit<RegionBarProps, 'onButtonClick' | 'postalCode' | 'city'>
365
365
  >
366
366
  LocationIcon: ComponentOverrideDefinition<IconProps, IconProps>
367
367
  ButtonIcon: ComponentOverrideDefinition<IconProps, IconProps>
368
+ FilterButtonIcon: ComponentOverrideDefinition<IconProps, IconProps>
368
369
  }
369
370
  }
370
371
  }
@@ -0,0 +1,74 @@
1
+ import deepmerge from 'deepmerge'
2
+ import { usePage } from 'src/sdk/overrides/PageProvider'
3
+
4
+ export type GlobalCmsData = {
5
+ regionalization?: RegionalizationCmsData
6
+ deliveryPromise?: DeliveryPromiseCmsData
7
+ }
8
+
9
+ type RegionalizationCmsData = {
10
+ inputField?: {
11
+ label?: string
12
+ errorMessage?: string
13
+ noProductsAvailableErrorMessage?: string
14
+ buttonActionText?: string
15
+ errorMessageHelper?: string
16
+ }
17
+ idkPostalCodeLink?: {
18
+ text?: string
19
+ to?: string
20
+ icon?: {
21
+ icon?: string
22
+ alt?: string
23
+ }
24
+ }
25
+ }
26
+
27
+ type DeliveryPromiseCmsData = {
28
+ deliveryMethods?: {
29
+ title?: string
30
+ description?: string
31
+ setLocationButtonLabel?: string
32
+ allDeliveryMethods?: string
33
+ delivery?: string
34
+ pickupInPoint?: string
35
+ pickupNearby?: string
36
+ pickupAll?: {
37
+ label?: string
38
+ enabled?: boolean
39
+ }
40
+ }
41
+ regionSlider?: {
42
+ title?: {
43
+ setLocation?: string
44
+ changeLocation?: string
45
+ changePickupPoint?: string
46
+ globalChangePickupPoint?: string
47
+ }
48
+ pickupPointChangeApplyButtonLabel?: string
49
+ pickupPointClearFilterButtonLabel?: string
50
+ choosePickupPointAriaLabel?: string
51
+ noPickupPointsAvailableInLocation?: string
52
+ }
53
+ filterByPickupPoint?: {
54
+ enabled?: boolean
55
+ label?: string
56
+ icon?: {
57
+ icon?: string
58
+ alt?: string
59
+ }
60
+ }
61
+ }
62
+
63
+ export function getGlobalSettings(
64
+ sectionRegionalizationData?: GlobalCmsData['regionalization']
65
+ ): GlobalCmsData {
66
+ const context = usePage()
67
+ const globalData: GlobalCmsData = context?.globalSettings ?? {}
68
+
69
+ if (sectionRegionalizationData === undefined) {
70
+ return globalData
71
+ }
72
+
73
+ return deepmerge(globalData, { regionalization: sectionRegionalizationData })
74
+ }
@@ -75,3 +75,8 @@ export function extractStatusFromError(error: any): number | undefined {
75
75
 
76
76
  return undefined
77
77
  }
78
+
79
+ export function sanitizeHost(url: string): string {
80
+ if (!url) return ''
81
+ return url.replace(/^https?:\/\//, '')
82
+ }
@@ -80,6 +80,7 @@ const QUERIES = [
80
80
  'accountProfile',
81
81
  'accountName',
82
82
  'validateUser',
83
+ 'pickupPoints',
83
84
  ]
84
85
 
85
86
  const MUTATIONS = [
@@ -1 +0,0 @@
1
- "use strict";exports.id=6272,exports.ids=[6272],exports.modules={56272:(e,t,o)=>{o.d(t,{En:()=>isSearchPage,OJ:()=>isPLP,ZP:()=>__WEBPACK_DEFAULT_EXPORT__,al:()=>usePDP,qt:()=>usePage,tS:()=>isPDP});var s=o(16689),a=o(20997);let isPDP=e=>e?.data?.product?.sku!=void 0&&e?.data?.product?.sku!=null,isPLP=e=>e?.data?.collection?.seo!=void 0&&e?.data?.collection?.seo!=null&&e?.data?.collection?.sku==void 0,isSearchPage=e=>void 0===e||e?.data?.title!=void 0||e?.data?.searchTerm!=void 0,i=(0,s.createContext)(null);function usePage(){let{context:e}=(0,s.useContext)(i);if(null==e)throw Error("Missing Overrides context on React tree");return e}let usePDP=()=>usePage(),__WEBPACK_DEFAULT_EXPORT__=function({context:e,children:t}){let o=(0,s.useMemo)(()=>({context:e}),[e]);return a.jsx(i.Provider,{value:o,children:t})}}};