@faststore/core 3.2.1 → 3.4.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 (160) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +30 -30
  3. package/.next/cache/.tsbuildinfo +1 -1
  4. package/.next/cache/config.json +3 -3
  5. package/.next/cache/eslint/.cache_1gneedd +1 -1
  6. package/.next/cache/webpack/client-production/0.pack +0 -0
  7. package/.next/cache/webpack/client-production/index.pack +0 -0
  8. package/.next/cache/webpack/server-production/0.pack +0 -0
  9. package/.next/cache/webpack/server-production/index.pack +0 -0
  10. package/.next/next-minimal-server.js.nft.json +1 -1
  11. package/.next/next-server.js.nft.json +1 -1
  12. package/.next/prerender-manifest.js +1 -1
  13. package/.next/prerender-manifest.json +1 -1
  14. package/.next/react-loadable-manifest.json +81 -41
  15. package/.next/routes-manifest.json +1 -1
  16. package/.next/server/chunks/2295.js +1 -0
  17. package/.next/server/chunks/2552.js +1 -1
  18. package/.next/server/chunks/2710.js +1 -0
  19. package/.next/server/chunks/3202.js +1 -1
  20. package/.next/server/chunks/3779.js +1 -0
  21. package/.next/server/chunks/4358.js +1 -0
  22. package/.next/server/chunks/5110.js +1 -0
  23. package/.next/server/chunks/5342.js +1 -0
  24. package/.next/server/chunks/5671.js +1 -1
  25. package/.next/server/chunks/5754.js +1 -1
  26. package/.next/server/chunks/6335.js +1 -0
  27. package/.next/server/chunks/64.js +1 -0
  28. package/.next/server/chunks/7228.js +1 -0
  29. package/.next/server/chunks/7468.js +1 -0
  30. package/.next/server/chunks/7986.js +1 -0
  31. package/.next/server/chunks/8724.js +1 -0
  32. package/.next/server/chunks/9088.js +1 -1
  33. package/.next/server/chunks/9160.js +1 -0
  34. package/.next/server/chunks/9410.js +1 -0
  35. package/.next/server/chunks/945.js +1 -1
  36. package/.next/server/chunks/9572.js +5 -5
  37. package/.next/server/chunks/983.js +1 -1
  38. package/.next/server/chunks/9844.js +1 -1
  39. package/.next/server/chunks/FilterSkeleton.js +1 -0
  40. package/.next/server/chunks/ScrollToTopButton.js +1 -1
  41. package/.next/server/chunks/UIBannerText.js +1 -1
  42. package/.next/server/middleware-build-manifest.js +1 -1
  43. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  44. package/.next/server/pages/404.js +1 -1
  45. package/.next/server/pages/404.js.nft.json +1 -1
  46. package/.next/server/pages/500.js +1 -1
  47. package/.next/server/pages/500.js.nft.json +1 -1
  48. package/.next/server/pages/[...slug].js +1 -1
  49. package/.next/server/pages/[...slug].js.nft.json +1 -1
  50. package/.next/server/pages/[slug]/p.js +1 -1
  51. package/.next/server/pages/[slug]/p.js.nft.json +1 -1
  52. package/.next/server/pages/_app.js.nft.json +1 -1
  53. package/.next/server/pages/_document.js.nft.json +1 -1
  54. package/.next/server/pages/_error.js.nft.json +1 -1
  55. package/.next/server/pages/account.js.nft.json +1 -1
  56. package/.next/server/pages/api/graphql.js.nft.json +1 -1
  57. package/.next/server/pages/api/health/live.js.nft.json +1 -1
  58. package/.next/server/pages/api/health/ready.js.nft.json +1 -1
  59. package/.next/server/pages/api/preview.js.nft.json +1 -1
  60. package/.next/server/pages/checkout.js.nft.json +1 -1
  61. package/.next/server/pages/en-US/404.html +1 -1
  62. package/.next/server/pages/en-US/404.json +1 -1
  63. package/.next/server/pages/en-US/500.html +1 -1
  64. package/.next/server/pages/en-US/500.json +1 -1
  65. package/.next/server/pages/en-US/account.html +1 -1
  66. package/.next/server/pages/en-US/account.json +1 -1
  67. package/.next/server/pages/en-US/checkout.html +1 -1
  68. package/.next/server/pages/en-US/checkout.json +1 -1
  69. package/.next/server/pages/en-US/login.html +1 -1
  70. package/.next/server/pages/en-US/login.json +1 -1
  71. package/.next/server/pages/en-US/s.html +1 -1
  72. package/.next/server/pages/en-US/s.json +1 -1
  73. package/.next/server/pages/en-US.html +1 -1
  74. package/.next/server/pages/en-US.json +1 -1
  75. package/.next/server/pages/index.js +1 -1
  76. package/.next/server/pages/index.js.nft.json +1 -1
  77. package/.next/server/pages/login.js +1 -1
  78. package/.next/server/pages/login.js.nft.json +1 -1
  79. package/.next/server/pages/s.js +1 -1
  80. package/.next/server/pages/s.js.nft.json +1 -1
  81. package/.next/server/pages-manifest.json +1 -1
  82. package/.next/server/webpack-runtime.js +1 -1
  83. package/.next/static/NwqA-ReE0HVefCIamuHZW/_buildManifest.js +1 -0
  84. package/.next/static/chunks/{1153.7f616071da309cf5.js → 1153.d7522522b6c917ed.js} +1 -1
  85. package/.next/static/chunks/1550-630692a9badd8065.js +1 -0
  86. package/.next/static/chunks/1978.6d1246731da0f1b0.js +1 -0
  87. package/.next/static/chunks/2552.35321485d927aa08.js +1 -0
  88. package/.next/static/chunks/299.0f890f8a7e5b1846.js +1 -0
  89. package/.next/static/chunks/3202.a1dabb5ce227338a.js +1 -0
  90. package/.next/static/chunks/4501-e4bf228242a711bc.js +1 -0
  91. package/.next/static/chunks/4551.fd8f840c3f6ab36f.js +1 -0
  92. package/.next/static/chunks/6379-6050cc5d5e5f2fa2.js +1 -0
  93. package/.next/static/chunks/64.225f7439e13cc375.js +1 -0
  94. package/.next/static/chunks/8724.66f3c6d121015974.js +1 -0
  95. package/.next/static/chunks/9024.a746900e79690cf9.js +1 -0
  96. package/.next/static/chunks/9160.f23fc2e8b2b6b813.js +1 -0
  97. package/.next/static/chunks/9540.d020c6959e15207a.js +1 -0
  98. package/.next/static/chunks/9638-24a86482d4a4b434.js +1 -0
  99. package/.next/static/chunks/983.c7179ebdb154d450.js +1 -0
  100. package/.next/static/chunks/BannerNewsletter.86e9f9fcf3d3e173.js +1 -0
  101. package/.next/static/chunks/BannerText.9822381f787e697d.js +1 -0
  102. package/.next/static/chunks/CartSidebar.c6b00aa5b0667b40.js +1 -0
  103. package/.next/static/chunks/FilterSkeleton.5cea0252ed1ff951.js +1 -0
  104. package/.next/static/chunks/ProductShelf.9341a11c5282b611.js +1 -0
  105. package/.next/static/chunks/RegionModal.5dc5ba359a7f5350.js +1 -0
  106. package/.next/static/chunks/Toast.fabbe374f1d57665.js +1 -0
  107. package/.next/static/chunks/UIBannerText.6284ec1895c33657.js +1 -0
  108. package/.next/static/chunks/UIToast.1e5aada1a1b104f5.js +1 -0
  109. package/.next/static/chunks/pages/{[...slug]-c2bf068f3f84b127.js → [...slug]-0203b74377537f7d.js} +1 -1
  110. package/.next/static/chunks/pages/[slug]/p-d9260cfe3d276855.js +1 -0
  111. package/.next/static/chunks/pages/{_app-7d970aad41a57338.js → _app-9d791333b87e7c18.js} +1 -1
  112. package/.next/static/chunks/pages/s-da1c36b5dafdf07b.js +1 -0
  113. package/.next/static/chunks/webpack-114d9639b5990b7f.js +1 -0
  114. package/.next/trace +98 -98
  115. package/.turbo/turbo-build.log +13 -13
  116. package/.turbo/turbo-lint.log +1 -1
  117. package/.turbo/turbo-test.log +5 -5
  118. package/CHANGELOG.md +12 -0
  119. package/package.json +3 -3
  120. package/src/Layout.tsx +2 -2
  121. package/src/components/search/Filter/FilterDesktop.tsx +34 -0
  122. package/src/components/search/Filter/FilterSlider.tsx +38 -9
  123. package/src/components/search/Filter/index.ts +1 -1
  124. package/src/components/sections/ProductGallery/DefaultComponents.ts +23 -7
  125. package/src/components/ui/ProductGallery/ProductGallery.tsx +48 -14
  126. package/src/sdk/analytics/hooks/usePageViewEvent.ts +3 -2
  127. package/src/sdk/analytics/platform/vtex/index.ts +2 -1
  128. package/src/sdk/analytics/platform/vtex/rc.ts +128 -0
  129. package/src/sdk/analytics/platform/vtex/search.ts +2 -14
  130. package/src/sdk/analytics/types.ts +55 -0
  131. package/.next/server/chunks/1844.js +0 -1
  132. package/.next/server/chunks/2195.js +0 -1
  133. package/.next/server/chunks/3199.js +0 -1
  134. package/.next/server/chunks/4350.js +0 -1
  135. package/.next/server/chunks/6150.js +0 -1
  136. package/.next/server/chunks/7917.js +0 -1
  137. package/.next/server/chunks/8419.js +0 -1
  138. package/.next/static/PmpN0_4SJrpkkEJ4TZn7l/_buildManifest.js +0 -1
  139. package/.next/static/chunks/1550-48e8637718c2dd74.js +0 -1
  140. package/.next/static/chunks/2552.b245748eb0e40257.js +0 -1
  141. package/.next/static/chunks/3202.d7d5a83625bed7aa.js +0 -1
  142. package/.next/static/chunks/459-404aa12d42b08af1.js +0 -1
  143. package/.next/static/chunks/5810.470a769e37e4b13b.js +0 -1
  144. package/.next/static/chunks/6379-1578190b254c09a6.js +0 -1
  145. package/.next/static/chunks/6999-078369e946149546.js +0 -1
  146. package/.next/static/chunks/9463.6f5675e44c925bfc.js +0 -1
  147. package/.next/static/chunks/983.024c2c324d061242.js +0 -1
  148. package/.next/static/chunks/BannerNewsletter.0b61ee5e562a55e0.js +0 -1
  149. package/.next/static/chunks/BannerText.a10d4f428fc5cd97.js +0 -1
  150. package/.next/static/chunks/CartSidebar.dfa8017080b88d46.js +0 -1
  151. package/.next/static/chunks/ProductShelf.0493dbf6e9982f10.js +0 -1
  152. package/.next/static/chunks/RegionModal.23513fc5245a511f.js +0 -1
  153. package/.next/static/chunks/Toast.8635143b7896eb54.js +0 -1
  154. package/.next/static/chunks/UIBannerText.ac22c6843ac720b8.js +0 -1
  155. package/.next/static/chunks/UIToast.a3b2b8fb137a7e55.js +0 -1
  156. package/.next/static/chunks/pages/[slug]/p-fa2418810fa3abeb.js +0 -1
  157. package/.next/static/chunks/pages/s-c4ff9fe20587e49e.js +0 -1
  158. package/.next/static/chunks/webpack-fcd6fda2fae47824.js +0 -1
  159. package/src/components/search/Filter/Filter.tsx +0 -101
  160. /package/.next/static/{PmpN0_4SJrpkkEJ4TZn7l → NwqA-ReE0HVefCIamuHZW}/_ssgManifest.js +0 -0
