@faststore/core 4.6.0-dev.2 → 4.6.0-dev.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-generate.log +4 -4
- package/.turbo/turbo-test.log +80 -77
- package/@generated/cached-operations.json +1 -1
- package/@generated/gql.ts +6 -6
- package/@generated/graphql.ts +10 -10
- package/@generated/persisted-documents.json +1 -1
- package/CHANGELOG.md +4 -0
- package/package.json +6 -6
- package/src/components/sections/RecommendationShelf/README.md +4 -1
- package/src/components/sections/RecommendationShelf/RecommendationShelf.tsx +11 -92
- package/src/components/sections/RecommendationShelf/RecommendationShelf.types.ts +3 -18
- package/src/sdk/recommendations/index.ts +17 -0
- package/src/sdk/recommendations/types.ts +17 -0
- package/src/sdk/recommendations/useRecommendationShelf.ts +141 -0
- package/src/{components/sections/RecommendationShelf → sdk/recommendations}/vrn.ts +1 -1
- package/test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx +6 -12
- package/test/sdk/recommendations/useRecommendationShelf.browser.test.tsx +199 -0
- package/test/{components/RecommendationShelf → sdk/recommendations}/useRecommendationUserId.test.ts +1 -1
- package/test/{components/RecommendationShelf → sdk/recommendations}/useRecommendations.test.ts +1 -1
- package/test/{components/RecommendationShelf → sdk/recommendations}/vrn.test.ts +1 -4
- /package/src/{components/sections/RecommendationShelf → sdk/recommendations}/useRecommendationUserId.ts +0 -0
- /package/src/{components/sections/RecommendationShelf → sdk/recommendations}/useRecommendations.ts +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@4.6.0-dev.
|
|
2
|
+
> @faststore/core@4.6.0-dev.2 generate /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> pnpm run gen-types && pnpm run cache-graphql
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @faststore/core@4.6.0-dev.
|
|
6
|
+
> @faststore/core@4.6.0-dev.2 gen-types /home/runner/work/faststore/faststore/packages/core
|
|
7
7
|
> node ../cli/bin/run generate-types .
|
|
8
8
|
|
|
9
9
|
[33m[STARTED][39m Parse Configuration
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
[32m[COMPLETED][39m Generate to /home/runner/work/faststore/faststore/packages/core/@generated/
|
|
20
20
|
[32m[COMPLETED][39m Generate outputs
|
|
21
21
|
|
|
22
|
-
> @faststore/core@4.6.0-dev.
|
|
22
|
+
> @faststore/core@4.6.0-dev.2 cache-graphql /home/runner/work/faststore/faststore/packages/core
|
|
23
23
|
> node ../cli/bin/run cache-graphql --config=./discovery.config.default.js --queries=./@generated/persisted-documents.json
|
|
24
24
|
|
|
25
25
|
[Info] - Config file location: /home/runner/work/faststore/faststore/packages/core/discovery.config.default.js
|
|
26
26
|
[Info] - Persisted documents at: /home/runner/work/faststore/faststore/packages/core/@generated/persisted-documents.json
|
|
27
27
|
[Info] - Cached operations output: /home/runner/work/faststore/faststore/packages/core/@generated/cached-operations.json
|
|
28
28
|
[Success] - GraphQL queries cached with success: 🎉
|
|
29
|
-
Queries:
|
|
29
|
+
Queries: ServerAccountPageQuery, ServerCollectionPageQuery, ServerProductQuery, ServerOrderDetailsQuery, ServerListOrdersQuery, ServerProfileQuery, ServerListQuotesQuery, ServerQuotesOrganizationMemberQuery, ServerSecurity, ServerUserDetailsQuery, AvailableContractsQuery, ValidateUser, ClientPickupPointsQuery, OrderEntryOperationQuery, OrderFormItemsQuery, ClientProductCountQuery, ClientAllVariantProductsQuery, ClientManyProductsQueryWithSearchId, ClientProductGalleryQuery, ClientProductQuery, ClientManyProductsQuery, ClientManyProductsSelectedQuery, ClientProfileQuery, ClientRecommendationsQuery, ClientSearchSuggestionsQuery, ClientTopSearchSuggestionsQuery, ClientShippingSimulationQuery, ServerManyProductsQuery
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@4.6.0-dev.
|
|
2
|
+
> @faststore/core@4.6.0-dev.2 test /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> vitest run
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
[1m[46m RUN [49m[22m [36mv4.0.18 [39m[90m/home/runner/work/faststore/faststore/packages/core[39m
|
|
7
7
|
|
|
8
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/ui/ProductGallery/GalleryPageHeightLock.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[33m 310[2mms[22m[39m
|
|
8
9
|
Not implemented: navigation to another Document
|
|
9
10
|
Not implemented: navigation to another Document
|
|
10
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/ui/useScrollRestoration.browser.test.ts [2m([22m[2m43 tests[22m[2m)[22m[33m
|
|
11
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/ui/useScrollRestoration.browser.test.ts [2m([22m[2m43 tests[22m[2m)[22m[33m 881[2mms[22m[39m
|
|
12
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/ContractSwitcher.browser.test.tsx [2m([22m[2m13 tests[22m[2m)[22m[33m 2268[2mms[22m[39m
|
|
13
|
+
[33m[2m✓[22m[39m shows an error state when the list fails to load [33m 726[2mms[22m[39m
|
|
14
|
+
[33m[2m✓[22m[39m requires selecting a contract before Confirm is enabled, then switches (REQ-03) [33m 347[2mms[22m[39m
|
|
15
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.browser.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 27[2mms[22m[39m
|
|
11
16
|
[90mstderr[2m | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx
|
|
12
17
|
[22m[39mError in optimistic validation: TypeError: Failed to parse URL from /api/graphql?operationName=ValidateCartMutation&operationHash=3c71b0d3fc2bade14df68abfa271858beb361b12
|
|
13
18
|
[90m at node:internal/deps/undici/undici:16416:13[39m
|
|
@@ -37,14 +42,11 @@ Not implemented: navigation to another Document
|
|
|
37
42
|
Browserslist: browsers data (caniuse-lite) is 6 months old. Please run:
|
|
38
43
|
npx update-browserslist-db@latest
|
|
39
44
|
Why you should do it regularly: https://github.com/browserslist/update-db#readme
|
|
40
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/ContractSwitcher.browser.test.tsx [2m([22m[2m13 tests[22m[2m)[22m[33m 1389[2mms[22m[39m
|
|
41
45
|
[90mstderr[2m | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx[2m > [22m[2mRecommendationShelf[2m > [22m[2mrenders nothing when there is an error
|
|
42
46
|
[22m[39mError fetching recommendations [90mundefined[39m boom for campaign vrn:recommendations:acc:rec-top-items-v2:campaign-1
|
|
43
47
|
|
|
44
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
45
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
46
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.browser.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 14[2mms[22m[39m
|
|
47
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/getInitialSession.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 19[2mms[22m[39m
|
|
48
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 244[2mms[22m[39m
|
|
49
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/recommendations/useRecommendationShelf.browser.test.tsx [2m([22m[2m10 tests[22m[2m)[22m[32m 104[2mms[22m[39m
|
|
48
50
|
[90mstderr[2m | test/pages/password-protection.browser.test.tsx[2m > [22m[2mPasswordProtectionLogin[2m > [22m[2mposts the password and redirects to the requested return path
|
|
49
51
|
[22m[39mWarning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
|
|
50
52
|
|
|
@@ -274,11 +276,12 @@ act(() => {
|
|
|
274
276
|
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
|
|
275
277
|
at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
|
|
276
278
|
|
|
277
|
-
[32m✓[39m [30m[46m browser [49m[39m test/pages/password-protection.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m
|
|
278
|
-
[33m[2m✓[22m[39m renders the password protection form [33m
|
|
279
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/
|
|
280
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
281
|
-
|
|
279
|
+
[32m✓[39m [30m[46m browser [49m[39m test/pages/password-protection.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m 844[2mms[22m[39m
|
|
280
|
+
[33m[2m✓[22m[39m renders the password protection form [33m 351[2mms[22m[39m
|
|
281
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/getInitialSession.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 13[2mms[22m[39m
|
|
282
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/changeContractToken.browser.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 26[2mms[22m[39m
|
|
283
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawer.browser.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 919[2mms[22m[39m
|
|
284
|
+
[33m[2m✓[22m[39m renders the menu view with contract details and manage footer [33m 455[2mms[22m[39m
|
|
282
285
|
[90mstderr[2m | test/sdk/localization/store-url.browser.test.ts
|
|
283
286
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
284
287
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -287,10 +290,10 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
287
290
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
288
291
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
289
292
|
|
|
290
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/localization/store-url.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
291
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useAvailableContracts.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
292
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/templates/SearchPage/SearchWrapper.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
293
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useSwitchContract.browser.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
293
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/localization/store-url.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
294
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useAvailableContracts.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 32[2mms[22m[39m
|
|
295
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/templates/SearchPage/SearchWrapper.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 27[2mms[22m[39m
|
|
296
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useSwitchContract.browser.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 34[2mms[22m[39m
|
|
294
297
|
[90mstderr[2m | test/components/account/doLogout.browser.test.ts
|
|
295
298
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
296
299
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -299,8 +302,8 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
299
302
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
300
303
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
301
304
|
|
|
302
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/doLogout.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
303
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerHeader.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
305
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/doLogout.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 21[2mms[22m[39m
|
|
306
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerHeader.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 191[2mms[22m[39m
|
|
304
307
|
[90mstderr[2m | test/sdk/account/clearPersistedSessionState.browser.test.ts
|
|
305
308
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
306
309
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -309,13 +312,13 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
309
312
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
310
313
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
311
314
|
|
|
312
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/clearPersistedSessionState.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
313
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerFooter.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
315
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/clearPersistedSessionState.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
316
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerFooter.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 253[2mms[22m[39m
|
|
314
317
|
[32m✓[39m [30m[46m browser [49m[39m test/utils/isLocalHost.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
315
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
318
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
319
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/skeletons/ProductGridSkeleton.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 31[2mms[22m[39m
|
|
316
320
|
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/bindingPaths.test.ts [2m([22m[2m71 tests[22m[2m)[22m[32m 21[2mms[22m[39m
|
|
317
|
-
[32m✓[39m [30m[
|
|
318
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/password-protection-service.test.ts [2m([22m[2m22 tests[22m[2m)[22m[32m 25[2mms[22m[39m
|
|
321
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/password-protection-service.test.ts [2m([22m[2m22 tests[22m[2m)[22m[32m 26[2mms[22m[39m
|
|
319
322
|
[90mstderr[2m | test/sdk/account/refreshToken.browser.test.ts
|
|
320
323
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
321
324
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -324,11 +327,11 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
324
327
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
325
328
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
326
329
|
|
|
327
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/match-url.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
330
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/match-url.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
328
331
|
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/refreshToken.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
329
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/useBindingSelector.test.tsx [2m([22m[2m22 tests[22m[2m)[22m[32m
|
|
330
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/unlock.test.ts [2m([22m[2m15 tests[22m[2m)[22m[32m
|
|
331
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/bindingSelector.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m
|
|
332
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/useBindingSelector.test.tsx [2m([22m[2m22 tests[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
333
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/unlock.test.ts [2m([22m[2m15 tests[22m[2m)[22m[32m 125[2mms[22m[39m
|
|
334
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/bindingSelector.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
332
335
|
[90mstderr[2m | test/components/search/SearchInputComponent.test.tsx
|
|
333
336
|
[22m[39mWarning: forwardRef render functions accept exactly two parameters: props and ref. Did you forget to use the ref parameter?
|
|
334
337
|
|
|
@@ -392,11 +395,11 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
392
395
|
at Suspense
|
|
393
396
|
at Wrapper (/home/runner/work/faststore/faststore/packages/core/test/components/search/SearchInputComponent.test.tsx:106:20)
|
|
394
397
|
|
|
395
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInputComponent.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
396
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/cookieCacheBusting.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
397
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/search/useSearchHistory.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m
|
|
398
|
-
[32m✓[39m [30m[43m node [49m[39m test/experimental/myAccountCmsServerSideProps.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
399
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/clearCookies.test.ts [2m([22m[2m20 tests[22m[2m)[22m[32m
|
|
398
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInputComponent.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 68[2mms[22m[39m
|
|
399
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/cookieCacheBusting.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
400
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/search/useSearchHistory.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m 51[2mms[22m[39m
|
|
401
|
+
[32m✓[39m [30m[43m node [49m[39m test/experimental/myAccountCmsServerSideProps.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
402
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/clearCookies.test.ts [2m([22m[2m20 tests[22m[2m)[22m[32m 17[2mms[22m[39m
|
|
400
403
|
[90mstderr[2m | test/pages/api/graphql.test.ts[2m > [22m[2m/api/graphql error status propagation[2m > [22m[2mpropagates the upstream 400 from a wrapped BadRequestError instead of 500
|
|
401
404
|
[22m[39mGraphql execution returned with error: [
|
|
402
405
|
{
|
|
@@ -489,64 +492,64 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
489
492
|
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1653:37
|
|
490
493
|
at Traces.$ (file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/vitest@4.0.18_@opentelemetry+api@1.9.0_@types+node@20.19.13_jiti@2.6.1_jsdom@27.4.0_sas_13be941c57d55f08f06eeaf1c180ddfe/node_modules/[4mvitest[24m/dist/chunks/traces.CCmnQaNT.js:142:27)
|
|
491
494
|
|
|
492
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/graphql.test.ts [2m([22m[2m17 tests[22m[2m)[22m[32m
|
|
493
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotesTable.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[33m
|
|
495
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/graphql.test.ts [2m([22m[2m17 tests[22m[2m)[22m[32m 30[2mms[22m[39m
|
|
496
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotesTable.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[33m 302[2mms[22m[39m
|
|
497
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryOperation.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
|
494
498
|
[90mstderr[2m | test/sdk/account/useSetPassword.test.ts[2m > [22m[2museSetPassword[2m > [22m[2mmaps wrongcredentials error responses to the existing message
|
|
495
499
|
[22m[39mSet password request failed: Bad Request
|
|
496
500
|
|
|
497
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/useSetPassword.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
498
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
499
|
-
|
|
500
|
-
[33m[2m✓[22m[39m navigates
|
|
501
|
-
|
|
502
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/quoteFilters.test.ts [2m([22m[2m23 tests[22m[2m)[22m[32m
|
|
503
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/
|
|
504
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
505
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
506
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
507
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/
|
|
508
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
509
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
510
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/getMyAccountRoutes.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
501
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/useSetPassword.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 31[2mms[22m[39m
|
|
502
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotes.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 830[2mms[22m[39m
|
|
503
|
+
[33m[2m✓[22m[39m navigates with the search term on blur [33m 361[2mms[22m[39m
|
|
504
|
+
[33m[2m✓[22m[39m navigates without a label param when the search is cleared [33m 361[2mms[22m[39m
|
|
505
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/multipleTemplates.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
506
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/quoteFilters.test.ts [2m([22m[2m23 tests[22m[2m)[22m[32m 29[2mms[22m[39m
|
|
507
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/localizeRedirectDestination.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
508
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryUpload.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 42[2mms[22m[39m
|
|
509
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesFilterSlider.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 121[2mms[22m[39m
|
|
510
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/analytics/useStartRecommendationSession.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 47[2mms[22m[39m
|
|
511
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntry.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
|
512
|
+
[32m✓[39m [30m[43m node [49m[39m test/proxy.localization.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 23[2mms[22m[39m
|
|
513
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/getMyAccountRoutes.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
511
514
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/session/syncSalesChannelFromOrderForm.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
512
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/index.test.ts [2m([22m[2m7 tests[22m[2m)[22m[33m
|
|
513
|
-
[33m[2m✓[22m[39m should handle options and execute [33m
|
|
514
|
-
[32m✓[39m [30m[43m node [49m[39m test/proxy.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
515
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/webops-api.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m
|
|
516
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesSelectedTags.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
517
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderFormItems.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m
|
|
515
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/index.test.ts [2m([22m[2m7 tests[22m[2m)[22m[33m 874[2mms[22m[39m
|
|
516
|
+
[33m[2m✓[22m[39m should handle options and execute [33m 439[2mms[22m[39m
|
|
517
|
+
[32m✓[39m [30m[43m node [49m[39m test/proxy.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 18[2mms[22m[39m
|
|
518
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/webops-api.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
519
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesSelectedTags.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 81[2mms[22m[39m
|
|
520
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderFormItems.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 36[2mms[22m[39m
|
|
518
521
|
[32m✓[39m [30m[43m node [49m[39m test/server/content/service.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
519
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/cart/waitForSessionValidated.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
520
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/refreshToken.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
522
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/cart/waitForSessionValidated.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 10[2mms[22m[39m
|
|
523
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/refreshToken.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
521
524
|
[32m✓[39m [30m[43m node [49m[39m test/server/cms/global.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
522
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/store-url.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
523
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/auth/useAuth.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
525
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/store-url.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
526
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/auth/useAuth.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 26[2mms[22m[39m
|
|
527
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesStatusSelector.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 110[2mms[22m[39m
|
|
524
528
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/analytics/hasEnabledRecommendationShelf.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
525
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
526
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
527
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/preview.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
529
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/getRequestHostname.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
530
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/preview.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
528
531
|
[32m✓[39m [30m[43m node [49m[39m test/utils/validateSessionRefreshToken.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
529
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
530
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
531
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
532
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/cms/index.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
533
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/retry.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
534
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/account/Layout.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
535
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
532
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInput.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
533
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/rootSpan.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 30[2mms[22m[39m
|
|
534
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/vrn.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
535
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/cms/index.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
536
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/retry.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 10[2mms[22m[39m
|
|
537
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/Layout.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 34[2mms[22m[39m
|
|
538
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/useRecommendationUserId.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 184[2mms[22m[39m
|
|
536
539
|
[32m✓[39m [30m[43m node [49m[39m test/utils/unlockResponse.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
537
540
|
[32m✓[39m [30m[43m node [49m[39m test/server/cms/myAccountDefaultSections.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
538
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
541
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/useRecommendations.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
539
542
|
[32m✓[39m [30m[43m node [49m[39m test/utils/isLocalHost.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
543
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/OrganizationDrawerBody.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 41[2mms[22m[39m
|
|
540
544
|
[32m✓[39m [30m[43m node [49m[39m test/utils/userOrderStatus.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
541
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/account/OrganizationDrawerBody.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 33[2mms[22m[39m
|
|
542
545
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/analytics/utils.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
543
|
-
[32m✓[39m [30m[43m node [49m[39m test/instrumentation.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
546
|
+
[32m✓[39m [30m[43m node [49m[39m test/instrumentation.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
544
547
|
[32m✓[39m [30m[43m node [49m[39m test/components/auth/ProfileChallenge.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 32[2mms[22m[39m
|
|
545
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/clearPersistedSessionState.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
546
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuoteStatusBadge.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
548
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/clearPersistedSessionState.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 14[2mms[22m[39m
|
|
549
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuoteStatusBadge.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 23[2mms[22m[39m
|
|
547
550
|
|
|
548
|
-
[2m Test Files [22m [1m[
|
|
549
|
-
[2m Tests [22m [1m[
|
|
550
|
-
[2m Start at [22m
|
|
551
|
-
[2m Duration [22m 29.
|
|
551
|
+
[2m Test Files [22m [1m[32m82 passed[39m[22m[90m (82)[39m
|
|
552
|
+
[2m Tests [22m [1m[32m661 passed[39m[22m[90m (661)[39m
|
|
553
|
+
[2m Start at [22m 15:05:26
|
|
554
|
+
[2m Duration [22m 29.73s[2m (transform 6.68s, setup 0ms, import 23.96s, tests 9.74s, environment 38.48s)[22m
|
|
552
555
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
[
|
|
2
|
-
"ClientRecommendationsQuery",
|
|
3
2
|
"ServerAccountPageQuery",
|
|
4
3
|
"ServerCollectionPageQuery",
|
|
5
4
|
"ServerProductQuery",
|
|
@@ -23,6 +22,7 @@
|
|
|
23
22
|
"ClientManyProductsQuery",
|
|
24
23
|
"ClientManyProductsSelectedQuery",
|
|
25
24
|
"ClientProfileQuery",
|
|
25
|
+
"ClientRecommendationsQuery",
|
|
26
26
|
"ClientSearchSuggestionsQuery",
|
|
27
27
|
"ClientTopSearchSuggestionsQuery",
|
|
28
28
|
"ClientShippingSimulationQuery",
|
package/@generated/gql.ts
CHANGED
|
@@ -18,7 +18,6 @@ type Documents = {
|
|
|
18
18
|
"\n fragment ProductSummary_product on StoreProduct {\n id: productID\n slug\n sku\n brand {\n brandName: name\n }\n name\n gtin\n\t\tunitMultiplier\n\n isVariantOf {\n productGroupID\n name\n\t\t\tskuVariants {\n\t\t\t\tallVariantsByName\n\t\t\t\tactiveVariations\n\t\t\t\tslugsMap\n\t\t\t\tavailableVariations\n\t\t\t}\n }\n\n image {\n url\n alternateName\n }\n\n brand {\n name\n }\n\n offers {\n lowPrice\n lowPriceWithTaxes\n offers {\n availability\n price\n listPrice\n listPriceWithTaxes\n priceWithTaxes\n quantity\n priceToken\n seller {\n identifier\n }\n }\n }\n\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n\n hasSpecifications\n\n unitMultiplier\n\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n allVariantProducts {\n name\n productID\n }\n }\n }\n\n advertisement {\n adId\n adResponseId\n }\n\n deliveryPromiseBadges {\n typeName\n }\n }\n": typeof types.ProductSummary_ProductFragmentDoc,
|
|
19
19
|
"\n fragment Filter_facets on StoreFacet {\n ... on StoreFacetRange {\n key\n label\n\n min {\n selected\n absolute\n }\n\n max {\n selected\n absolute\n }\n\n __typename\n }\n ... on StoreFacetBoolean {\n key\n label\n values {\n label\n value\n selected\n quantity\n }\n\n __typename\n }\n }\n": typeof types.Filter_FacetsFragmentDoc,
|
|
20
20
|
"\n fragment ProductDetailsFragment_product on StoreProduct {\n id: productID\n sku\n name\n gtin\n description\n unitMultiplier\n isVariantOf {\n name\n productGroupID\n\t\t\tskuVariants {\n activeVariations\n slugsMap\n availableVariations\n allVariantProducts {\n name\n productID\n }\n }\n }\n\n image {\n url\n alternateName\n }\n\n brand {\n name\n }\n\n offers {\n lowPrice\n lowPriceWithTaxes\n offers {\n availability\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n quantity\n priceToken\n seller {\n identifier\n }\n }\n }\n\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n\n # Contains necessary info to add this item to cart\n ...CartProductItem\n }\n": typeof types.ProductDetailsFragment_ProductFragmentDoc,
|
|
21
|
-
"query ClientRecommendationsQuery(\n $campaignVrn: String!\n $userId: String\n $products: [String!]\n) {\n recommendations(\n userId: $userId\n campaignVrn: $campaignVrn\n products: $products\n ) {\n products {\n ...ProductSummary_product\n }\n correlationId\n campaign {\n id\n title\n type\n }\n }\n}\n": typeof types.ClientRecommendationsQueryDocument,
|
|
22
21
|
"\n fragment ProductComparisonFragment_product on StoreProduct {\n id: productID\n sku\n slug\n name\n gtin\n description\n unitMultiplier\n isVariantOf {\n name\n productGroupID\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n allVariantProducts {\n name\n productID\n }\n }\n }\n\n image {\n url\n alternateName\n }\n\n brand {\n name\n }\n\n offers {\n lowPrice\n lowPriceWithTaxes\n offers {\n availability\n price\n priceWithTaxes\n listPrice\n quantity\n listPriceWithTaxes\n priceToken\n seller {\n identifier\n }\n }\n }\n\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n\n advertisement {\n adId\n adResponseId\n }\n\n hasSpecifications\n\n skuSpecifications {\n field {\n id\n name\n originalName\n }\n values {\n name\n id\n fieldId\n originalName\n }\n }\n\n specificationGroups {\n name\n originalName\n specifications {\n name\n originalName\n values\n }\n }\n }\n": typeof types.ProductComparisonFragment_ProductFragmentDoc,
|
|
23
22
|
"\n fragment ProductSKUMatrixSidebarFragment_product on StoreProduct {\n id: productID\n isVariantOf {\n name\n productGroupID\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n allVariantProducts {\n\t\t\t\t\tsku\n name\n image {\n url\n alternateName\n }\n offers {\n highPrice\n lowPrice\n lowPriceWithTaxes\n offerCount\n priceCurrency\n offers {\n listPrice\n listPriceWithTaxes\n sellingPrice\n priceCurrency\n price\n priceWithTaxes\n priceValidUntil\n itemCondition\n availability\n quantity\n priceToken\n }\n }\n additionalProperty {\n propertyID\n value\n name\n valueReference\n }\n }\n }\n }\n }\n": typeof types.ProductSkuMatrixSidebarFragment_ProductFragmentDoc,
|
|
24
23
|
"\n fragment ClientManyProducts on Query {\n search(\n first: $first\n after: $after\n sort: $sort\n term: $term\n selectedFacets: $selectedFacets\n sponsoredCount: $sponsoredCount\n\n ) {\n products {\n pageInfo {\n totalCount\n }\n }\n }\n }\n": typeof types.ClientManyProductsFragmentDoc,
|
|
@@ -60,6 +59,7 @@ type Documents = {
|
|
|
60
59
|
"\n query ClientManyProductsQuery(\n $first: Int!\n $after: String\n $sort: StoreSort!\n $term: String!\n $selectedFacets: [IStoreSelectedFacet!]!\n $sponsoredCount: Int\n ) {\n ...ClientManyProducts\n search(\n first: $first\n after: $after\n sort: $sort\n term: $term\n selectedFacets: $selectedFacets\n sponsoredCount: $sponsoredCount\n ) {\n products {\n pageInfo {\n totalCount\n }\n edges {\n node {\n ...ProductSummary_product\n }\n }\n }\n }\n }\n": typeof types.ClientManyProductsQueryDocument,
|
|
61
60
|
"\n query ClientManyProductsSelectedQuery(\n $productIds: [String!]!\n ) {\n products(productIds: $productIds) {\n ...ProductComparisonFragment_product\n }\n }\n": typeof types.ClientManyProductsSelectedQueryDocument,
|
|
62
61
|
"\n query ClientProfileQuery($id: String!) {\n profile(id: $id) {\n addresses {\n country\n postalCode\n geoCoordinate\n city\n }\n }\n }\n": typeof types.ClientProfileQueryDocument,
|
|
62
|
+
"query ClientRecommendationsQuery(\n $campaignVrn: String!\n $userId: String\n $products: [String!]\n) {\n recommendations(\n userId: $userId\n campaignVrn: $campaignVrn\n products: $products\n ) {\n products {\n ...ProductSummary_product\n }\n correlationId\n campaign {\n id\n title\n type\n }\n }\n}\n": typeof types.ClientRecommendationsQueryDocument,
|
|
63
63
|
"\n query ClientSearchSuggestionsQuery(\n $term: String!\n $selectedFacets: [IStoreSelectedFacet!]\n ) {\n ...ClientSearchSuggestions\n search(first: 5, term: $term, selectedFacets: $selectedFacets) {\n suggestions {\n terms {\n value\n }\n products {\n ...ProductSummary_product\n }\n }\n products {\n pageInfo {\n totalCount\n }\n }\n metadata {\n ...SearchEvent_metadata\n }\n searchId\n }\n }\n": typeof types.ClientSearchSuggestionsQueryDocument,
|
|
64
64
|
"\n query ClientTopSearchSuggestionsQuery(\n $term: String!\n $selectedFacets: [IStoreSelectedFacet!]\n ) {\n ...ClientTopSearchSuggestions\n search(first: 5, term: $term, selectedFacets: $selectedFacets) {\n suggestions {\n terms {\n value\n }\n }\n }\n }\n": typeof types.ClientTopSearchSuggestionsQueryDocument,
|
|
65
65
|
"\n mutation ValidateSession($session: IStoreSession!, $search: String!) {\n validateSession(session: $session, search: $search) {\n locale\n channel\n country\n addressType\n postalCode\n city\n deliveryMode {\n deliveryChannel\n deliveryMethod\n deliveryWindow {\n startDate\n endDate\n }\n }\n geoCoordinates {\n latitude\n longitude\n }\n currency {\n code\n symbol\n }\n person {\n id\n email\n givenName\n familyName\n }\n b2b {\n customerId\n isRepresentative\n unitName\n unitId\n firstName\n lastName\n userName\n userEmail\n savedPostalCode\n contractName\n organizationManager\n }\n marketingData {\n utmCampaign\n utmMedium\n utmSource\n utmiCampaign\n utmiPage\n utmiPart\n }\n refreshAfter\n }\n }\n": typeof types.ValidateSessionDocument,
|
|
@@ -70,7 +70,6 @@ const documents: Documents = {
|
|
|
70
70
|
"\n fragment ProductSummary_product on StoreProduct {\n id: productID\n slug\n sku\n brand {\n brandName: name\n }\n name\n gtin\n\t\tunitMultiplier\n\n isVariantOf {\n productGroupID\n name\n\t\t\tskuVariants {\n\t\t\t\tallVariantsByName\n\t\t\t\tactiveVariations\n\t\t\t\tslugsMap\n\t\t\t\tavailableVariations\n\t\t\t}\n }\n\n image {\n url\n alternateName\n }\n\n brand {\n name\n }\n\n offers {\n lowPrice\n lowPriceWithTaxes\n offers {\n availability\n price\n listPrice\n listPriceWithTaxes\n priceWithTaxes\n quantity\n priceToken\n seller {\n identifier\n }\n }\n }\n\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n\n hasSpecifications\n\n unitMultiplier\n\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n allVariantProducts {\n name\n productID\n }\n }\n }\n\n advertisement {\n adId\n adResponseId\n }\n\n deliveryPromiseBadges {\n typeName\n }\n }\n": types.ProductSummary_ProductFragmentDoc,
|
|
71
71
|
"\n fragment Filter_facets on StoreFacet {\n ... on StoreFacetRange {\n key\n label\n\n min {\n selected\n absolute\n }\n\n max {\n selected\n absolute\n }\n\n __typename\n }\n ... on StoreFacetBoolean {\n key\n label\n values {\n label\n value\n selected\n quantity\n }\n\n __typename\n }\n }\n": types.Filter_FacetsFragmentDoc,
|
|
72
72
|
"\n fragment ProductDetailsFragment_product on StoreProduct {\n id: productID\n sku\n name\n gtin\n description\n unitMultiplier\n isVariantOf {\n name\n productGroupID\n\t\t\tskuVariants {\n activeVariations\n slugsMap\n availableVariations\n allVariantProducts {\n name\n productID\n }\n }\n }\n\n image {\n url\n alternateName\n }\n\n brand {\n name\n }\n\n offers {\n lowPrice\n lowPriceWithTaxes\n offers {\n availability\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n quantity\n priceToken\n seller {\n identifier\n }\n }\n }\n\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n\n # Contains necessary info to add this item to cart\n ...CartProductItem\n }\n": types.ProductDetailsFragment_ProductFragmentDoc,
|
|
73
|
-
"query ClientRecommendationsQuery(\n $campaignVrn: String!\n $userId: String\n $products: [String!]\n) {\n recommendations(\n userId: $userId\n campaignVrn: $campaignVrn\n products: $products\n ) {\n products {\n ...ProductSummary_product\n }\n correlationId\n campaign {\n id\n title\n type\n }\n }\n}\n": types.ClientRecommendationsQueryDocument,
|
|
74
73
|
"\n fragment ProductComparisonFragment_product on StoreProduct {\n id: productID\n sku\n slug\n name\n gtin\n description\n unitMultiplier\n isVariantOf {\n name\n productGroupID\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n allVariantProducts {\n name\n productID\n }\n }\n }\n\n image {\n url\n alternateName\n }\n\n brand {\n name\n }\n\n offers {\n lowPrice\n lowPriceWithTaxes\n offers {\n availability\n price\n priceWithTaxes\n listPrice\n quantity\n listPriceWithTaxes\n priceToken\n seller {\n identifier\n }\n }\n }\n\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n\n advertisement {\n adId\n adResponseId\n }\n\n hasSpecifications\n\n skuSpecifications {\n field {\n id\n name\n originalName\n }\n values {\n name\n id\n fieldId\n originalName\n }\n }\n\n specificationGroups {\n name\n originalName\n specifications {\n name\n originalName\n values\n }\n }\n }\n": types.ProductComparisonFragment_ProductFragmentDoc,
|
|
75
74
|
"\n fragment ProductSKUMatrixSidebarFragment_product on StoreProduct {\n id: productID\n isVariantOf {\n name\n productGroupID\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n allVariantProducts {\n\t\t\t\t\tsku\n name\n image {\n url\n alternateName\n }\n offers {\n highPrice\n lowPrice\n lowPriceWithTaxes\n offerCount\n priceCurrency\n offers {\n listPrice\n listPriceWithTaxes\n sellingPrice\n priceCurrency\n price\n priceWithTaxes\n priceValidUntil\n itemCondition\n availability\n quantity\n priceToken\n }\n }\n additionalProperty {\n propertyID\n value\n name\n valueReference\n }\n }\n }\n }\n }\n": types.ProductSkuMatrixSidebarFragment_ProductFragmentDoc,
|
|
76
75
|
"\n fragment ClientManyProducts on Query {\n search(\n first: $first\n after: $after\n sort: $sort\n term: $term\n selectedFacets: $selectedFacets\n sponsoredCount: $sponsoredCount\n\n ) {\n products {\n pageInfo {\n totalCount\n }\n }\n }\n }\n": types.ClientManyProductsFragmentDoc,
|
|
@@ -112,6 +111,7 @@ const documents: Documents = {
|
|
|
112
111
|
"\n query ClientManyProductsQuery(\n $first: Int!\n $after: String\n $sort: StoreSort!\n $term: String!\n $selectedFacets: [IStoreSelectedFacet!]!\n $sponsoredCount: Int\n ) {\n ...ClientManyProducts\n search(\n first: $first\n after: $after\n sort: $sort\n term: $term\n selectedFacets: $selectedFacets\n sponsoredCount: $sponsoredCount\n ) {\n products {\n pageInfo {\n totalCount\n }\n edges {\n node {\n ...ProductSummary_product\n }\n }\n }\n }\n }\n": types.ClientManyProductsQueryDocument,
|
|
113
112
|
"\n query ClientManyProductsSelectedQuery(\n $productIds: [String!]!\n ) {\n products(productIds: $productIds) {\n ...ProductComparisonFragment_product\n }\n }\n": types.ClientManyProductsSelectedQueryDocument,
|
|
114
113
|
"\n query ClientProfileQuery($id: String!) {\n profile(id: $id) {\n addresses {\n country\n postalCode\n geoCoordinate\n city\n }\n }\n }\n": types.ClientProfileQueryDocument,
|
|
114
|
+
"query ClientRecommendationsQuery(\n $campaignVrn: String!\n $userId: String\n $products: [String!]\n) {\n recommendations(\n userId: $userId\n campaignVrn: $campaignVrn\n products: $products\n ) {\n products {\n ...ProductSummary_product\n }\n correlationId\n campaign {\n id\n title\n type\n }\n }\n}\n": types.ClientRecommendationsQueryDocument,
|
|
115
115
|
"\n query ClientSearchSuggestionsQuery(\n $term: String!\n $selectedFacets: [IStoreSelectedFacet!]\n ) {\n ...ClientSearchSuggestions\n search(first: 5, term: $term, selectedFacets: $selectedFacets) {\n suggestions {\n terms {\n value\n }\n products {\n ...ProductSummary_product\n }\n }\n products {\n pageInfo {\n totalCount\n }\n }\n metadata {\n ...SearchEvent_metadata\n }\n searchId\n }\n }\n": types.ClientSearchSuggestionsQueryDocument,
|
|
116
116
|
"\n query ClientTopSearchSuggestionsQuery(\n $term: String!\n $selectedFacets: [IStoreSelectedFacet!]\n ) {\n ...ClientTopSearchSuggestions\n search(first: 5, term: $term, selectedFacets: $selectedFacets) {\n suggestions {\n terms {\n value\n }\n }\n }\n }\n": types.ClientTopSearchSuggestionsQueryDocument,
|
|
117
117
|
"\n mutation ValidateSession($session: IStoreSession!, $search: String!) {\n validateSession(session: $session, search: $search) {\n locale\n channel\n country\n addressType\n postalCode\n city\n deliveryMode {\n deliveryChannel\n deliveryMethod\n deliveryWindow {\n startDate\n endDate\n }\n }\n geoCoordinates {\n latitude\n longitude\n }\n currency {\n code\n symbol\n }\n person {\n id\n email\n givenName\n familyName\n }\n b2b {\n customerId\n isRepresentative\n unitName\n unitId\n firstName\n lastName\n userName\n userEmail\n savedPostalCode\n contractName\n organizationManager\n }\n marketingData {\n utmCampaign\n utmMedium\n utmSource\n utmiCampaign\n utmiPage\n utmiPart\n }\n refreshAfter\n }\n }\n": types.ValidateSessionDocument,
|
|
@@ -131,10 +131,6 @@ export function gql(source: "\n fragment Filter_facets on StoreFacet {\n ...
|
|
|
131
131
|
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
132
132
|
*/
|
|
133
133
|
export function gql(source: "\n fragment ProductDetailsFragment_product on StoreProduct {\n id: productID\n sku\n name\n gtin\n description\n unitMultiplier\n isVariantOf {\n name\n productGroupID\n\t\t\tskuVariants {\n activeVariations\n slugsMap\n availableVariations\n allVariantProducts {\n name\n productID\n }\n }\n }\n\n image {\n url\n alternateName\n }\n\n brand {\n name\n }\n\n offers {\n lowPrice\n lowPriceWithTaxes\n offers {\n availability\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n quantity\n priceToken\n seller {\n identifier\n }\n }\n }\n\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n\n # Contains necessary info to add this item to cart\n ...CartProductItem\n }\n"): typeof import('./graphql').ProductDetailsFragment_ProductFragmentDoc;
|
|
134
|
-
/**
|
|
135
|
-
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
136
|
-
*/
|
|
137
|
-
export function gql(source: "query ClientRecommendationsQuery(\n $campaignVrn: String!\n $userId: String\n $products: [String!]\n) {\n recommendations(\n userId: $userId\n campaignVrn: $campaignVrn\n products: $products\n ) {\n products {\n ...ProductSummary_product\n }\n correlationId\n campaign {\n id\n title\n type\n }\n }\n}\n"): typeof import('./graphql').ClientRecommendationsQueryDocument;
|
|
138
134
|
/**
|
|
139
135
|
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
140
136
|
*/
|
|
@@ -299,6 +295,10 @@ export function gql(source: "\n query ClientManyProductsSelectedQuery(\n $pr
|
|
|
299
295
|
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
300
296
|
*/
|
|
301
297
|
export function gql(source: "\n query ClientProfileQuery($id: String!) {\n profile(id: $id) {\n addresses {\n country\n postalCode\n geoCoordinate\n city\n }\n }\n }\n"): typeof import('./graphql').ClientProfileQueryDocument;
|
|
298
|
+
/**
|
|
299
|
+
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
300
|
+
*/
|
|
301
|
+
export function gql(source: "query ClientRecommendationsQuery(\n $campaignVrn: String!\n $userId: String\n $products: [String!]\n) {\n recommendations(\n userId: $userId\n campaignVrn: $campaignVrn\n products: $products\n ) {\n products {\n ...ProductSummary_product\n }\n correlationId\n campaign {\n id\n title\n type\n }\n }\n}\n"): typeof import('./graphql').ClientRecommendationsQueryDocument;
|
|
302
302
|
/**
|
|
303
303
|
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
304
304
|
*/
|
package/@generated/graphql.ts
CHANGED
|
@@ -2727,15 +2727,6 @@ export type Filter_FacetsFragment =
|
|
|
2727
2727
|
|
|
2728
2728
|
export type ProductDetailsFragment_ProductFragment = { sku: string, name: string, gtin: string, description: string, unitMultiplier: number | null, id: string, isVariantOf: { name: string, productGroupID: string, skuVariants: { activeVariations: any | null, slugsMap: any | null, availableVariations: any | null, allVariantProducts: Array<{ name: string, productID: string }> | null } | null }, image: Array<{ url: string, alternateName: string }>, brand: { name: string }, offers: { lowPrice: number, lowPriceWithTaxes: number, offers: Array<{ availability: string, price: number, priceWithTaxes: number, listPrice: number, listPriceWithTaxes: number, quantity: number, priceToken: string | null, seller: { identifier: string } }> }, additionalProperty: Array<{ propertyID: string, name: string, value: any, valueReference: any }> };
|
|
2729
2729
|
|
|
2730
|
-
export type ClientRecommendationsQueryQueryVariables = Exact<{
|
|
2731
|
-
campaignVrn: Scalars['String']['input'];
|
|
2732
|
-
userId: InputMaybe<Scalars['String']['input']>;
|
|
2733
|
-
products: InputMaybe<Array<Scalars['String']['input']> | Scalars['String']['input']>;
|
|
2734
|
-
}>;
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
export type ClientRecommendationsQueryQuery = { recommendations: { correlationId: string, products: Array<{ slug: string, sku: string, name: string, gtin: string, unitMultiplier: number | null, hasSpecifications: boolean | null, id: string, brand: { name: string, brandName: string }, isVariantOf: { productGroupID: string, name: string, skuVariants: { allVariantsByName: any | null, activeVariations: any | null, slugsMap: any | null, availableVariations: any | null, allVariantProducts: Array<{ name: string, productID: string }> | null } | null }, image: Array<{ url: string, alternateName: string }>, offers: { lowPrice: number, lowPriceWithTaxes: number, offers: Array<{ availability: string, price: number, listPrice: number, listPriceWithTaxes: number, priceWithTaxes: number, quantity: number, priceToken: string | null, seller: { identifier: string } }> }, additionalProperty: Array<{ propertyID: string, name: string, value: any, valueReference: any }>, advertisement: { adId: string, adResponseId: string } | null, deliveryPromiseBadges: Array<{ typeName: string | null } | null> | null }>, campaign: { id: string, title: string | null, type: string } } };
|
|
2738
|
-
|
|
2739
2730
|
export type ProductComparisonFragment_ProductFragment = { sku: string, slug: string, name: string, gtin: string, description: string, unitMultiplier: number | null, hasSpecifications: boolean | null, id: string, isVariantOf: { name: string, productGroupID: string, skuVariants: { activeVariations: any | null, slugsMap: any | null, availableVariations: any | null, allVariantProducts: Array<{ name: string, productID: string }> | null } | null }, image: Array<{ url: string, alternateName: string }>, brand: { name: string }, offers: { lowPrice: number, lowPriceWithTaxes: number, offers: Array<{ availability: string, price: number, priceWithTaxes: number, listPrice: number, quantity: number, listPriceWithTaxes: number, priceToken: string | null, seller: { identifier: string } }> }, additionalProperty: Array<{ propertyID: string, name: string, value: any, valueReference: any }>, advertisement: { adId: string, adResponseId: string } | null, skuSpecifications: Array<{ field: { id: string | null, name: string, originalName: string | null }, values: Array<{ name: string, id: string | null, fieldId: string | null, originalName: string | null }> }>, specificationGroups: Array<{ name: string, originalName: string, specifications: Array<{ name: string, originalName: string, values: Array<string> }> }> };
|
|
2740
2731
|
|
|
2741
2732
|
export type ProductSkuMatrixSidebarFragment_ProductFragment = { id: string, isVariantOf: { name: string, productGroupID: string, skuVariants: { activeVariations: any | null, slugsMap: any | null, availableVariations: any | null, allVariantProducts: Array<{ sku: string, name: string, image: Array<{ url: string, alternateName: string }>, offers: { highPrice: number, lowPrice: number, lowPriceWithTaxes: number, offerCount: number, priceCurrency: string, offers: Array<{ listPrice: number, listPriceWithTaxes: number, sellingPrice: number, priceCurrency: string, price: number, priceWithTaxes: number, priceValidUntil: string, itemCondition: string, availability: string, quantity: number, priceToken: string | null }> }, additionalProperty: Array<{ propertyID: string, value: any, name: string, valueReference: any }> }> | null } | null } };
|
|
@@ -2994,6 +2985,15 @@ export type ClientProfileQueryQueryVariables = Exact<{
|
|
|
2994
2985
|
|
|
2995
2986
|
export type ClientProfileQueryQuery = { profile: { addresses: Array<{ country: string | null, postalCode: string | null, geoCoordinate: Array<number | null> | null, city: string | null } | null> | null } | null };
|
|
2996
2987
|
|
|
2988
|
+
export type ClientRecommendationsQueryQueryVariables = Exact<{
|
|
2989
|
+
campaignVrn: Scalars['String']['input'];
|
|
2990
|
+
userId: InputMaybe<Scalars['String']['input']>;
|
|
2991
|
+
products: InputMaybe<Array<Scalars['String']['input']> | Scalars['String']['input']>;
|
|
2992
|
+
}>;
|
|
2993
|
+
|
|
2994
|
+
|
|
2995
|
+
export type ClientRecommendationsQueryQuery = { recommendations: { correlationId: string, products: Array<{ slug: string, sku: string, name: string, gtin: string, unitMultiplier: number | null, hasSpecifications: boolean | null, id: string, brand: { name: string, brandName: string }, isVariantOf: { productGroupID: string, name: string, skuVariants: { allVariantsByName: any | null, activeVariations: any | null, slugsMap: any | null, availableVariations: any | null, allVariantProducts: Array<{ name: string, productID: string }> | null } | null }, image: Array<{ url: string, alternateName: string }>, offers: { lowPrice: number, lowPriceWithTaxes: number, offers: Array<{ availability: string, price: number, listPrice: number, listPriceWithTaxes: number, priceWithTaxes: number, quantity: number, priceToken: string | null, seller: { identifier: string } }> }, additionalProperty: Array<{ propertyID: string, name: string, value: any, valueReference: any }>, advertisement: { adId: string, adResponseId: string } | null, deliveryPromiseBadges: Array<{ typeName: string | null } | null> | null }>, campaign: { id: string, title: string | null, type: string } } };
|
|
2996
|
+
|
|
2997
2997
|
export type ClientSearchSuggestionsQueryQueryVariables = Exact<{
|
|
2998
2998
|
term: Scalars['String']['input'];
|
|
2999
2999
|
selectedFacets: InputMaybe<Array<IStoreSelectedFacet> | IStoreSelectedFacet>;
|
|
@@ -3555,7 +3555,6 @@ export const SearchEvent_MetadataFragmentDoc = new TypedDocumentString(`
|
|
|
3555
3555
|
fuzzy
|
|
3556
3556
|
}
|
|
3557
3557
|
`, {"fragmentName":"SearchEvent_metadata"}) as unknown as TypedDocumentString<SearchEvent_MetadataFragment, unknown>;
|
|
3558
|
-
export const ClientRecommendationsQueryDocument = {"__meta__":{"operationName":"ClientRecommendationsQuery","operationHash":"b227071b0388469d7b90d04cff4cbc11f8f134d4"}} as unknown as TypedDocumentString<ClientRecommendationsQueryQuery, ClientRecommendationsQueryQueryVariables>;
|
|
3559
3558
|
export const ServerAccountPageQueryDocument = {"__meta__":{"operationName":"ServerAccountPageQuery","operationHash":"9baae331b75848a310fecb457e8c971ae27897ff"}} as unknown as TypedDocumentString<ServerAccountPageQueryQuery, ServerAccountPageQueryQueryVariables>;
|
|
3560
3559
|
export const ServerCollectionPageQueryDocument = {"__meta__":{"operationName":"ServerCollectionPageQuery","operationHash":"d46841b30ae1f6350021b5cf02f253d56c848664"}} as unknown as TypedDocumentString<ServerCollectionPageQueryQuery, ServerCollectionPageQueryQueryVariables>;
|
|
3561
3560
|
export const ServerProductQueryDocument = {"__meta__":{"operationName":"ServerProductQuery","operationHash":"b89e93519be01aebc01c402489a0ae640d38675a"}} as unknown as TypedDocumentString<ServerProductQueryQuery, ServerProductQueryQueryVariables>;
|
|
@@ -3586,6 +3585,7 @@ export const ClientProductQueryDocument = {"__meta__":{"operationName":"ClientPr
|
|
|
3586
3585
|
export const ClientManyProductsQueryDocument = {"__meta__":{"operationName":"ClientManyProductsQuery","operationHash":"ee14fd92b4a04fc3751efcbfcb60b3886d912253"}} as unknown as TypedDocumentString<ClientManyProductsQueryQuery, ClientManyProductsQueryQueryVariables>;
|
|
3587
3586
|
export const ClientManyProductsSelectedQueryDocument = {"__meta__":{"operationName":"ClientManyProductsSelectedQuery","operationHash":"7e1b06c167e411905ceac9db11c1a6a7892cfdd6"}} as unknown as TypedDocumentString<ClientManyProductsSelectedQueryQuery, ClientManyProductsSelectedQueryQueryVariables>;
|
|
3588
3587
|
export const ClientProfileQueryDocument = {"__meta__":{"operationName":"ClientProfileQuery","operationHash":"34ea14c0d4a57ddf9bc11e4be0cd2b5a6506d3d4"}} as unknown as TypedDocumentString<ClientProfileQueryQuery, ClientProfileQueryQueryVariables>;
|
|
3588
|
+
export const ClientRecommendationsQueryDocument = {"__meta__":{"operationName":"ClientRecommendationsQuery","operationHash":"b227071b0388469d7b90d04cff4cbc11f8f134d4"}} as unknown as TypedDocumentString<ClientRecommendationsQueryQuery, ClientRecommendationsQueryQueryVariables>;
|
|
3589
3589
|
export const ClientSearchSuggestionsQueryDocument = {"__meta__":{"operationName":"ClientSearchSuggestionsQuery","operationHash":"ee57cd392fdfde90620787c9954e2ecae47881f9"}} as unknown as TypedDocumentString<ClientSearchSuggestionsQueryQuery, ClientSearchSuggestionsQueryQueryVariables>;
|
|
3590
3590
|
export const ClientTopSearchSuggestionsQueryDocument = {"__meta__":{"operationName":"ClientTopSearchSuggestionsQuery","operationHash":"e2385b0f11726d0068f96548f57a8dd441c064e3"}} as unknown as TypedDocumentString<ClientTopSearchSuggestionsQueryQuery, ClientTopSearchSuggestionsQueryQueryVariables>;
|
|
3591
3591
|
export const ValidateSessionDocument = {"__meta__":{"operationName":"ValidateSession","operationHash":"8c3a5999496e227f167e9dc79697e6c478d48a9e"}} as unknown as TypedDocumentString<ValidateSessionMutation, ValidateSessionMutationVariables>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
{
|
|
2
|
-
"b227071b0388469d7b90d04cff4cbc11f8f134d4": "fragment ProductSummary_product on StoreProduct { additionalProperty { name propertyID value valueReference } advertisement { adId adResponseId } brand { brandName: name } brand { name } deliveryPromiseBadges { typeName } gtin hasSpecifications image { alternateName url } isVariantOf { name productGroupID skuVariants { activeVariations allVariantsByName availableVariations slugsMap } } isVariantOf { name productGroupID skuVariants { activeVariations allVariantProducts { name productID } availableVariations slugsMap } } name offers { lowPrice lowPriceWithTaxes offers { availability listPrice listPriceWithTaxes price priceToken priceWithTaxes quantity seller { identifier } } } id: productID sku slug unitMultiplier unitMultiplier } query ClientRecommendationsQuery($campaignVrn: String!, $products: [String!], $userId: String) { recommendations(userId: $userId, campaignVrn: $campaignVrn, products: $products) { campaign { id title type } correlationId products { ...ProductSummary_product } } }",
|
|
3
2
|
"9baae331b75848a310fecb457e8c971ae27897ff": "query ServerAccountPageQuery { accountProfile { name } }",
|
|
4
3
|
"d46841b30ae1f6350021b5cf02f253d56c848664": "fragment ServerCollectionPage on Query { collection(slug: $slug) { id } } query ServerCollectionPageQuery($slug: String!) { collection(slug: $slug) { breadcrumbList { itemListElement { item name position } } meta { selectedFacets { key value } } otherLocales { locale slug } seo { description title } } ...ServerCollectionPage }",
|
|
5
4
|
"b89e93519be01aebc01c402489a0ae640d38675a": "fragment CartProductItem on StoreProduct { additionalProperty { name propertyID value valueReference } brand { name } gtin image { alternateName url } isVariantOf { name productGroupID skuVariants { activeVariations availableVariations slugsMap } } name sku unitMultiplier } fragment ProductDetailsFragment_product on StoreProduct { additionalProperty { name propertyID value valueReference } brand { name } description gtin image { alternateName url } isVariantOf { name productGroupID skuVariants { activeVariations allVariantProducts { name productID } availableVariations slugsMap } } name offers { lowPrice lowPriceWithTaxes offers { availability listPrice listPriceWithTaxes price priceToken priceWithTaxes quantity seller { identifier } } } id: productID sku unitMultiplier ...CartProductItem } fragment ServerProduct on Query { product(locator: $locator) { id: productID } } query ServerProductQuery($locator: [IStoreSelectedFacet!]!) { product(locator: $locator) { brand { name } breadcrumbList { itemListElement { item name position } } description gtin image { alternateName url } isVariantOf { productGroupID } mpn name offers { highPrice lowPrice lowPriceWithTaxes offers { availability itemCondition price priceCurrency priceToken priceValidUntil seller { identifier } } priceCurrency } otherLocales { locale slug } id: productID releaseDate seo { canonical description title } sku ...ProductDetailsFragment_product } ...ServerProduct }",
|
|
@@ -30,6 +29,7 @@
|
|
|
30
29
|
"ee14fd92b4a04fc3751efcbfcb60b3886d912253": "fragment ClientManyProducts on Query { search( first: $first after: $after sort: $sort term: $term selectedFacets: $selectedFacets sponsoredCount: $sponsoredCount ) { products { pageInfo { totalCount } } } } fragment ProductSummary_product on StoreProduct { additionalProperty { name propertyID value valueReference } advertisement { adId adResponseId } brand { brandName: name } brand { name } deliveryPromiseBadges { typeName } gtin hasSpecifications image { alternateName url } isVariantOf { name productGroupID skuVariants { activeVariations allVariantsByName availableVariations slugsMap } } isVariantOf { name productGroupID skuVariants { activeVariations allVariantProducts { name productID } availableVariations slugsMap } } name offers { lowPrice lowPriceWithTaxes offers { availability listPrice listPriceWithTaxes price priceToken priceWithTaxes quantity seller { identifier } } } id: productID sku slug unitMultiplier unitMultiplier } query ClientManyProductsQuery($after: String, $first: Int!, $selectedFacets: [IStoreSelectedFacet!]!, $sort: StoreSort!, $sponsoredCount: Int, $term: String!) { search( first: $first after: $after sort: $sort term: $term selectedFacets: $selectedFacets sponsoredCount: $sponsoredCount ) { products { edges { node { ...ProductSummary_product } } pageInfo { totalCount } } } ...ClientManyProducts }",
|
|
31
30
|
"7e1b06c167e411905ceac9db11c1a6a7892cfdd6": "fragment ProductComparisonFragment_product on StoreProduct { additionalProperty { name propertyID value valueReference } advertisement { adId adResponseId } brand { name } description gtin hasSpecifications image { alternateName url } isVariantOf { name productGroupID skuVariants { activeVariations allVariantProducts { name productID } availableVariations slugsMap } } name offers { lowPrice lowPriceWithTaxes offers { availability listPrice listPriceWithTaxes price priceToken priceWithTaxes quantity seller { identifier } } } id: productID sku skuSpecifications { field { id name originalName } values { fieldId id name originalName } } slug specificationGroups { name originalName specifications { name originalName values } } unitMultiplier } query ClientManyProductsSelectedQuery($productIds: [String!]!) { products(productIds: $productIds) { ...ProductComparisonFragment_product } }",
|
|
32
31
|
"34ea14c0d4a57ddf9bc11e4be0cd2b5a6506d3d4": "query ClientProfileQuery($id: String!) { profile(id: $id) { addresses { city country geoCoordinate postalCode } } }",
|
|
32
|
+
"b227071b0388469d7b90d04cff4cbc11f8f134d4": "fragment ProductSummary_product on StoreProduct { additionalProperty { name propertyID value valueReference } advertisement { adId adResponseId } brand { brandName: name } brand { name } deliveryPromiseBadges { typeName } gtin hasSpecifications image { alternateName url } isVariantOf { name productGroupID skuVariants { activeVariations allVariantsByName availableVariations slugsMap } } isVariantOf { name productGroupID skuVariants { activeVariations allVariantProducts { name productID } availableVariations slugsMap } } name offers { lowPrice lowPriceWithTaxes offers { availability listPrice listPriceWithTaxes price priceToken priceWithTaxes quantity seller { identifier } } } id: productID sku slug unitMultiplier unitMultiplier } query ClientRecommendationsQuery($campaignVrn: String!, $products: [String!], $userId: String) { recommendations(userId: $userId, campaignVrn: $campaignVrn, products: $products) { campaign { id title type } correlationId products { ...ProductSummary_product } } }",
|
|
33
33
|
"ee57cd392fdfde90620787c9954e2ecae47881f9": "fragment ClientSearchSuggestions on Query { search(first: 5, term: $term, selectedFacets: $selectedFacets) { suggestions { terms { value } } } } fragment ProductSummary_product on StoreProduct { additionalProperty { name propertyID value valueReference } advertisement { adId adResponseId } brand { brandName: name } brand { name } deliveryPromiseBadges { typeName } gtin hasSpecifications image { alternateName url } isVariantOf { name productGroupID skuVariants { activeVariations allVariantsByName availableVariations slugsMap } } isVariantOf { name productGroupID skuVariants { activeVariations allVariantProducts { name productID } availableVariations slugsMap } } name offers { lowPrice lowPriceWithTaxes offers { availability listPrice listPriceWithTaxes price priceToken priceWithTaxes quantity seller { identifier } } } id: productID sku slug unitMultiplier unitMultiplier } fragment SearchEvent_metadata on SearchMetadata { fuzzy isTermMisspelled logicalOperator } query ClientSearchSuggestionsQuery($selectedFacets: [IStoreSelectedFacet!], $term: String!) { search(first: 5, term: $term, selectedFacets: $selectedFacets) { metadata { ...SearchEvent_metadata } products { pageInfo { totalCount } } searchId suggestions { products { ...ProductSummary_product } terms { value } } } ...ClientSearchSuggestions }",
|
|
34
34
|
"e2385b0f11726d0068f96548f57a8dd441c064e3": "fragment ClientTopSearchSuggestions on Query { search(first: 5, term: $term, selectedFacets: $selectedFacets) { suggestions { terms { value } } } } query ClientTopSearchSuggestionsQuery($selectedFacets: [IStoreSelectedFacet!], $term: String!) { search(first: 5, term: $term, selectedFacets: $selectedFacets) { suggestions { terms { value } } } ...ClientTopSearchSuggestions }",
|
|
35
35
|
"8c3a5999496e227f167e9dc79697e6c478d48a9e": "mutation ValidateSession($search: String!, $session: IStoreSession!) { validateSession(session: $session, search: $search) { addressType b2b { contractName customerId firstName isRepresentative lastName organizationManager savedPostalCode unitId unitName userEmail userName } channel city country currency { code symbol } deliveryMode { deliveryChannel deliveryMethod deliveryWindow { endDate startDate } } geoCoordinates { latitude longitude } locale marketingData { utmCampaign utmMedium utmSource utmiCampaign utmiPage utmiPart } person { email familyName givenName id } postalCode refreshAfter } }",
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
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
|
+
# [4.6.0-dev.3](https://github.com/vtex/faststore/compare/v4.6.0-dev.2...v4.6.0-dev.3) (2026-08-12)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @faststore/core
|
|
9
|
+
|
|
6
10
|
# [4.6.0-dev.2](https://github.com/vtex/faststore/compare/v4.6.0-dev.1...v4.6.0-dev.2) (2026-08-12)
|
|
7
11
|
|
|
8
12
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "4.6.0-dev.
|
|
3
|
+
"version": "4.6.0-dev.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -71,11 +71,11 @@
|
|
|
71
71
|
"style-loader": "^3.3.1",
|
|
72
72
|
"swr": "^2.2.5",
|
|
73
73
|
"use-sync-external-store": "^1.6.0",
|
|
74
|
-
"@faststore/diagnostics": "4.6.0-dev.
|
|
75
|
-
"@faststore/
|
|
76
|
-
"@faststore/
|
|
77
|
-
"@faststore/
|
|
78
|
-
"@faststore/
|
|
74
|
+
"@faststore/diagnostics": "4.6.0-dev.3",
|
|
75
|
+
"@faststore/lighthouse": "4.6.0-dev.3",
|
|
76
|
+
"@faststore/sdk": "4.6.0-dev.3",
|
|
77
|
+
"@faststore/ui": "4.6.0-dev.3",
|
|
78
|
+
"@faststore/api": "4.6.0-dev.3"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@cypress/code-coverage": "^3.12.1",
|
|
@@ -99,8 +99,11 @@ All recommendation work runs client-side after hydration:
|
|
|
99
99
|
5. **Render** — shows `ProductShelfSkeleton` while loading; returns `null` on error or empty results; otherwise renders the carousel and optional heading.
|
|
100
100
|
6. **Tracking** — when correlation and campaign identifiers are present, the shelf emits `data-af-*` attributes for Activity Flow. PDP product views use `product:*` meta tags from `pages/[slug]/p.tsx`.
|
|
101
101
|
|
|
102
|
+
Steps 1 to 4 carry no presentation: they live in `src/sdk/recommendations` and are orchestrated by `useRecommendationShelf()`, which the shelf consumes.
|
|
103
|
+
|
|
102
104
|
Related files:
|
|
103
105
|
|
|
106
|
+
- Shared data layer: `src/sdk/recommendations/`
|
|
104
107
|
- Shelf: `src/components/sections/RecommendationShelf/`
|
|
105
108
|
- Hook: `src/sdk/analytics/hooks/useStartRecommendationSession.ts`
|
|
106
109
|
- Layout: `src/Layout.tsx`
|
|
@@ -129,7 +132,7 @@ import { RecommendationShelf } from 'src/components/sections/RecommendationShelf
|
|
|
129
132
|
- **`ProductCard`**: custom card component (defaults to the core `ProductCard`).
|
|
130
133
|
- **`mapProductToProductCard`**: maps each recommended product (normalized `StoreProduct`) into card props. When provided, it fully owns the card props and the default `productCardConfiguration` merge no longer applies.
|
|
131
134
|
|
|
132
|
-
Campaign types and VRN validation are defined in `vrn.ts` (`VRN_TYPE_TO_RECOMMENDATION`). Updates should be made there and mirrored in the CMS schema `pattern`.
|
|
135
|
+
Campaign types and VRN validation are defined in `src/sdk/recommendations/vrn.ts` (`VRN_TYPE_TO_RECOMMENDATION`). Updates should be made there and mirrored in the CMS schema `pattern`.
|
|
133
136
|
|
|
134
137
|
## Placement guidelines
|
|
135
138
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { type ComponentType, useId, useMemo } from 'react'
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { ProductShelf, Carousel } from '@faststore/ui'
|
|
3
|
+
import { Carousel, ProductShelf } from '@faststore/ui'
|
|
5
4
|
import type { ProductSummary_ProductFragment } from '@generated/graphql'
|
|
6
5
|
|
|
7
6
|
import DefaultProductCard, {
|
|
8
7
|
type ProductCardProps,
|
|
9
8
|
} from 'src/components/product/ProductCard'
|
|
10
9
|
import ProductShelfSkeleton from 'src/components/skeletons/ProductShelfSkeleton'
|
|
11
|
-
import {
|
|
10
|
+
import { useRecommendationShelf } from 'src/sdk/recommendations'
|
|
12
11
|
import useScreenResize from 'src/sdk/ui/useScreenResize'
|
|
13
12
|
|
|
14
13
|
import type {
|
|
@@ -16,48 +15,6 @@ import type {
|
|
|
16
15
|
RecommendationShelfProps,
|
|
17
16
|
} from './RecommendationShelf.types'
|
|
18
17
|
import styles from './section.module.scss'
|
|
19
|
-
import {
|
|
20
|
-
useRecommendations,
|
|
21
|
-
type RecommendationInput,
|
|
22
|
-
} from './useRecommendations'
|
|
23
|
-
import { useRecommendationUserId } from './useRecommendationUserId'
|
|
24
|
-
import { getTypeFromVrn } from './vrn'
|
|
25
|
-
|
|
26
|
-
function getRecommendationArguments(
|
|
27
|
-
campaignVrn: string,
|
|
28
|
-
context: { userId?: string | null; contextProducts: string[] }
|
|
29
|
-
): RecommendationInput | null {
|
|
30
|
-
const { userId, contextProducts } = context
|
|
31
|
-
const type = getTypeFromVrn(campaignVrn)
|
|
32
|
-
|
|
33
|
-
// `type` is null for malformed/unknown VRNs; bail out so we never fetch (and
|
|
34
|
-
// never throw) on an invalid campaign coming from the CMS.
|
|
35
|
-
if (!type || !userId) return null
|
|
36
|
-
|
|
37
|
-
switch (type) {
|
|
38
|
-
case 'NEXT_INTERACTION':
|
|
39
|
-
case 'VISUAL_SIMILARITY':
|
|
40
|
-
case 'CROSS_SELL':
|
|
41
|
-
case 'SIMILAR_ITEMS':
|
|
42
|
-
// These campaigns need product context. Without any (e.g. `CART` context
|
|
43
|
-
// on an empty cart, or `PDP` context outside a product page), skip the
|
|
44
|
-
// fetch instead of requesting recommendations we can't anchor.
|
|
45
|
-
if (contextProducts.length === 0) {
|
|
46
|
-
return null
|
|
47
|
-
}
|
|
48
|
-
return {
|
|
49
|
-
userId,
|
|
50
|
-
campaignVrn,
|
|
51
|
-
products: contextProducts,
|
|
52
|
-
}
|
|
53
|
-
default:
|
|
54
|
-
return {
|
|
55
|
-
userId,
|
|
56
|
-
campaignVrn,
|
|
57
|
-
products: [],
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
18
|
|
|
62
19
|
export function RecommendationShelf<
|
|
63
20
|
TCardProps extends object = ProductCardProps,
|
|
@@ -96,43 +53,14 @@ export function RecommendationShelf<
|
|
|
96
53
|
const itemsPerPage =
|
|
97
54
|
isMobile || isTablet ? itemsPerPageMobile : itemsPerPageDesktop
|
|
98
55
|
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
// source: the current PDP product, or the (deduplicated) cart items.
|
|
106
|
-
const contextProducts = useMemo(() => {
|
|
107
|
-
if (itemsContext === 'CART') {
|
|
108
|
-
return Array.from(
|
|
109
|
-
new Set(
|
|
110
|
-
cartItems
|
|
111
|
-
.map((item) => item.itemOffered.isVariantOf.productGroupID)
|
|
112
|
-
.filter(Boolean)
|
|
113
|
-
)
|
|
114
|
-
)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const pdpProduct = productDetailPage?.product?.isVariantOf?.productGroupID
|
|
118
|
-
|
|
119
|
-
return pdpProduct ? [pdpProduct] : []
|
|
120
|
-
}, [itemsContext, cartItems, productDetailPage])
|
|
121
|
-
|
|
122
|
-
// Gate the whole feature behind the CMS opt-in: when Recommendations is
|
|
123
|
-
// disabled the shelf never requests recommendations (nor renders).
|
|
124
|
-
const recommendationArgs = enableRecommendations
|
|
125
|
-
? getRecommendationArguments(campaignVrn, {
|
|
126
|
-
userId,
|
|
127
|
-
contextProducts,
|
|
128
|
-
})
|
|
129
|
-
: null
|
|
130
|
-
|
|
131
|
-
const { data, isLoading, error } = useRecommendations(recommendationArgs)
|
|
56
|
+
const { items, isLoading, error, campaign, correlationId } =
|
|
57
|
+
useRecommendationShelf({
|
|
58
|
+
campaignVrn,
|
|
59
|
+
enableRecommendations,
|
|
60
|
+
itemsContext,
|
|
61
|
+
})
|
|
132
62
|
|
|
133
|
-
const
|
|
134
|
-
const correlationId = data?.correlationId
|
|
135
|
-
const campaignId = data?.campaign.id
|
|
63
|
+
const campaignId = campaign?.id
|
|
136
64
|
|
|
137
65
|
const productIds = useMemo(
|
|
138
66
|
() => items.map((p) => p.isVariantOf.productGroupID).join(', '),
|
|
@@ -147,15 +75,6 @@ export function RecommendationShelf<
|
|
|
147
75
|
)
|
|
148
76
|
|
|
149
77
|
if (error) {
|
|
150
|
-
// Don't log `recommendationArgs`: it carries the userId. Log only
|
|
151
|
-
// non-identifying context.
|
|
152
|
-
console.error(
|
|
153
|
-
'Error fetching recommendations',
|
|
154
|
-
error.cause,
|
|
155
|
-
error.message,
|
|
156
|
-
'for campaign',
|
|
157
|
-
campaignVrn
|
|
158
|
-
)
|
|
159
78
|
return null
|
|
160
79
|
}
|
|
161
80
|
|
|
@@ -178,9 +97,9 @@ export function RecommendationShelf<
|
|
|
178
97
|
: {})}
|
|
179
98
|
>
|
|
180
99
|
<ProductShelfSkeleton loading={isLoading} itemsPerPage={itemsPerPage}>
|
|
181
|
-
{(title ||
|
|
100
|
+
{(title || campaign?.title) && (
|
|
182
101
|
<h2 className="text__title-section layout__content">
|
|
183
|
-
{title ||
|
|
102
|
+
{title || campaign?.title}
|
|
184
103
|
</h2>
|
|
185
104
|
)}
|
|
186
105
|
|
|
@@ -4,6 +4,9 @@ import type { CarouselProps } from '@faststore/ui'
|
|
|
4
4
|
import type { ProductSummary_ProductFragment } from '@generated/graphql'
|
|
5
5
|
|
|
6
6
|
import type { ProductCardProps } from 'src/components/product/ProductCard'
|
|
7
|
+
import type { ItemContext } from 'src/sdk/recommendations'
|
|
8
|
+
|
|
9
|
+
export type { ItemContext, RecommendationType } from 'src/sdk/recommendations'
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* Maps a recommendation product (a normalized `StoreProduct`, identical to the
|
|
@@ -17,14 +20,6 @@ export type RecommendationProductCardMapper<TCardProps = ProductCardProps> = (
|
|
|
17
20
|
index: number
|
|
18
21
|
) => TCardProps
|
|
19
22
|
|
|
20
|
-
/**
|
|
21
|
-
* Source of the products used as context for the recommendation request:
|
|
22
|
-
* - `'PDP'`: the current product detail page product.
|
|
23
|
-
* - `'CART'`: the products currently in the cart (useful for cross-sell on the
|
|
24
|
-
* cart page).
|
|
25
|
-
*/
|
|
26
|
-
export type ItemContext = 'PDP' | 'CART'
|
|
27
|
-
|
|
28
23
|
export type RecommendationShelfProps<
|
|
29
24
|
TCardProps extends object = ProductCardProps,
|
|
30
25
|
> = {
|
|
@@ -106,13 +101,3 @@ export type RecommendationShelfProps<
|
|
|
106
101
|
readonly bordered?: boolean
|
|
107
102
|
}
|
|
108
103
|
}
|
|
109
|
-
|
|
110
|
-
export type RecommendationType =
|
|
111
|
-
| 'CROSS_SELL'
|
|
112
|
-
| 'SIMILAR_ITEMS'
|
|
113
|
-
| 'PERSONALIZED'
|
|
114
|
-
| 'TOP_ITEMS'
|
|
115
|
-
| 'LAST_SEEN'
|
|
116
|
-
| 'SEARCH_BASED'
|
|
117
|
-
| 'VISUAL_SIMILARITY'
|
|
118
|
-
| 'NEXT_INTERACTION'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type { ItemContext, RecommendationType } from './types'
|
|
2
|
+
export type {
|
|
3
|
+
RecommendationInput,
|
|
4
|
+
RecommendationProduct,
|
|
5
|
+
RecommendationResponse,
|
|
6
|
+
} from './useRecommendations'
|
|
7
|
+
export { useRecommendations } from './useRecommendations'
|
|
8
|
+
export { useRecommendationUserId } from './useRecommendationUserId'
|
|
9
|
+
export type {
|
|
10
|
+
UseRecommendationShelfArgs,
|
|
11
|
+
UseRecommendationShelfResult,
|
|
12
|
+
} from './useRecommendationShelf'
|
|
13
|
+
export {
|
|
14
|
+
getRecommendationArguments,
|
|
15
|
+
useRecommendationShelf,
|
|
16
|
+
} from './useRecommendationShelf'
|
|
17
|
+
export { getTypeFromVrn, isValidVrn } from './vrn'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source of the products used as context for the recommendation request:
|
|
3
|
+
* - `'PDP'`: the current product detail page product.
|
|
4
|
+
* - `'CART'`: the products currently in the cart (useful for cross-sell on the
|
|
5
|
+
* cart page and inside the cart drawer).
|
|
6
|
+
*/
|
|
7
|
+
export type ItemContext = 'PDP' | 'CART'
|
|
8
|
+
|
|
9
|
+
export type RecommendationType =
|
|
10
|
+
| 'CROSS_SELL'
|
|
11
|
+
| 'SIMILAR_ITEMS'
|
|
12
|
+
| 'PERSONALIZED'
|
|
13
|
+
| 'TOP_ITEMS'
|
|
14
|
+
| 'LAST_SEEN'
|
|
15
|
+
| 'SEARCH_BASED'
|
|
16
|
+
| 'VISUAL_SIMILARITY'
|
|
17
|
+
| 'NEXT_INTERACTION'
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { usePDP } from '@faststore/core'
|
|
2
|
+
import { useMemo } from 'react'
|
|
3
|
+
|
|
4
|
+
import { useCart } from 'src/sdk/cart'
|
|
5
|
+
|
|
6
|
+
import type { ItemContext } from './types'
|
|
7
|
+
import {
|
|
8
|
+
type RecommendationInput,
|
|
9
|
+
type RecommendationResponse,
|
|
10
|
+
useRecommendations,
|
|
11
|
+
} from './useRecommendations'
|
|
12
|
+
import { useRecommendationUserId } from './useRecommendationUserId'
|
|
13
|
+
import { getTypeFromVrn } from './vrn'
|
|
14
|
+
|
|
15
|
+
export function getRecommendationArguments(
|
|
16
|
+
campaignVrn: string,
|
|
17
|
+
context: { userId?: string | null; contextProducts: string[] }
|
|
18
|
+
): RecommendationInput | null {
|
|
19
|
+
const { userId, contextProducts } = context
|
|
20
|
+
const type = getTypeFromVrn(campaignVrn)
|
|
21
|
+
|
|
22
|
+
// `type` is null for malformed/unknown VRNs; bail out so we never fetch (and
|
|
23
|
+
// never throw) on an invalid campaign coming from the CMS.
|
|
24
|
+
if (!type || !userId) return null
|
|
25
|
+
|
|
26
|
+
switch (type) {
|
|
27
|
+
case 'NEXT_INTERACTION':
|
|
28
|
+
case 'VISUAL_SIMILARITY':
|
|
29
|
+
case 'CROSS_SELL':
|
|
30
|
+
case 'SIMILAR_ITEMS':
|
|
31
|
+
// These campaigns need product context. Without any (e.g. `CART` context
|
|
32
|
+
// on an empty cart, or `PDP` context outside a product page), skip the
|
|
33
|
+
// fetch instead of requesting recommendations we can't anchor.
|
|
34
|
+
if (contextProducts.length === 0) {
|
|
35
|
+
return null
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
userId,
|
|
39
|
+
campaignVrn,
|
|
40
|
+
products: contextProducts,
|
|
41
|
+
}
|
|
42
|
+
default:
|
|
43
|
+
return {
|
|
44
|
+
userId,
|
|
45
|
+
campaignVrn,
|
|
46
|
+
products: [],
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type UseRecommendationShelfArgs = {
|
|
52
|
+
readonly campaignVrn: string
|
|
53
|
+
/**
|
|
54
|
+
* Opt-in for VTEX Recommendations. When `false` (default) the campaign is
|
|
55
|
+
* never requested. The anonymous user id is still resolved, but it goes
|
|
56
|
+
* unused and never leaves the browser.
|
|
57
|
+
*/
|
|
58
|
+
readonly enableRecommendations?: boolean
|
|
59
|
+
/**
|
|
60
|
+
* Where to read the products used as context for the recommendation request.
|
|
61
|
+
* @default 'PDP'
|
|
62
|
+
*/
|
|
63
|
+
readonly itemsContext?: ItemContext
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export type UseRecommendationShelfResult = {
|
|
67
|
+
readonly items: RecommendationResponse['products']
|
|
68
|
+
readonly isLoading: boolean
|
|
69
|
+
readonly error: unknown
|
|
70
|
+
readonly campaign?: RecommendationResponse['campaign']
|
|
71
|
+
readonly correlationId?: string
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const EMPTY_ITEMS: RecommendationResponse['products'] = []
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Headless data layer behind every recommendation shelf: resolves the campaign
|
|
78
|
+
* type, the anonymous user id and the product context, then fetches the
|
|
79
|
+
* campaign. It renders nothing — presentation lives in the shelf components
|
|
80
|
+
* that consume it, so a new surface can reuse the campaign rules instead of
|
|
81
|
+
* reimplementing them.
|
|
82
|
+
*/
|
|
83
|
+
export function useRecommendationShelf({
|
|
84
|
+
campaignVrn,
|
|
85
|
+
enableRecommendations = false,
|
|
86
|
+
itemsContext = 'PDP',
|
|
87
|
+
}: UseRecommendationShelfArgs): UseRecommendationShelfResult {
|
|
88
|
+
const userId = useRecommendationUserId(campaignVrn)
|
|
89
|
+
|
|
90
|
+
const { data: productDetailPage } = usePDP()
|
|
91
|
+
const { items: cartItems } = useCart()
|
|
92
|
+
|
|
93
|
+
// Resolve the products used as context for the request from the configured
|
|
94
|
+
// source: the current PDP product, or the (deduplicated) cart items.
|
|
95
|
+
const contextProducts = useMemo(() => {
|
|
96
|
+
if (itemsContext === 'CART') {
|
|
97
|
+
return Array.from(
|
|
98
|
+
new Set(
|
|
99
|
+
cartItems
|
|
100
|
+
.map((item) => item.itemOffered.isVariantOf.productGroupID)
|
|
101
|
+
.filter(Boolean)
|
|
102
|
+
)
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const pdpProduct = productDetailPage?.product?.isVariantOf?.productGroupID
|
|
107
|
+
|
|
108
|
+
return pdpProduct ? [pdpProduct] : []
|
|
109
|
+
}, [itemsContext, cartItems, productDetailPage])
|
|
110
|
+
|
|
111
|
+
// Gate the whole feature behind the CMS opt-in: when Recommendations is
|
|
112
|
+
// disabled the shelf never requests recommendations (nor renders).
|
|
113
|
+
const recommendationArgs = enableRecommendations
|
|
114
|
+
? getRecommendationArguments(campaignVrn, {
|
|
115
|
+
userId,
|
|
116
|
+
contextProducts,
|
|
117
|
+
})
|
|
118
|
+
: null
|
|
119
|
+
|
|
120
|
+
const { data, isLoading, error } = useRecommendations(recommendationArgs)
|
|
121
|
+
|
|
122
|
+
if (error) {
|
|
123
|
+
// Don't log `recommendationArgs`: it carries the userId. Log only
|
|
124
|
+
// non-identifying context.
|
|
125
|
+
console.error(
|
|
126
|
+
'Error fetching recommendations',
|
|
127
|
+
(error as { cause?: unknown })?.cause,
|
|
128
|
+
(error as { message?: string })?.message,
|
|
129
|
+
'for campaign',
|
|
130
|
+
campaignVrn
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
items: error ? EMPTY_ITEMS : (data?.products ?? EMPTY_ITEMS),
|
|
136
|
+
isLoading,
|
|
137
|
+
error,
|
|
138
|
+
campaign: data?.campaign,
|
|
139
|
+
correlationId: data?.correlationId,
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RecommendationType } from './
|
|
1
|
+
import type { RecommendationType } from './types'
|
|
2
2
|
|
|
3
3
|
// Single source of truth for the campaign taxonomy: maps each Intelligent Search
|
|
4
4
|
// campaign VRN type to its `RecommendationType`. The supported VRN types, the
|
|
@@ -29,23 +29,17 @@ vi.mock('src/components/skeletons/ProductShelfSkeleton', () => ({
|
|
|
29
29
|
}))
|
|
30
30
|
|
|
31
31
|
const useRecommendations = vi.hoisted(() => vi.fn())
|
|
32
|
-
vi.mock(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
useRecommendations,
|
|
36
|
-
})
|
|
37
|
-
)
|
|
32
|
+
vi.mock('src/sdk/recommendations/useRecommendations', () => ({
|
|
33
|
+
useRecommendations,
|
|
34
|
+
}))
|
|
38
35
|
|
|
39
36
|
const useScreenResize = vi.hoisted(() => vi.fn())
|
|
40
37
|
vi.mock('src/sdk/ui/useScreenResize', () => ({ default: useScreenResize }))
|
|
41
38
|
|
|
42
39
|
const useRecommendationUserId = vi.hoisted(() => vi.fn())
|
|
43
|
-
vi.mock(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
useRecommendationUserId,
|
|
47
|
-
})
|
|
48
|
-
)
|
|
40
|
+
vi.mock('src/sdk/recommendations/useRecommendationUserId', () => ({
|
|
41
|
+
useRecommendationUserId,
|
|
42
|
+
}))
|
|
49
43
|
|
|
50
44
|
import { RecommendationShelf } from 'src/components/sections/RecommendationShelf/RecommendationShelf'
|
|
51
45
|
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { renderHook } from '@testing-library/react'
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
const usePDP = vi.hoisted(() => vi.fn())
|
|
5
|
+
vi.mock('@faststore/core', () => ({ usePDP }))
|
|
6
|
+
|
|
7
|
+
const useCart = vi.hoisted(() => vi.fn())
|
|
8
|
+
vi.mock('src/sdk/cart', () => ({ useCart }))
|
|
9
|
+
|
|
10
|
+
const useRecommendations = vi.hoisted(() => vi.fn())
|
|
11
|
+
vi.mock('src/sdk/recommendations/useRecommendations', () => ({
|
|
12
|
+
useRecommendations,
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
const useRecommendationUserId = vi.hoisted(() => vi.fn())
|
|
16
|
+
vi.mock('src/sdk/recommendations/useRecommendationUserId', () => ({
|
|
17
|
+
useRecommendationUserId,
|
|
18
|
+
}))
|
|
19
|
+
|
|
20
|
+
import { useRecommendationShelf } from 'src/sdk/recommendations/useRecommendationShelf'
|
|
21
|
+
|
|
22
|
+
const TOP_ITEMS_VRN = 'vrn:recommendations:acc:rec-top-items-v2:campaign-1'
|
|
23
|
+
const CROSS_SELL_VRN = 'vrn:recommendations:acc:rec-cross-v2:campaign-1'
|
|
24
|
+
|
|
25
|
+
const cartItem = (productGroupID: string) => ({
|
|
26
|
+
itemOffered: { isVariantOf: { productGroupID } },
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const campaignData = {
|
|
30
|
+
products: [
|
|
31
|
+
{ id: 'p-1', isVariantOf: { productGroupID: 'p-1' } },
|
|
32
|
+
{ id: 'p-2', isVariantOf: { productGroupID: 'p-2' } },
|
|
33
|
+
],
|
|
34
|
+
correlationId: 'corr-1',
|
|
35
|
+
campaign: { id: 'camp-1', title: 'Recommended for you', type: 'TOP_ITEMS' },
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const lastArgs = () => useRecommendations.mock.calls.at(-1)?.[0]
|
|
39
|
+
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
usePDP.mockReturnValue({ data: undefined })
|
|
42
|
+
useCart.mockReturnValue({ items: [] })
|
|
43
|
+
useRecommendationUserId.mockReturnValue('user-1')
|
|
44
|
+
useRecommendations.mockReturnValue({
|
|
45
|
+
data: campaignData,
|
|
46
|
+
isLoading: false,
|
|
47
|
+
error: null,
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
afterEach(() => {
|
|
52
|
+
vi.clearAllMocks()
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
describe('useRecommendationShelf', () => {
|
|
56
|
+
it('exposes the campaign payload when enabled', () => {
|
|
57
|
+
const { result } = renderHook(() =>
|
|
58
|
+
useRecommendationShelf({
|
|
59
|
+
campaignVrn: TOP_ITEMS_VRN,
|
|
60
|
+
enableRecommendations: true,
|
|
61
|
+
})
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
expect(result.current.items).toHaveLength(2)
|
|
65
|
+
expect(result.current.campaign?.title).toBe('Recommended for you')
|
|
66
|
+
expect(result.current.correlationId).toBe('corr-1')
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('never fetches while recommendations are disabled', () => {
|
|
70
|
+
renderHook(() => useRecommendationShelf({ campaignVrn: TOP_ITEMS_VRN }))
|
|
71
|
+
|
|
72
|
+
expect(lastArgs()).toBeNull()
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('never fetches before a userId resolves', () => {
|
|
76
|
+
useRecommendationUserId.mockReturnValue(null)
|
|
77
|
+
|
|
78
|
+
renderHook(() =>
|
|
79
|
+
useRecommendationShelf({
|
|
80
|
+
campaignVrn: TOP_ITEMS_VRN,
|
|
81
|
+
enableRecommendations: true,
|
|
82
|
+
})
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
expect(lastArgs()).toBeNull()
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('never fetches on a malformed campaign vrn', () => {
|
|
89
|
+
renderHook(() =>
|
|
90
|
+
useRecommendationShelf({
|
|
91
|
+
campaignVrn: 'not-a-vrn',
|
|
92
|
+
enableRecommendations: true,
|
|
93
|
+
})
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
expect(lastArgs()).toBeNull()
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('anchors cart-context campaigns on the deduplicated cart products', () => {
|
|
100
|
+
useCart.mockReturnValue({
|
|
101
|
+
items: [cartItem('pg-1'), cartItem('pg-2'), cartItem('pg-1')],
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
renderHook(() =>
|
|
105
|
+
useRecommendationShelf({
|
|
106
|
+
campaignVrn: CROSS_SELL_VRN,
|
|
107
|
+
enableRecommendations: true,
|
|
108
|
+
itemsContext: 'CART',
|
|
109
|
+
})
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
expect(lastArgs()).toEqual({
|
|
113
|
+
userId: 'user-1',
|
|
114
|
+
campaignVrn: CROSS_SELL_VRN,
|
|
115
|
+
products: ['pg-1', 'pg-2'],
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('skips cart-context campaigns while the cart is empty', () => {
|
|
120
|
+
renderHook(() =>
|
|
121
|
+
useRecommendationShelf({
|
|
122
|
+
campaignVrn: CROSS_SELL_VRN,
|
|
123
|
+
enableRecommendations: true,
|
|
124
|
+
itemsContext: 'CART',
|
|
125
|
+
})
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
expect(lastArgs()).toBeNull()
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('still fetches context-agnostic campaigns on an empty cart', () => {
|
|
132
|
+
renderHook(() =>
|
|
133
|
+
useRecommendationShelf({
|
|
134
|
+
campaignVrn: TOP_ITEMS_VRN,
|
|
135
|
+
enableRecommendations: true,
|
|
136
|
+
itemsContext: 'CART',
|
|
137
|
+
})
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
expect(lastArgs()).toEqual({
|
|
141
|
+
userId: 'user-1',
|
|
142
|
+
campaignVrn: TOP_ITEMS_VRN,
|
|
143
|
+
products: [],
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('follows the live cart context when not frozen', () => {
|
|
148
|
+
useCart.mockReturnValue({ items: [cartItem('pg-1')] })
|
|
149
|
+
|
|
150
|
+
const { rerender } = renderHook(() =>
|
|
151
|
+
useRecommendationShelf({
|
|
152
|
+
campaignVrn: CROSS_SELL_VRN,
|
|
153
|
+
enableRecommendations: true,
|
|
154
|
+
itemsContext: 'CART',
|
|
155
|
+
})
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
useCart.mockReturnValue({ items: [cartItem('pg-1'), cartItem('pg-2')] })
|
|
159
|
+
rerender()
|
|
160
|
+
|
|
161
|
+
expect(lastArgs()?.products).toEqual(['pg-1', 'pg-2'])
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it('anchors PDP-context campaigns on the current product', () => {
|
|
165
|
+
usePDP.mockReturnValue({
|
|
166
|
+
data: { product: { isVariantOf: { productGroupID: 'pg-pdp' } } },
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
renderHook(() =>
|
|
170
|
+
useRecommendationShelf({
|
|
171
|
+
campaignVrn: CROSS_SELL_VRN,
|
|
172
|
+
enableRecommendations: true,
|
|
173
|
+
})
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
expect(lastArgs()?.products).toEqual(['pg-pdp'])
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
it('returns no items and logs without the userId on error', () => {
|
|
180
|
+
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
181
|
+
useRecommendations.mockReturnValue({
|
|
182
|
+
data: undefined,
|
|
183
|
+
isLoading: false,
|
|
184
|
+
error: new Error('boom'),
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
const { result } = renderHook(() =>
|
|
188
|
+
useRecommendationShelf({
|
|
189
|
+
campaignVrn: TOP_ITEMS_VRN,
|
|
190
|
+
enableRecommendations: true,
|
|
191
|
+
})
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
expect(result.current.items).toEqual([])
|
|
195
|
+
expect(result.current.error).toBeInstanceOf(Error)
|
|
196
|
+
expect(consoleError).toHaveBeenCalled()
|
|
197
|
+
expect(JSON.stringify(consoleError.mock.calls)).not.toContain('user-1')
|
|
198
|
+
})
|
|
199
|
+
})
|
package/test/{components/RecommendationShelf → sdk/recommendations}/useRecommendationUserId.test.ts
RENAMED
|
@@ -14,7 +14,7 @@ vi.mock('src/utils/retry', () => ({
|
|
|
14
14
|
retry: (fn: () => unknown) => Promise.resolve().then(fn),
|
|
15
15
|
}))
|
|
16
16
|
|
|
17
|
-
import { useRecommendationUserId } from 'src/
|
|
17
|
+
import { useRecommendationUserId } from 'src/sdk/recommendations/useRecommendationUserId'
|
|
18
18
|
|
|
19
19
|
const CAMPAIGN_VRN = 'vrn:recommendations:acc:rec-top-items-v2:campaign-1'
|
|
20
20
|
|
package/test/{components/RecommendationShelf → sdk/recommendations}/useRecommendations.test.ts
RENAMED
|
@@ -7,7 +7,7 @@ vi.mock('src/sdk/graphql/useQuery', () => ({
|
|
|
7
7
|
useQuery: useQueryMock,
|
|
8
8
|
}))
|
|
9
9
|
|
|
10
|
-
import { useRecommendations } from 'src/
|
|
10
|
+
import { useRecommendations } from 'src/sdk/recommendations/useRecommendations'
|
|
11
11
|
|
|
12
12
|
afterEach(() => {
|
|
13
13
|
vi.clearAllMocks()
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
getTypeFromVrn,
|
|
5
|
-
isValidVrn,
|
|
6
|
-
} from 'src/components/sections/RecommendationShelf/vrn'
|
|
3
|
+
import { getTypeFromVrn, isValidVrn } from 'src/sdk/recommendations/vrn'
|
|
7
4
|
|
|
8
5
|
const vrn = (type: string) => `vrn:recommendations:account:${type}:campaign-1`
|
|
9
6
|
|
|
File without changes
|
/package/src/{components/sections/RecommendationShelf → sdk/recommendations}/useRecommendations.ts
RENAMED
|
File without changes
|