@@ -46,33 +46,33 @@ Warning: Dynamic Content not found for the page: home. Refer to the Dynamic Cont
46
46
  Collecting build traces ...
47
47
 
48
48
  Route (pages) Size First Load JS
49
- ┌ ● / 3.21 kB 121 kB
49
+ ┌ ● / 3.21 kB 122 kB
50
50
  ├ └ css/b1806cbafd0c1f81.css 3.06 kB
51
- ├ /_app 0 B 91.7 kB
52
- ├ ● /[...slug] 2 kB 137 kB
53
- ├ ● /[slug]/p 30.3 kB 148 kB
51
+ ├ /_app 0 B 91.8 kB
52
+ ├ ● /[...slug] 2 kB 132 kB
53
+ ├ ● /[slug]/p 30.5 kB 149 kB
54
54
  ├ ├ css/bf1560439df2c1a1.css 5.66 kB
55
55
  ├ ├ css/e3ff5d95518a5c79.css 6.01 kB
56
56
  ├ └ css/9718991cd57978e9.css 14.8 kB
57
57
  ├ ○ /404 1.46 kB 120 kB
58
58
  ├ ● /500 1.46 kB 120 kB
59
59
  ├ ● /account 712 B 119 kB
60
- ├ λ /api/graphql 0 B 91.7 kB
61
- ├ λ /api/health/live 0 B 91.7 kB
62
- ├ λ /api/health/ready 0 B 91.7 kB
63
- ├ λ /api/preview 0 B 91.7 kB
60
+ ├ λ /api/graphql 0 B 91.8 kB
61
+ ├ λ /api/health/live 0 B 91.8 kB
62
+ ├ λ /api/health/ready 0 B 91.8 kB
63
+ ├ λ /api/preview 0 B 91.8 kB
64
64
  ├ ● /checkout 694 B 119 kB
65
65
  ├ ● /login 1.57 kB 120 kB
66
- └ ● /s 2.44 kB 137 kB
67
- + First Load JS shared by all 94.7 kB
66
+ └ ● /s 2.63 kB 132 kB
67
+ + First Load JS shared by all 94.9 kB
68
68
  ├ chunks/framework-12a146e94cfcf7c4.js 45.4 kB
69
69
  ├ chunks/main-209ac4974b020af1.js 33.1 kB
70
- ├ chunks/pages/_app-7d970aad41a57338.js 9.84 kB
71
- ├ chunks/webpack-fcd6fda2fae47824.js 3.39 kB
70
+ ├ chunks/pages/_app-9d791333b87e7c18.js 9.9 kB
71
+ ├ chunks/webpack-114d9639b5990b7f.js 3.5 kB
72
72
  └ css/ee0556daedda6306.css 3.07 kB
73
73
 
74
74
  λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps)
75
75
  ○ (Static) automatically rendered as static HTML (uses no initial props)
76
76
  ● (SSG) automatically generated as static HTML + JSON (uses getStaticProps)
77
77
 
78
- Done in 70.31s.
78
+ Done in 69.28s.
@@ -1,4 +1,4 @@
1
1
  yarn run v1.22.22
2
2
  $ next lint
3
3
  ✔ No ESLint warnings or errors
4
- Done in 5.88s.
4
+ Done in 6.22s.
@@ -1,12 +1,12 @@
1
1
  yarn run v1.22.22
2
2
  $ jest
3
- PASS test/utils/multipleTemplates.test.ts (35.749 s)
4
- PASS test/server/cms/index.test.ts (36.923 s)
5
- PASS test/server/index.test.ts (40.444 s)
3
+ PASS test/utils/multipleTemplates.test.ts (36.84 s)
4
+ PASS test/server/cms/index.test.ts (37.45 s)
5
+ PASS test/server/index.test.ts (39.531 s)
6
6
 
7
7
  Test Suites: 3 passed, 3 total
8
8
  Tests: 19 passed, 19 total
9
9
  Snapshots: 0 total
10
- Time: 41.653 s
10
+ Time: 40.737 s
11
11
  Ran all test suites.
12
- Done in 43.25s.
12
+ Done in 42.44s.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [3.4.0](https://github.com/vtex/faststore/compare/v3.3.0...v3.4.0) (2024-12-19)
7
+
8
+ ### Features
9
+
10
+ - handle RC Events ([#2567](https://github.com/vtex/faststore/issues/2567)) ([486563d](https://github.com/vtex/faststore/commit/486563dd6e15a04686c99bcfaea6f216520255c9))
11
+
12
+ # [3.3.0](https://github.com/vtex/faststore/compare/v3.2.1...v3.3.0) (2024-12-18)
13
+
14
+ ### Features
15
+
16
+ - `Filter` with next/dynamic and lazy import ([#2596](https://github.com/vtex/faststore/issues/2596)) ([73e5496](https://github.com/vtex/faststore/commit/73e54965e656f848c20865cd2760158d634bb0c0))
17
+
6
18
  ## [3.2.1](https://github.com/vtex/faststore/compare/v3.2.0...v3.2.1) (2024-12-16)
7
19
 
8
20
  **Note:** Version bump only for package @faststore/core
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/core",
3
- "version": "3.2.1",
3
+ "version": "3.4.0",
4
4
  "license": "MIT",
5
5
  "repository": "vtex/faststore",
6
6
  "browserslist": "supports es6-module and not dead",
@@ -47,7 +47,7 @@
47
47
  "@faststore/components": "^3.1.3",
48
48
  "@faststore/graphql-utils": "^3.1.3",
49
49
  "@faststore/lighthouse": "^3.1.3",
50
- "@faststore/sdk": "^3.1.3",
50
+ "@faststore/sdk": "^3.4.0",
51
51
  "@faststore/ui": "^3.1.4",
52
52
  "@graphql-codegen/cli": "5.0.2",
53
53
  "@graphql-codegen/client-preset": "4.2.6",
@@ -128,5 +128,5 @@
128
128
  "node": "18.19.0",
129
129
  "yarn": "1.19.1"
130
130
  },
131
- "gitHead": "3b311ad0a99db4cf44c396bde2aa4a01c30a3646"
131
+ "gitHead": "49e9dcacf82f062a09309f68e537d032f674b5cc"
132
132
  }
package/src/Layout.tsx CHANGED
@@ -1,9 +1,9 @@
1
- import { type PropsWithChildren } from 'react'
1
+ import type { PropsWithChildren, ReactElement } from 'react'
2
2
 
3
3
  import { usePageViewEvent } from './sdk/analytics/hooks/usePageViewEvent'
4
4
 
5
5
  function Layout({ children }: PropsWithChildren) {
6
- usePageViewEvent()
6
+ usePageViewEvent((children as ReactElement)?.props)
7
7
 
8
8
  return <>{children}</>
9
9
  }
@@ -7,6 +7,7 @@ import {
7
7
  FilterFacetRange as UIFilterFacetRange,
8
8
  FilterFacets as UIFilterFacets,
9
9
  } from '@faststore/ui'
10
+ import { gql } from '@generated/gql'
10
11
  import type { Filter_FacetsFragment } from '@generated/graphql'
11
12
  import { useFormattedPrice } from 'src/sdk/product/useFormattedPrice'
12
13
  import { useFilter } from 'src/sdk/search/useFilter'
@@ -110,4 +111,37 @@ function FilterDesktop({
110
111
  )
111
112
  }
112
113
 
114
+ export const fragment = gql(`
115
+ fragment Filter_facets on StoreFacet {
116
+ ... on StoreFacetRange {
117
+ key
118
+ label
119
+
120
+ min {
121
+ selected
122
+ absolute
123
+ }
124
+
125
+ max {
126
+ selected
127
+ absolute
128
+ }
129
+
130
+ __typename
131
+ }
132
+ ... on StoreFacetBoolean {
133
+ key
134
+ label
135
+ values {
136
+ label
137
+ value
138
+ selected
139
+ quantity
140
+ }
141
+
142
+ __typename
143
+ }
144
+ }
145
+ `)
146
+
113
147
  export default FilterDesktop
@@ -1,14 +1,43 @@
1
+ import dynamic from 'next/dynamic'
2
+
1
3
  import { useSearch } from '@faststore/sdk'
2
- import {
3
- Filter as UIFilter,
4
- FilterFacetBoolean as UIFilterFacetBoolean,
5
- FilterFacetBooleanItem as UIFilterFacetBooleanItem,
6
- FilterFacetRange as UIFilterFacetRange,
7
- FilterFacets as UIFilterFacets,
8
- FilterSlider as UIFilterSlider,
9
- } from '@faststore/ui'
10
4
  import { useFormattedPrice } from 'src/sdk/product/useFormattedPrice'
11
5
 
6
+ import type {
7
+ FilterFacetBooleanItemProps as UIFilterFacetBooleanItemProps,
8
+ FilterFacetRangeProps as UIFilterFacetRangeProps,
9
+ FilterFacetsProps as UIFilterFacetsProps,
10
+ FilterProps as UIFilterProps,
11
+ FilterSliderProps as UIFilterSliderProps,
12
+ } from '@faststore/ui'
13
+
14
+ const UIFilter = dynamic<{ children: React.ReactNode } & UIFilterProps>(() =>
15
+ /* webpackChunkName: "UIFilter" */
16
+ import('@faststore/ui').then((mod) => mod.Filter)
17
+ )
18
+ const UIFilterFacetBoolean = dynamic<{ children: React.ReactNode }>(() =>
19
+ /* webpackChunkName: "UIFilterFacetBoolean" */
20
+ import('@faststore/ui').then((mod) => mod.FilterFacetBoolean)
21
+ )
22
+ const UIFilterFacetBooleanItem = dynamic<UIFilterFacetBooleanItemProps>(() =>
23
+ /* webpackChunkName: "UIFilterFacetBooleanItem" */
24
+ import('@faststore/ui').then((mod) => mod.FilterFacetBooleanItem)
25
+ )
26
+ const UIFilterFacetRange = dynamic<UIFilterFacetRangeProps>(() =>
27
+ /* webpackChunkName: "UIFilterFacetRange" */
28
+ import('@faststore/ui').then((mod) => mod.FilterFacetRange)
29
+ )
30
+ const UIFilterFacets = dynamic<
31
+ { children: React.ReactNode } & UIFilterFacetsProps
32
+ >(() =>
33
+ /* webpackChunkName: "UIFilterFacets" */
34
+ import('@faststore/ui').then((mod) => mod.FilterFacets)
35
+ )
36
+ const UIFilterSlider = dynamic<UIFilterSliderProps>(() =>
37
+ /* webpackChunkName: "UIFilterSlider" */
38
+ import('@faststore/ui').then((mod) => mod.FilterSlider)
39
+ )
40
+
12
41
  import type { Filter_FacetsFragment } from '@generated/graphql'
13
42
 
14
43
  import type { useFilter } from 'src/sdk/search/useFilter'
@@ -87,7 +116,7 @@ function FilterSlider({
87
116
  <UIFilter
88
117
  testId={`mobile-${testId}`}
89
118
  indicesExpanded={expanded}
90
- onAccordionChange={(index) =>
119
+ onAccordionChange={(index: number) =>
91
120
  dispatch({ type: 'toggleExpanded', payload: index })
92
121
  }
93
122
  >
@@ -1,2 +1,2 @@
1
- export { default } from './Filter'
1
+ export { default as FilterDesktop } from './FilterDesktop'
2
2
  export { default as FilterSlider } from './FilterSlider'
@@ -1,18 +1,34 @@
1
- import { lazy } from 'react'
2
1
  import {
3
2
  Button as UIButton,
3
+ Icon as UIIcon,
4
4
  LinkButton as UILinkButton,
5
5
  Skeleton as UISkeleton,
6
- Icon as UIIcon,
7
6
  } from '@faststore/ui'
8
7
 
9
- import ProductCard from 'src/components/product/ProductCard'
10
- import FilterDesktop from 'src/components/search/Filter/FilterDesktop'
11
- import EmptyGallery from './EmptyGallery'
8
+ import dynamic from 'next/dynamic'
12
9
 
13
- const FilterSlider = lazy(
14
- () => import('src/components/search/Filter/FilterSlider')
10
+ const ProductCard = dynamic(
11
+ () =>
12
+ /* webpackChunkName: "ProductCard" */
13
+ import('src/components/product/ProductCard')
15
14
  )
15
+ const EmptyGallery = dynamic(
16
+ () =>
17
+ /* webpackChunkName: "EmptyGallery" */
18
+ import('./EmptyGallery')
19
+ )
20
+
21
+ const FilterDesktop = dynamic(
22
+ () =>
23
+ /* webpackChunkName: "FilterDesktop" */
24
+ import('src/components/search/Filter/FilterDesktop')
25
+ )
26
+ const FilterSlider = dynamic(
27
+ () =>
28
+ /* webpackChunkName: "FilterSlider" */
29
+ import('src/components/search/Filter/FilterSlider')
30
+ )
31
+
16
32
  export const ProductGalleryDefaultComponents = {
17
33
  MobileFilterButton: UIButton,
18
34
  FilterIcon: UIIcon,
@@ -4,11 +4,11 @@ import type { MouseEvent } from 'react'
4
4
  import { Suspense, lazy } from 'react'
5
5
 
6
6
  import { useUI } from '@faststore/ui'
7
- import Filter from 'src/components/search/Filter'
8
7
  import Sort from 'src/components/search/Sort'
9
- import FilterSkeleton from 'src/components/skeletons/FilterSkeleton'
10
8
  import ProductGridSkeleton from 'src/components/skeletons/ProductGridSkeleton'
11
9
 
10
+ import dynamic from 'next/dynamic'
11
+
12
12
  import { ProductCardProps } from 'src/components/product/ProductCard'
13
13
  import { FilterSliderProps } from 'src/components/search/Filter/FilterSlider'
14
14
  import { SortProps } from 'src/components/search/Sort/Sort'
@@ -21,8 +21,18 @@ import {
21
21
  import { useProductsPrefetch } from 'src/sdk/product/useProductsPrefetch'
22
22
  import { useDelayedFacets } from 'src/sdk/search/useDelayedFacets'
23
23
  import { useDelayedPagination } from 'src/sdk/search/useDelayedPagination'
24
+ import { useFilter } from 'src/sdk/search/useFilter'
25
+ import useScreenResize from 'src/sdk/ui/useScreenResize'
24
26
 
25
27
  const ProductGalleryPage = lazy(() => import('./ProductGalleryPage'))
28
+ const FilterSkeleton = dynamic(
29
+ () =>
30
+ import(
31
+ /* webpackChunkName: "FilterSkeleton" */
32
+ 'src/components/skeletons/FilterSkeleton'
33
+ )
34
+ )
35
+
26
36
  const GalleryPageSkeleton = <ProductGridSkeleton loading />
27
37
 
28
38
  export interface ProductGalleryProps {
@@ -69,7 +79,7 @@ function ProductGallery({
69
79
  totalCount,
70
80
  searchTermLabel,
71
81
  totalCountLabel,
72
- filter,
82
+ filter: filterCmsData,
73
83
  previousPageButton,
74
84
  loadMorePageButton,
75
85
  sortBySelector,
@@ -84,20 +94,25 @@ function ProductGallery({
84
94
  PrevIcon,
85
95
  ResultsCountSkeleton,
86
96
  SortSkeleton,
97
+ __experimentalFilterDesktop: FilterDesktop,
98
+ __experimentalFilterSlider: FilterSlider,
87
99
  } = useOverrideComponents<'ProductGallery'>()
88
100
 
89
- const { openFilter } = useUI()
101
+ const { openFilter, filter: displayFilter } = useUI()
90
102
  const { pages, addNextPage, addPrevPage, itemsPerPage } = useSearch()
91
103
  const context = usePage<SearchPageContext | PLPContext>()
92
104
  const data = context?.data
93
105
  const facets = useDelayedFacets(data) ?? []
94
106
  const { next, prev } = useDelayedPagination(totalCount)
95
107
 
108
+ const { isDesktop } = useScreenResize()
109
+
96
110
  useProductsPrefetch(prev ? prev.cursor : null)
97
111
  useProductsPrefetch(next ? next.cursor : null)
98
112
 
99
113
  const hasFacetsLoaded = Boolean(data?.search?.facets)
100
114
  const hasProductsLoaded = Boolean(data?.search?.products)
115
+ const filter = useFilter(facets)
101
116
 
102
117
  return (
103
118
  <section data-testid="product-gallery" data-fs-product-listing>
@@ -115,13 +130,32 @@ function ProductGallery({
115
130
  data-fs-product-listing-content-grid
116
131
  data-fs-content="product-gallery"
117
132
  >
118
- <div data-fs-product-listing-filters>
119
- <FilterSkeleton loading={!hasFacetsLoaded}>
120
- {hasFacetsLoaded && facets?.length > 0 && (
121
- <Filter facets={facets} filter={filter} />
122
- )}
123
- </FilterSkeleton>
124
- </div>
133
+ {isDesktop && (
134
+ <div data-fs-product-listing-filters>
135
+ <FilterSkeleton loading={!hasFacetsLoaded}>
136
+ {hasFacetsLoaded && facets?.length > 0 && (
137
+ <div className="hidden-mobile">
138
+ <FilterDesktop.Component
139
+ {...FilterDesktop.props}
140
+ {...filter}
141
+ title={filterCmsData?.title}
142
+ />
143
+ </div>
144
+ )}
145
+ </FilterSkeleton>
146
+ </div>
147
+ )}
148
+ {!isDesktop && displayFilter && (
149
+ <div data-fs-product-listing-filters>
150
+ <FilterSlider.Component
151
+ {...FilterSlider.props}
152
+ {...filter}
153
+ title={filterCmsData?.title}
154
+ clearButtonLabel={filterCmsData?.mobileOnly?.clearButtonLabel}
155
+ applyButtonLabel={filterCmsData?.mobileOnly?.applyButtonLabel}
156
+ />
157
+ </div>
158
+ )}
125
159
  <div data-fs-product-listing-results-count data-count={totalCount}>
126
160
  <ResultsCountSkeleton.Component
127
161
  data-fs-product-listing-results-count-skeleton
@@ -168,11 +202,11 @@ function ProductGallery({
168
202
  height={16}
169
203
  {...FilterIcon.props}
170
204
  name={
171
- filter?.mobileOnly?.filterButton?.icon?.icon ??
205
+ filterCmsData?.mobileOnly?.filterButton?.icon?.icon ??
172
206
  FilterIcon.props.name
173
207
  }
174
208
  aria-label={
175
- filter?.mobileOnly?.filterButton?.icon?.alt ??
209
+ filterCmsData?.mobileOnly?.filterButton?.icon?.alt ??
176
210
  FilterIcon.props['aria-label']
177
211
  }
178
212
  />
@@ -183,7 +217,7 @@ function ProductGallery({
183
217
  // This decision can be reviewed later if needed
184
218
  onClick={openFilter}
185
219
  >
186
- {filter?.mobileOnly?.filterButton?.label}
220
+ {filterCmsData?.mobileOnly?.filterButton?.label}
187
221
  </MobileFilterButton.Component>
188
222
  )}
189
223
  </FilterButtonSkeleton.Component>
@@ -2,7 +2,7 @@ import type { PageViewEvent } from '@faststore/sdk'
2
2
  import { useRouter } from 'next/router'
3
3
  import { useCallback, useEffect } from 'react'
4
4
 
5
- export const usePageViewEvent = () => {
5
+ export const usePageViewEvent = (props?: any) => {
6
6
  const sendPageViewEvent = useCallback(() => {
7
7
  import('@faststore/sdk').then(({ sendAnalyticsEvent }) => {
8
8
  sendAnalyticsEvent<PageViewEvent>({
@@ -11,10 +11,11 @@ export const usePageViewEvent = () => {
11
11
  page_title: document.title,
12
12
  page_location: location.href,
13
13
  send_page_view: true,
14
+ ...props,
14
15
  },
15
16
  })
16
17
  })
17
- }, [])
18
+ }, [props])
18
19
 
19
20
  const router = useRouter()
20
21
 
@@ -1,10 +1,11 @@
1
1
  import type { AnalyticsEvent } from '@faststore/sdk'
2
2
 
3
+ import handleRCEvent from './rc'
3
4
  import handleSearchEvent from './search'
4
5
 
5
6
  export default function sendEvent(event: AnalyticsEvent) {
6
7
  // VTEX RC
7
- window?.sendrc?.(event.name, event.params)
8
+ handleRCEvent(event)
8
9
 
9
10
  // VTEX Intelligent Search
10
11
  handleSearchEvent(event)
@@ -0,0 +1,128 @@
1
+ import { AnalyticsEvent, PageViewEvent } from '@faststore/sdk'
2
+ import { ServerProductQueryQuery } from '@generated/graphql'
3
+ import {
4
+ CategoryView,
5
+ DepartmentView,
6
+ HomeView,
7
+ IntelligentSearchQueryEvent,
8
+ InternalSiteSearchView,
9
+ OtherView,
10
+ ProductView,
11
+ SearchEvents,
12
+ } from '../../types'
13
+
14
+ const EventNames = {
15
+ OTHER_VIEW: 'otherView',
16
+ HOME_VIEW: 'homeView',
17
+ CATEGORY_VIEW: 'categoryView',
18
+ DEPARTMENT_VIEW: 'departmentView',
19
+ INTERNAL_SITE_SEARCH_VIEW: 'internalSiteSearchView',
20
+ PRODUCT_VIEW: 'productView',
21
+ } as const
22
+
23
+ type RequestCaptureEventNames = (typeof EventNames)[keyof typeof EventNames]
24
+ type RequestCaptureEvent =
25
+ | HomeView
26
+ | CategoryView
27
+ | DepartmentView
28
+ | InternalSiteSearchView
29
+ | ProductView
30
+ | OtherView
31
+
32
+ const sendEvent = (
33
+ eventName: RequestCaptureEventNames,
34
+ eventParams: RequestCaptureEvent
35
+ ) => {
36
+ window?.sendrc?.(eventName, eventParams)
37
+ }
38
+
39
+ const handleEvent = (event: AnalyticsEvent | SearchEvents) => {
40
+ let eventParams
41
+ switch (event.name) {
42
+ case 'page_view':
43
+ eventParams = (event as PageViewEvent).params
44
+ const pageType = eventParams?.page?.type ?? eventParams?.type
45
+
46
+ switch (pageType) {
47
+ case 'plp':
48
+ if (!eventParams?.page_location?.includes('fuzzy')) {
49
+ // Skip when there is no fuzzy parameters on the URL,
50
+ // otherwise it'll be sent twice (once without fuzzy and once with fuzzy)
51
+ break
52
+ }
53
+ const collection = eventParams?.data?.collection
54
+ const collectionCategoryList =
55
+ collection?.breadcrumbList?.itemListElement
56
+ if (collectionCategoryList.length > 1) {
57
+ sendEvent(EventNames.CATEGORY_VIEW, {
58
+ departmentName: collectionCategoryList[0]?.name,
59
+ categoryId: collection?.id,
60
+ categoryName:
61
+ collectionCategoryList[collectionCategoryList.length - 1]?.name,
62
+ })
63
+ } else {
64
+ sendEvent(EventNames.DEPARTMENT_VIEW, {
65
+ departmentId: collection?.id,
66
+ departmentName: collectionCategoryList[0]?.name,
67
+ })
68
+ }
69
+
70
+ break
71
+
72
+ case 'pdp':
73
+ const product = eventParams?.data
74
+ ?.product as ServerProductQueryQuery['product']
75
+ const productCategoryList = product?.breadcrumbList?.itemListElement
76
+ const offers = product?.offers?.offers
77
+ const sellerIds = offers.map((offer) => offer.seller.identifier)
78
+ const skusOutOfStock = offers.filter(
79
+ (offer) => offer.availability === 'https://schema.org/OutOfStock'
80
+ )
81
+
82
+ sendEvent(EventNames.PRODUCT_VIEW, {
83
+ skuStockOutFromProductDetail: skusOutOfStock,
84
+ productId: product?.isVariantOf?.productGroupID,
85
+ productName: product?.isVariantOf?.name,
86
+ productBrandName: product?.brand?.name,
87
+ productDepartmentName: productCategoryList
88
+ ? productCategoryList[0]?.name
89
+ : '',
90
+ productCategoryName:
91
+ productCategoryList.length > 1
92
+ ? productCategoryList[productCategoryList.length - 2]?.name
93
+ : '',
94
+ productPrice: offers[0]?.price,
95
+ productListPrice: offers[0]?.listPrice,
96
+ sellerId: offers[0]?.seller?.identifier,
97
+ sellerIds: sellerIds.join(','),
98
+ })
99
+ break
100
+
101
+ case 'home':
102
+ sendEvent(EventNames.HOME_VIEW, {})
103
+ break
104
+
105
+ case 'search':
106
+ // This one is skipped because the event related to search view is being
107
+ // sent using the intelligent_search_query event due to its parameters
108
+ break
109
+
110
+ default:
111
+ sendEvent(EventNames.OTHER_VIEW, {})
112
+ }
113
+ break
114
+
115
+ case 'intelligent_search_query':
116
+ eventParams = (event as IntelligentSearchQueryEvent).params
117
+ sendEvent(EventNames.INTERNAL_SITE_SEARCH_VIEW, {
118
+ siteSearchTerm: eventParams.term,
119
+ siteSearchForm: eventParams.url,
120
+ siteSearchResults: eventParams.totalCount,
121
+ })
122
+ break
123
+
124
+ default:
125
+ }
126
+ }
127
+
128
+ export default handleEvent
@@ -2,12 +2,7 @@
2
2
  * More info at: https://developers.vtex.com/docs/api-reference/intelligent-search-events-api-headless
3
3
  */
4
4
  import type { AnalyticsEvent } from '@faststore/sdk'
5
- import type {
6
- IntelligentSearchAutocompleteClickEvent,
7
- IntelligentSearchAutocompleteQueryEvent,
8
- IntelligentSearchQueryEvent,
9
- SearchSelectItemEvent,
10
- } from '../../types'
5
+ import type { SearchEvents } from '../../types'
11
6
 
12
7
  import config from '../../../../../discovery.config'
13
8
  import { getCookie } from '../../../../utils/getCookie'
@@ -103,14 +98,7 @@ const isFullTextSearch = (url: URL) =>
103
98
  typeof url.searchParams.get('q') === 'string' &&
104
99
  /^\/s(\/)?$/g.test(url.pathname)
105
100
 
106
- const handleEvent = (
107
- event:
108
- | AnalyticsEvent
109
- | SearchSelectItemEvent
110
- | IntelligentSearchQueryEvent
111
- | IntelligentSearchAutocompleteQueryEvent
112
- | IntelligentSearchAutocompleteClickEvent
113
- ) => {
101
+ const handleEvent = (event: AnalyticsEvent | SearchEvents) => {
114
102
  switch (event.name) {
115
103
  case 'search_select_item': {
116
104
  const url = new URL(event.params.url)
@@ -60,3 +60,58 @@ export interface IntelligentSearchAutocompleteClickEvent {
60
60
  name: 'intelligent_search_autocomplete_click'
61
61
  params: IntelligentSearchAutocompleteClickParams
62
62
  }
63
+
64
+ export type SearchEvents =
65
+ | SearchSelectItemEvent
66
+ | IntelligentSearchQueryEvent
67
+ | IntelligentSearchAutocompleteQueryEvent
68
+ | IntelligentSearchAutocompleteClickEvent
69
+
70
+ /**
71
+ * RC event types
72
+ * Types copied from Request Capture App: https://github.com/vtex/request-capture-app/blob/1becac32c002cb03a57bf36c8a7f9400eab8b933/react/typings/rcevents.d.ts
73
+ */
74
+
75
+ export interface HomeView {}
76
+
77
+ export interface CategoryView {
78
+ departmentId?: string
79
+ departmentName?: string
80
+ categoryId?: string
81
+ categoryName?: string
82
+ }
83
+
84
+ export interface DepartmentView {
85
+ departmentId?: string
86
+ departmentName?: string
87
+ }
88
+
89
+ export interface InternalSiteSearchView {
90
+ siteSearchTerm?: string // e.g.: "areia"
91
+ siteSearchForm?: string // e.g.: "/gatos/ambiente--gatos/caixa-de-areia/areia?PS=20"
92
+ siteSearchCategory?: string // e.g.: "10000283"
93
+ siteSearchResults?: number // e.g.: 26
94
+ }
95
+
96
+ type SkuId = string
97
+
98
+ export interface ProductView {
99
+ skuStockOutFromProductDetail: string[]
100
+ productId: string
101
+ productReferenceId: string
102
+ productEans: string[]
103
+ skuStocks: Record<SkuId, number>
104
+ productName: string
105
+ productBrandId: string
106
+ productBrandName: string
107
+ productDepartmentId: string
108
+ productDepartmentName: string
109
+ productCategoryId: string
110
+ productCategoryName: string
111
+ productListPrice: number
112
+ productPrice: number
113
+ sellerId: string
114
+ sellerIds: string // e.g.: "00443713,04412311,1"
115
+ }
116
+
117
+ export interface OtherView {}