@faststore/core 4.4.1-dev.0 → 4.5.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/.turbo/turbo-generate.log +4 -4
  2. package/.turbo/turbo-test.log +137 -51
  3. package/@generated/cached-operations.json +4 -0
  4. package/@generated/gql.ts +30 -0
  5. package/@generated/graphql.ts +141 -0
  6. package/@generated/persisted-documents.json +5 -0
  7. package/@generated/schema.graphql +100 -0
  8. package/CHANGELOG.md +26 -0
  9. package/cms/faststore/components/cms_component__recommendationshelf.jsonc +86 -0
  10. package/cms/faststore/schema.json +89 -0
  11. package/discovery.config.default.js +3 -0
  12. package/discovery.config.js +10 -1
  13. package/discovery.config.local.example.js +62 -0
  14. package/package.json +6 -6
  15. package/public/icons.svg +4 -0
  16. package/src/Layout.tsx +6 -0
  17. package/src/components/account/Drawer/OrganizationDrawer/ContractSwitcher/ContractSwitcher.tsx +376 -0
  18. package/src/components/account/Drawer/OrganizationDrawer/ContractSwitcher/index.ts +2 -0
  19. package/src/components/account/Drawer/OrganizationDrawer/OrganizationDrawer.tsx +52 -23
  20. package/src/components/account/Drawer/OrganizationDrawer/OrganizationDrawerBody.tsx +16 -6
  21. package/src/components/account/Drawer/OrganizationDrawer/OrganizationDrawerFooter.tsx +55 -0
  22. package/src/components/account/Drawer/OrganizationDrawer/OrganizationDrawerHeader.tsx +45 -5
  23. package/src/components/account/Drawer/OrganizationDrawer/index.ts +5 -0
  24. package/src/components/account/Drawer/OrganizationDrawer/section.module.scss +452 -54
  25. package/src/components/account/Layout/Layout.tsx +14 -5
  26. package/src/components/account/quotes/MyAccountListQuotes/MyAccountListQuotes.tsx +170 -0
  27. package/src/components/account/quotes/MyAccountListQuotes/MyAccountListQuotesTable/MyAccountListQuotesTable.tsx +194 -0
  28. package/src/components/account/quotes/MyAccountListQuotes/MyAccountListQuotesTable/MyAccountQuoteStatusBadge.tsx +15 -0
  29. package/src/components/account/quotes/MyAccountListQuotes/MyAccountQuotesFilterSlider/MyAccountQuotesFilterSlider.tsx +162 -0
  30. package/src/components/account/quotes/MyAccountListQuotes/MyAccountQuotesFilterSlider/section.module.scss +49 -0
  31. package/src/components/account/quotes/MyAccountListQuotes/MyAccountQuotesSelectedTags/MyAccountQuotesSelectedTags.tsx +125 -0
  32. package/src/components/account/quotes/MyAccountListQuotes/MyAccountQuotesStatusSelector/MyAccountQuotesStatusSelector.tsx +107 -0
  33. package/src/components/account/quotes/MyAccountListQuotes/MyAccountQuotesStatusSelector/styles.module.scss +144 -0
  34. package/src/components/account/quotes/MyAccountListQuotes/index.ts +2 -0
  35. package/src/components/account/quotes/MyAccountListQuotes/quoteFilters.ts +89 -0
  36. package/src/components/account/quotes/MyAccountListQuotes/styles.module.scss +174 -0
  37. package/src/components/cms/global/Components.ts +10 -0
  38. package/src/components/sections/ProductGallery/ProductGallery.tsx +1 -1
  39. package/src/components/sections/RecommendationShelf/RecommendationShelf.tsx +223 -0
  40. package/src/components/sections/RecommendationShelf/RecommendationShelf.types.ts +111 -0
  41. package/src/components/sections/RecommendationShelf/index.ts +1 -0
  42. package/src/components/sections/RecommendationShelf/section.module.scss +49 -0
  43. package/src/components/sections/RecommendationShelf/useRecommendationUserId.ts +49 -0
  44. package/src/components/sections/RecommendationShelf/useRecommendations.ts +55 -0
  45. package/src/components/sections/RecommendationShelf/vrn.ts +55 -0
  46. package/src/customizations/src/myAccount/extensions/quotes/after.tsx +5 -0
  47. package/src/customizations/src/myAccount/extensions/quotes/before.tsx +5 -0
  48. package/src/pages/[slug]/p.tsx +45 -0
  49. package/src/pages/pvt/account/quotes/index.tsx +264 -0
  50. package/src/sdk/account/changeContractToken.ts +119 -0
  51. package/src/sdk/account/clearPersistedSessionState.ts +26 -0
  52. package/src/sdk/account/getMyAccountRoutes.ts +7 -0
  53. package/src/sdk/account/refreshToken.ts +21 -8
  54. package/src/sdk/account/useAvailableContracts.ts +49 -0
  55. package/src/sdk/account/useSwitchContract.ts +60 -0
  56. package/src/sdk/analytics/hooks/useStartRecommendationSession.ts +96 -0
  57. package/src/sdk/analytics/utils.ts +9 -0
  58. package/src/utils/quoteStatus.ts +27 -0
  59. package/src/utils/retry.ts +69 -0
  60. package/test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx +235 -0
  61. package/test/components/RecommendationShelf/useRecommendationUserId.test.ts +69 -0
  62. package/test/components/RecommendationShelf/useRecommendations.test.ts +52 -0
  63. package/test/components/RecommendationShelf/vrn.test.ts +56 -0
  64. package/test/components/account/ContractSwitcher.browser.test.tsx +236 -0
  65. package/test/components/account/Layout.test.tsx +62 -0
  66. package/test/components/account/OrganizationDrawer.browser.test.tsx +197 -0
  67. package/test/components/account/OrganizationDrawerBody.test.tsx +52 -0
  68. package/test/components/account/OrganizationDrawerFooter.browser.test.tsx +54 -0
  69. package/test/components/account/OrganizationDrawerHeader.browser.test.tsx +55 -0
  70. package/test/components/account/doLogout.browser.test.ts +102 -0
  71. package/test/components/quotes/MyAccountListQuotes.test.tsx +232 -0
  72. package/test/components/quotes/MyAccountListQuotesTable.test.tsx +240 -0
  73. package/test/components/quotes/MyAccountQuoteStatusBadge.test.tsx +28 -0
  74. package/test/components/quotes/MyAccountQuotesFilterSlider.test.tsx +152 -0
  75. package/test/components/quotes/MyAccountQuotesSelectedTags.test.tsx +122 -0
  76. package/test/components/quotes/MyAccountQuotesStatusSelector.test.tsx +85 -0
  77. package/test/components/quotes/quoteFilters.test.ts +185 -0
  78. package/test/sdk/account/changeContractToken.browser.test.ts +157 -0
  79. package/test/sdk/account/clearPersistedSessionState.browser.test.ts +41 -0
  80. package/test/sdk/account/clearPersistedSessionState.test.ts +20 -0
  81. package/test/sdk/account/getMyAccountRoutes.test.ts +90 -0
  82. package/test/sdk/account/refreshToken.browser.test.ts +34 -0
  83. package/test/sdk/account/refreshToken.test.ts +87 -0
  84. package/test/sdk/account/useAvailableContracts.browser.test.ts +124 -0
  85. package/test/sdk/account/useSwitchContract.browser.test.ts +111 -0
  86. package/test/sdk/analytics/useStartRecommendationSession.test.ts +69 -0
  87. package/test/sdk/analytics/utils.test.ts +23 -0
  88. package/test/server/index.test.ts +5 -0
  89. package/test/utils/retry.test.ts +59 -0
@@ -671,6 +671,8 @@ export type Mutation = {
671
671
  * Returns an operationId to poll for the operation status.
672
672
  */
673
673
  startOrderEntryOperation: Maybe<StoreOrderEntryOperationResult>;
674
+ /** Starts an anonymous personalization session for the current shopper. */
675
+ startRecommendationSession: Scalars['Boolean']['output'];
674
676
  /** Subscribes a new person to the newsletter list. */
675
677
  subscribeToNewsletter: Maybe<PersonNewsletter>;
676
678
  /**
@@ -871,10 +873,20 @@ export type Query = {
871
873
  allCollections: StoreCollectionConnection;
872
874
  /** Returns information about all products. */
873
875
  allProducts: StoreProductConnection;
876
+ /**
877
+ * Lists the commercial contracts associated with the given Organization Unit,
878
+ * resolved to human-readable corporate names. Governed: only contracts associated
879
+ * with the authenticated buyer's Organization Unit are returned.
880
+ */
881
+ availableContracts: Array<StoreContract>;
874
882
  /** Returns the details of a collection based on the collection slug. */
875
883
  collection: StoreCollection;
884
+ /** Returns whether the current authenticated user belongs to a B2B organization unit. */
885
+ isOrganizationMember: Scalars['Boolean']['output'];
876
886
  /** Returns the list of Orders that the User can view. */
877
887
  listUserOrders: Maybe<UserOrderListMinimalResult>;
888
+ /** Returns the list of Quotes that the authenticated Buyer can view. */
889
+ listUserQuotes: Maybe<UserQuoteListResult>;
878
890
  /** Returns the status of an Order Entry Service operation by its ID. */
879
891
  orderEntryOperation: Maybe<StoreOrderEntryOperationStatus>;
880
892
  /** Returns the items in an orderForm by its ID. */
@@ -889,6 +901,8 @@ export type Query = {
889
901
  products: Array<StoreProduct>;
890
902
  /** Returns information about the profile. */
891
903
  profile: Maybe<Profile>;
904
+ /** Returns personalized product recommendations for a given campaign. */
905
+ recommendations: RecommendationResponse;
892
906
  /** Returns if there's a redirect for a search. */
893
907
  redirect: Maybe<StoreRedirect>;
894
908
  /** Returns the result of a product, facet, or suggestion search. */
@@ -918,6 +932,11 @@ export type QueryAllProductsArgs = {
918
932
  };
919
933
 
920
934
 
935
+ export type QueryAvailableContractsArgs = {
936
+ orgUnitId: Scalars['String']['input'];
937
+ };
938
+
939
+
921
940
  export type QueryCollectionArgs = {
922
941
  slug: Scalars['String']['input'];
923
942
  };
@@ -935,6 +954,18 @@ export type QueryListUserOrdersArgs = {
935
954
  };
936
955
 
937
956
 
957
+ export type QueryListUserQuotesArgs = {
958
+ createdAtFrom: InputMaybe<Scalars['String']['input']>;
959
+ createdAtTo: InputMaybe<Scalars['String']['input']>;
960
+ expiresAtFrom: InputMaybe<Scalars['String']['input']>;
961
+ expiresAtTo: InputMaybe<Scalars['String']['input']>;
962
+ label: InputMaybe<Scalars['String']['input']>;
963
+ page: InputMaybe<Scalars['Int']['input']>;
964
+ perPage: InputMaybe<Scalars['Int']['input']>;
965
+ status: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>>;
966
+ };
967
+
968
+
938
969
  export type QueryOrderEntryOperationArgs = {
939
970
  operationId: Scalars['String']['input'];
940
971
  };
@@ -970,6 +1001,13 @@ export type QueryProfileArgs = {
970
1001
  };
971
1002
 
972
1003
 
1004
+ export type QueryRecommendationsArgs = {
1005
+ campaignVrn: Scalars['String']['input'];
1006
+ products: InputMaybe<Array<Scalars['String']['input']>>;
1007
+ userId: InputMaybe<Scalars['String']['input']>;
1008
+ };
1009
+
1010
+
973
1011
  export type QueryRedirectArgs = {
974
1012
  selectedFacets: InputMaybe<Array<IStoreSelectedFacet>>;
975
1013
  term: InputMaybe<Scalars['String']['input']>;
@@ -1005,6 +1043,18 @@ export type QueryUserOrderArgs = {
1005
1043
  orderId: Scalars['String']['input'];
1006
1044
  };
1007
1045
 
1046
+ export type RecommendationCampaign = {
1047
+ id: Scalars['String']['output'];
1048
+ title: Maybe<Scalars['String']['output']>;
1049
+ type: Scalars['String']['output'];
1050
+ };
1051
+
1052
+ export type RecommendationResponse = {
1053
+ campaign: RecommendationCampaign;
1054
+ correlationId: Scalars['String']['output'];
1055
+ products: Array<StoreProduct>;
1056
+ };
1057
+
1008
1058
  export type SkuSpecificationField = {
1009
1059
  id: Maybe<Scalars['String']['output']>;
1010
1060
  name: Scalars['String']['output'];
@@ -1295,6 +1345,16 @@ export type StoreCollectionType =
1295
1345
  /** Third level of product categorization. */
1296
1346
  | 'SubCategory';
1297
1347
 
1348
+ /** A commercial contract available to a buyer's Organization Unit. */
1349
+ export type StoreContract = {
1350
+ /** Human-readable corporate name of the contract (resolved from MasterData). */
1351
+ corporateName: Scalars['String']['output'];
1352
+ /** Contract identifier (the contract/scope ID associated with the Organization Unit). */
1353
+ id: Scalars['ID']['output'];
1354
+ /** Indicates whether this contract is the one currently active in the session. */
1355
+ isActive: Scalars['Boolean']['output'];
1356
+ };
1357
+
1298
1358
  /** Currency information. */
1299
1359
  export type StoreCurrency = {
1300
1360
  /** Currency code (e.g: USD). */
@@ -2560,6 +2620,42 @@ export type UserOrderTransactions = {
2560
2620
  transactionId: Maybe<Scalars['String']['output']>;
2561
2621
  };
2562
2622
 
2623
+ /** Pagination metadata for the quotes list. */
2624
+ export type UserQuoteListPaging = {
2625
+ /** Current page number (1-based). */
2626
+ currentPage: Scalars['Int']['output'];
2627
+ /** Number of items per page. */
2628
+ perPage: Scalars['Int']['output'];
2629
+ /** Total number of quotes matching the query. */
2630
+ total: Scalars['Int']['output'];
2631
+ };
2632
+
2633
+ /** Result returned by the listUserQuotes query. */
2634
+ export type UserQuoteListResult = {
2635
+ /** Array of quote summaries for the current page. */
2636
+ list: Array<UserQuoteSummary>;
2637
+ /** Pagination information. */
2638
+ paging: UserQuoteListPaging;
2639
+ };
2640
+
2641
+ /** Summary of a quote returned in list results. */
2642
+ export type UserQuoteSummary = {
2643
+ /** Total amount of the quote. */
2644
+ amount: Scalars['Float']['output'];
2645
+ /** ISO 8601 date-time when the quote was created. */
2646
+ createdAt: Scalars['String']['output'];
2647
+ /** Name or email of the user who created the quote. */
2648
+ createdBy: Maybe<Scalars['String']['output']>;
2649
+ /** ISO 8601 date-time when the quote expires. */
2650
+ expiresAt: Scalars['String']['output'];
2651
+ /** Unique identifier of the quote. */
2652
+ id: Scalars['String']['output'];
2653
+ /** Optional label assigned to the quote. */
2654
+ label: Maybe<Scalars['String']['output']>;
2655
+ /** Status of the quote. */
2656
+ status: Scalars['String']['output'];
2657
+ };
2658
+
2563
2659
  export type ValidateUserData = {
2564
2660
  /** Indicates if the user is valid. */
2565
2661
  isValid: Scalars['Boolean']['output'];
@@ -2578,6 +2674,15 @@ export type Filter_FacetsFragment =
2578
2674
 
2579
2675
  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, seller: { identifier: string } }> }, additionalProperty: Array<{ propertyID: string, name: string, value: any, valueReference: any }> };
2580
2676
 
2677
+ export type ClientRecommendationsQueryQueryVariables = Exact<{
2678
+ campaignVrn: Scalars['String']['input'];
2679
+ userId: InputMaybe<Scalars['String']['input']>;
2680
+ products: InputMaybe<Array<Scalars['String']['input']> | Scalars['String']['input']>;
2681
+ }>;
2682
+
2683
+
2684
+ 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, 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 } } };
2685
+
2581
2686
  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, 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> }> }> };
2582
2687
 
2583
2688
  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 }> }, additionalProperty: Array<{ propertyID: string, value: any, name: string, valueReference: any }> }> | null } | null } };
@@ -2645,6 +2750,25 @@ export type ServerProfileQueryQueryVariables = Exact<{ [key: string]: never; }>;
2645
2750
 
2646
2751
  export type ServerProfileQueryQuery = { accountProfile: { name: string | null, email: string | null, id: string | null } };
2647
2752
 
2753
+ export type ServerListQuotesQueryQueryVariables = Exact<{
2754
+ page: InputMaybe<Scalars['Int']['input']>;
2755
+ perPage: InputMaybe<Scalars['Int']['input']>;
2756
+ status: InputMaybe<Array<InputMaybe<Scalars['String']['input']>> | InputMaybe<Scalars['String']['input']>>;
2757
+ createdAtFrom: InputMaybe<Scalars['String']['input']>;
2758
+ createdAtTo: InputMaybe<Scalars['String']['input']>;
2759
+ expiresAtFrom: InputMaybe<Scalars['String']['input']>;
2760
+ expiresAtTo: InputMaybe<Scalars['String']['input']>;
2761
+ label: InputMaybe<Scalars['String']['input']>;
2762
+ }>;
2763
+
2764
+
2765
+ export type ServerListQuotesQueryQuery = { listUserQuotes: { list: Array<{ id: string, status: string, label: string | null, createdAt: string, expiresAt: string, amount: number, createdBy: string | null }>, paging: { total: number, currentPage: number, perPage: number } } | null };
2766
+
2767
+ export type ServerQuotesOrganizationMemberQueryQueryVariables = Exact<{ [key: string]: never; }>;
2768
+
2769
+
2770
+ export type ServerQuotesOrganizationMemberQueryQuery = { isOrganizationMember: boolean };
2771
+
2648
2772
  export type ServerSecurityQueryVariables = Exact<{ [key: string]: never; }>;
2649
2773
 
2650
2774
 
@@ -2655,6 +2779,13 @@ export type ServerUserDetailsQueryQueryVariables = Exact<{ [key: string]: never;
2655
2779
 
2656
2780
  export type ServerUserDetailsQueryQuery = { accountProfile: { name: string | null }, userDetails: { username: string | null, name: string | null, email: string | null, phone: string | null, role: Array<string | null> | null, orgUnit: string | null } };
2657
2781
 
2782
+ export type AvailableContractsQueryQueryVariables = Exact<{
2783
+ orgUnitId: Scalars['String']['input'];
2784
+ }>;
2785
+
2786
+
2787
+ export type AvailableContractsQueryQuery = { availableContracts: Array<{ id: string, corporateName: string, isActive: boolean }> };
2788
+
2658
2789
  export type CancelOrderMutationMutationVariables = Exact<{
2659
2790
  data: IUserOrderCancel;
2660
2791
  }>;
@@ -2674,6 +2805,11 @@ export type ValidateUserQueryVariables = Exact<{ [key: string]: never; }>;
2674
2805
 
2675
2806
  export type ValidateUserQuery = { validateUser: { isValid: boolean } | null };
2676
2807
 
2808
+ export type StartRecommendationSessionMutationVariables = Exact<{ [key: string]: never; }>;
2809
+
2810
+
2811
+ export type StartRecommendationSessionMutation = { startRecommendationSession: boolean };
2812
+
2677
2813
  export type ValidateCartMutationMutationVariables = Exact<{
2678
2814
  cart: IStoreCart;
2679
2815
  session: IStoreSession;
@@ -3361,17 +3497,22 @@ export const SearchEvent_MetadataFragmentDoc = new TypedDocumentString(`
3361
3497
  fuzzy
3362
3498
  }
3363
3499
  `, {"fragmentName":"SearchEvent_metadata"}) as unknown as TypedDocumentString<SearchEvent_MetadataFragment, unknown>;
3500
+ export const ClientRecommendationsQueryDocument = {"__meta__":{"operationName":"ClientRecommendationsQuery","operationHash":"db61ca57203036d24d5e1e2c9e40d6d0906f0056"}} as unknown as TypedDocumentString<ClientRecommendationsQueryQuery, ClientRecommendationsQueryQueryVariables>;
3364
3501
  export const ServerAccountPageQueryDocument = {"__meta__":{"operationName":"ServerAccountPageQuery","operationHash":"9baae331b75848a310fecb457e8c971ae27897ff"}} as unknown as TypedDocumentString<ServerAccountPageQueryQuery, ServerAccountPageQueryQueryVariables>;
3365
3502
  export const ServerCollectionPageQueryDocument = {"__meta__":{"operationName":"ServerCollectionPageQuery","operationHash":"4b33c5c07f440dc7489e55619dc2211a13786e72"}} as unknown as TypedDocumentString<ServerCollectionPageQueryQuery, ServerCollectionPageQueryQueryVariables>;
3366
3503
  export const ServerProductQueryDocument = {"__meta__":{"operationName":"ServerProductQuery","operationHash":"f03d0963fed159ac4bbe11f90ea09c635a66b68c"}} as unknown as TypedDocumentString<ServerProductQueryQuery, ServerProductQueryQueryVariables>;
3367
3504
  export const ServerOrderDetailsQueryDocument = {"__meta__":{"operationName":"ServerOrderDetailsQuery","operationHash":"bdf677bbccce12186a5ef15aebdce46585a99782"}} as unknown as TypedDocumentString<ServerOrderDetailsQueryQuery, ServerOrderDetailsQueryQueryVariables>;
3368
3505
  export const ServerListOrdersQueryDocument = {"__meta__":{"operationName":"ServerListOrdersQuery","operationHash":"70d06de1da9c11f10ebde31b66fd74eccd456af5"}} as unknown as TypedDocumentString<ServerListOrdersQueryQuery, ServerListOrdersQueryQueryVariables>;
3369
3506
  export const ServerProfileQueryDocument = {"__meta__":{"operationName":"ServerProfileQuery","operationHash":"672fe0f00b7b710b63fc6573c0a6b2ec54812b8f"}} as unknown as TypedDocumentString<ServerProfileQueryQuery, ServerProfileQueryQueryVariables>;
3507
+ export const ServerListQuotesQueryDocument = {"__meta__":{"operationName":"ServerListQuotesQuery","operationHash":"cce44921361a629c793364adb43319601cc0aa33"}} as unknown as TypedDocumentString<ServerListQuotesQueryQuery, ServerListQuotesQueryQueryVariables>;
3508
+ export const ServerQuotesOrganizationMemberQueryDocument = {"__meta__":{"operationName":"ServerQuotesOrganizationMemberQuery","operationHash":"9ba9119f2a361c83af8ecc703cb28f915df10ac8"}} as unknown as TypedDocumentString<ServerQuotesOrganizationMemberQueryQuery, ServerQuotesOrganizationMemberQueryQueryVariables>;
3370
3509
  export const ServerSecurityDocument = {"__meta__":{"operationName":"ServerSecurity","operationHash":"0890ba3456c40a426893b80b698df7a84cfdd6a1"}} as unknown as TypedDocumentString<ServerSecurityQuery, ServerSecurityQueryVariables>;
3371
3510
  export const ServerUserDetailsQueryDocument = {"__meta__":{"operationName":"ServerUserDetailsQuery","operationHash":"630ec1f47f2710ce3d7895e9131482641f30c837"}} as unknown as TypedDocumentString<ServerUserDetailsQueryQuery, ServerUserDetailsQueryQueryVariables>;
3511
+ export const AvailableContractsQueryDocument = {"__meta__":{"operationName":"AvailableContractsQuery","operationHash":"011619bb1be93a21f6530fe4d193dec96a89e88a"}} as unknown as TypedDocumentString<AvailableContractsQueryQuery, AvailableContractsQueryQueryVariables>;
3372
3512
  export const CancelOrderMutationDocument = {"__meta__":{"operationName":"CancelOrderMutation","operationHash":"e2b06da6840614d3c72768e56579b9d3b8e80802"}} as unknown as TypedDocumentString<CancelOrderMutationMutation, CancelOrderMutationMutationVariables>;
3373
3513
  export const ProcessOrderAuthorizationMutationDocument = {"__meta__":{"operationName":"ProcessOrderAuthorizationMutation","operationHash":"8c25d37c8d6e7c20ab21bb8a4f4e6a2fe320ea8d"}} as unknown as TypedDocumentString<ProcessOrderAuthorizationMutationMutation, ProcessOrderAuthorizationMutationMutationVariables>;
3374
3514
  export const ValidateUserDocument = {"__meta__":{"operationName":"ValidateUser","operationHash":"32f99c73c3de958b64d6bece1afe800469f54548"}} as unknown as TypedDocumentString<ValidateUserQuery, ValidateUserQueryVariables>;
3515
+ export const StartRecommendationSessionDocument = {"__meta__":{"operationName":"StartRecommendationSession","operationHash":"1def6438c0cd87b85002411ac7326c221f192583"}} as unknown as TypedDocumentString<StartRecommendationSessionMutation, StartRecommendationSessionMutationVariables>;
3375
3516
  export const ValidateCartMutationDocument = {"__meta__":{"operationName":"ValidateCartMutation","operationHash":"32c15f8888ca34f223def7972b7f19090808435a"}} as unknown as TypedDocumentString<ValidateCartMutationMutation, ValidateCartMutationMutationVariables>;
3376
3517
  export const ClientPickupPointsQueryDocument = {"__meta__":{"operationName":"ClientPickupPointsQuery","operationHash":"3fa04e88c811fcb5ece7206fd5aa745bdbc143a8"}} as unknown as TypedDocumentString<ClientPickupPointsQueryQuery, ClientPickupPointsQueryQueryVariables>;
3377
3518
  export const SubscribeToNewsletterDocument = {"__meta__":{"operationName":"SubscribeToNewsletter","operationHash":"feb7005103a859e2bc8cf2360d568806fd88deba"}} as unknown as TypedDocumentString<SubscribeToNewsletterMutation, SubscribeToNewsletterMutationVariables>;
@@ -1,15 +1,20 @@
1
1
  {
2
+ "db61ca57203036d24d5e1e2c9e40d6d0906f0056": "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 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 } } }",
2
3
  "9baae331b75848a310fecb457e8c971ae27897ff": "query ServerAccountPageQuery { accountProfile { name } }",
3
4
  "4b33c5c07f440dc7489e55619dc2211a13786e72": "fragment ServerCollectionPage on Query { collection(slug: $slug) { id } } query ServerCollectionPageQuery($slug: String!) { collection(slug: $slug) { breadcrumbList { itemListElement { item name position } } meta { selectedFacets { key value } } seo { description title } } ...ServerCollectionPage }",
4
5
  "f03d0963fed159ac4bbe11f90ea09c635a66b68c": "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 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 priceValidUntil seller { identifier } } priceCurrency } id: productID releaseDate seo { canonical description title } sku ...ProductDetailsFragment_product } ...ServerProduct }",
5
6
  "bdf677bbccce12186a5ef15aebdce46585a99782": "query ServerOrderDetailsQuery($orderId: String!) { accountProfile { name } userOrder(orderId: $orderId) { allowCancellation budgetData { budgets { allocations { id linkedEntity { id } reservations } balance { remaining } id name } } canProcessOrderAuthorization clientProfileData { corporateName email firstName isCorporate lastName phone } creationDate customFields { fields { name refId value } id type } deliveryOptionsData { contact { email name phone } deliveryOptions { address { addressId addressType city complement country entityId geoCoordinates neighborhood number postalCode receiverName reference state street versionId } deliveryChannel deliveryCompany deliveryWindow { endDateUtc price startDateUtc } friendlyDeliveryOptionName friendlyShippingEstimate items { id imageUrl name price quantity sellingPrice tax taxPriceTagsTotal total uniqueId } pickupStoreInfo { additionalInfo address { addressId addressType city complement country entityId geoCoordinates neighborhood number postalCode receiverName reference state street versionId } dockId friendlyName isPickupStore } quantityOfDifferentItems selectedSla seller shippingEstimate shippingEstimateDate total } } orderId paymentData { transactions { isActive payments { bankIssuedInvoiceIdentificationNumber connectorResponses { authId } group id installments lastDigits paymentOrigin paymentSystemName redemptionCode referenceValue tid url value } } } ruleForAuthorization { dimensionId orderAuthorizationId rule { authorizationData { authorizers { authorizationDate email id type } requireAllApprovals } authorizedEmails doId id isUserAuthorized isUserNextAuthorizer name notification priority scoreInterval { accept deny } status timeout trigger { condition { conditionType description expression greatherThan lessThan } effect { description effectType funcPath } } } } shopper { email firstName lastName phone } status statusDescription storePreferencesData { currencyCode } totals { id name value } } }",
6
7
  "70d06de1da9c11f10ebde31b66fd74eccd456af5": "query ServerListOrdersQuery($clientEmail: String, $dateFinal: String, $dateInitial: String, $page: Int, $pendingMyApproval: Boolean, $perPage: Int, $status: [String], $text: String) { accountProfile { name } listUserOrders( page: $page perPage: $perPage status: $status dateInitial: $dateInitial dateFinal: $dateFinal text: $text clientEmail: $clientEmail pendingMyApproval: $pendingMyApproval ) { list { ShippingEstimatedDate clientName creationDate currencyCode customFields { type value } items { description ean id price productId quantity refId seller sellingPrice } orderId status statusDescription totalValue } paging { currentPage pages perPage total } } }",
7
8
  "672fe0f00b7b710b63fc6573c0a6b2ec54812b8f": "query ServerProfileQuery { accountProfile { email id name } }",
9
+ "cce44921361a629c793364adb43319601cc0aa33": "query ServerListQuotesQuery($createdAtFrom: String, $createdAtTo: String, $expiresAtFrom: String, $expiresAtTo: String, $label: String, $page: Int, $perPage: Int, $status: [String]) { listUserQuotes( page: $page perPage: $perPage status: $status createdAtFrom: $createdAtFrom createdAtTo: $createdAtTo expiresAtFrom: $expiresAtFrom expiresAtTo: $expiresAtTo label: $label ) { list { amount createdAt createdBy expiresAt id label status } paging { currentPage perPage total } } }",
10
+ "9ba9119f2a361c83af8ecc703cb28f915df10ac8": "query ServerQuotesOrganizationMemberQuery { isOrganizationMember }",
8
11
  "0890ba3456c40a426893b80b698df7a84cfdd6a1": "query ServerSecurity { accountProfile { name } userDetails { email } }",
9
12
  "630ec1f47f2710ce3d7895e9131482641f30c837": "query ServerUserDetailsQuery { accountProfile { name } userDetails { email name orgUnit phone role username } }",
13
+ "011619bb1be93a21f6530fe4d193dec96a89e88a": "query AvailableContractsQuery($orgUnitId: String!) { availableContracts(orgUnitId: $orgUnitId) { corporateName id isActive } }",
10
14
  "e2b06da6840614d3c72768e56579b9d3b8e80802": "mutation CancelOrderMutation($data: IUserOrderCancel!) { cancelOrder(data: $data) { data } }",
11
15
  "8c25d37c8d6e7c20ab21bb8a4f4e6a2fe320ea8d": "mutation ProcessOrderAuthorizationMutation($data: IProcessOrderAuthorization!) { processOrderAuthorization(data: $data) { isPendingForOtherAuthorizer ruleForAuthorization { dimensionId orderAuthorizationId rule { authorizationData { authorizers { authorizationDate email id type } requireAllApprovals } authorizedEmails doId id isUserAuthorized isUserNextAuthorizer name notification priority scoreInterval { accept deny } status timeout trigger { condition { conditionType description expression greatherThan lessThan } effect { description effectType funcPath } } } } } }",
12
16
  "32f99c73c3de958b64d6bece1afe800469f54548": "query ValidateUser { validateUser { isValid } }",
17
+ "1def6438c0cd87b85002411ac7326c221f192583": "mutation StartRecommendationSession { startRecommendationSession }",
13
18
  "32c15f8888ca34f223def7972b7f19090808435a": "fragment CartItem on StoreOffer { isGift itemOffered { ...CartProductItem } listPrice listPriceWithTaxes price priceWithTaxes quantity seller { identifier } } fragment CartMessage on StoreCartMessage { status text } 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 } mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) { validateCart(cart: $cart, session: $session) { messages { ...CartMessage } order { acceptedOffer { ...CartItem } orderNumber shouldSplitItem } } }",
14
19
  "3fa04e88c811fcb5ece7206fd5aa745bdbc143a8": "query ClientPickupPointsQuery($geoCoordinates: IStoreGeoCoordinates) { pickupPoints(geoCoordinates: $geoCoordinates) { pickupPointDistances { address { city number postalCode state street } distance isActive pickupId pickupName } } }",
15
20
  "feb7005103a859e2bc8cf2360d568806fd88deba": "mutation SubscribeToNewsletter($data: IPersonNewsletter!) { subscribeToNewsletter(data: $data) { id } }",
@@ -673,6 +673,8 @@ type Mutation {
673
673
  Returns an operationId to poll for the operation status.
674
674
  """
675
675
  startOrderEntryOperation(data: IOrderEntryOperation!): StoreOrderEntryOperationResult @auth
676
+ """Starts an anonymous personalization session for the current shopper."""
677
+ startRecommendationSession: Boolean!
676
678
  }
677
679
 
678
680
  """
@@ -941,6 +943,25 @@ type Query {
941
943
  """Filter orders that are pending user approval."""
942
944
  pendingMyApproval: Boolean
943
945
  ): UserOrderListMinimalResult @auth @cacheControl(scope: "private", sMaxAge: 300, staleWhileRevalidate: 3600)
946
+ """Returns the list of Quotes that the authenticated Buyer can view."""
947
+ listUserQuotes(
948
+ """Page number (1-based)."""
949
+ page: Int
950
+ """Number of items per page."""
951
+ perPage: Int
952
+ """Filter by quote status values."""
953
+ status: [String]
954
+ """Filter quotes created on or after this ISO 8601 date-time."""
955
+ createdAtFrom: String
956
+ """Filter quotes created on or before this ISO 8601 date-time."""
957
+ createdAtTo: String
958
+ """Filter quotes expiring on or after this ISO 8601 date-time."""
959
+ expiresAtFrom: String
960
+ """Filter quotes expiring on or before this ISO 8601 date-time."""
961
+ expiresAtTo: String
962
+ """Filter quotes by label (partial match)."""
963
+ label: String
964
+ ): UserQuoteListResult @auth @cacheControl(scope: "private", sMaxAge: 300, staleWhileRevalidate: 3600)
944
965
  """Returns information about the current user details."""
945
966
  userDetails: StoreUserDetails! @auth @cacheControl(scope: "private", sMaxAge: 300, staleWhileRevalidate: 3600)
946
967
  """
@@ -949,6 +970,19 @@ type Query {
949
970
  accountProfile: StoreAccountProfile! @auth @cacheControl(scope: "private", sMaxAge: 300, staleWhileRevalidate: 3600)
950
971
  """Returns information about the user validation."""
951
972
  validateUser: ValidateUserData @auth @cacheControl(scope: "private", sMaxAge: 300, staleWhileRevalidate: 3600)
973
+ """
974
+ Lists the commercial contracts associated with the given Organization Unit,
975
+ resolved to human-readable corporate names. Governed: only contracts associated
976
+ with the authenticated buyer's Organization Unit are returned.
977
+ """
978
+ availableContracts(
979
+ """The Organization Unit identifier whose contracts will be listed."""
980
+ orgUnitId: String!
981
+ ): [StoreContract!]! @auth @cacheControl(scope: "private", sMaxAge: 0)
982
+ """
983
+ Returns whether the current authenticated user belongs to a B2B organization unit.
984
+ """
985
+ isOrganizationMember: Boolean! @auth @cacheControl(scope: "private", sMaxAge: 300, staleWhileRevalidate: 3600)
952
986
  """Returns a list of pickup points near to the given geo coordinates."""
953
987
  pickupPoints(
954
988
  """Geo coordinates input."""
@@ -958,6 +992,20 @@ type Query {
958
992
  orderEntryOperation(operationId: String!): StoreOrderEntryOperationStatus @auth
959
993
  """Returns the items in an orderForm by its ID."""
960
994
  orderFormItems(orderFormId: String!): [StoreOrderFormCartItem!]! @auth
995
+ """Returns personalized product recommendations for a given campaign."""
996
+ recommendations(campaignVrn: String!, userId: String, products: [String!]): RecommendationResponse! @cacheControl(scope: "private", sMaxAge: 120, staleWhileRevalidate: 3600)
997
+ }
998
+
999
+ type RecommendationCampaign {
1000
+ id: String!
1001
+ title: String
1002
+ type: String!
1003
+ }
1004
+
1005
+ type RecommendationResponse {
1006
+ products: [StoreProduct!]!
1007
+ correlationId: String!
1008
+ campaign: RecommendationCampaign!
961
1009
  }
962
1010
 
963
1011
  type SKUSpecificationField {
@@ -1278,6 +1326,22 @@ enum StoreCollectionType {
1278
1326
  Collection
1279
1327
  }
1280
1328
 
1329
+ """A commercial contract available to a buyer's Organization Unit."""
1330
+ type StoreContract {
1331
+ """
1332
+ Contract identifier (the contract/scope ID associated with the Organization Unit).
1333
+ """
1334
+ id: ID!
1335
+ """
1336
+ Human-readable corporate name of the contract (resolved from MasterData).
1337
+ """
1338
+ corporateName: String!
1339
+ """
1340
+ Indicates whether this contract is the one currently active in the session.
1341
+ """
1342
+ isActive: Boolean!
1343
+ }
1344
+
1281
1345
  """Currency information."""
1282
1346
  type StoreCurrency {
1283
1347
  """Currency code (e.g: USD)."""
@@ -2588,6 +2652,42 @@ type UserOrderTransactions {
2588
2652
  payments: [UserOrderPayments]
2589
2653
  }
2590
2654
 
2655
+ """Pagination metadata for the quotes list."""
2656
+ type UserQuoteListPaging {
2657
+ """Total number of quotes matching the query."""
2658
+ total: Int!
2659
+ """Current page number (1-based)."""
2660
+ currentPage: Int!
2661
+ """Number of items per page."""
2662
+ perPage: Int!
2663
+ }
2664
+
2665
+ """Result returned by the listUserQuotes query."""
2666
+ type UserQuoteListResult {
2667
+ """Array of quote summaries for the current page."""
2668
+ list: [UserQuoteSummary!]!
2669
+ """Pagination information."""
2670
+ paging: UserQuoteListPaging!
2671
+ }
2672
+
2673
+ """Summary of a quote returned in list results."""
2674
+ type UserQuoteSummary {
2675
+ """Unique identifier of the quote."""
2676
+ id: String!
2677
+ """Status of the quote."""
2678
+ status: String!
2679
+ """Optional label assigned to the quote."""
2680
+ label: String
2681
+ """ISO 8601 date-time when the quote was created."""
2682
+ createdAt: String!
2683
+ """ISO 8601 date-time when the quote expires."""
2684
+ expiresAt: String!
2685
+ """Total amount of the quote."""
2686
+ amount: Float!
2687
+ """Name or email of the user who created the quote."""
2688
+ createdBy: String
2689
+ }
2690
+
2591
2691
  type ValidateUserData {
2592
2692
  """Indicates if the user is valid."""
2593
2693
  isValid: Boolean!
package/CHANGELOG.md CHANGED
@@ -3,6 +3,32 @@
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.5.0-dev.1](https://github.com/vtex/faststore/compare/v4.5.0-dev.0...v4.5.0-dev.1) (2026-07-14)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **api:** add storeCookies option to fetchAPI for recommendations ([0e36d26](https://github.com/vtex/faststore/commit/0e36d269600ad9d219e8899ad58d6f81b18f70cb))
11
+ - **api:** expose recommendation and personalization operations ([961112a](https://github.com/vtex/faststore/commit/961112a8d2434e9fa961e7b6805850d90165d70f))
12
+ - **core:** add recommendation/personalization GraphQL typeDefs ([5f3999b](https://github.com/vtex/faststore/commit/5f3999b3a045d6ca7218cbc9eadee00021a4231c))
13
+ - **core:** harden RecommendationShelf per review feedback ([e369181](https://github.com/vtex/faststore/commit/e36918123b0f14d9628d7ef71238ac714c99a7fc))
14
+ - **ProductGallery:** cast context to PLPContext for SEO title retrieval ([c674edc](https://github.com/vtex/faststore/commit/c674edccb35fabd5432185a4b85290f8447b7af6))
15
+
16
+ ### Features
17
+
18
+ - **api, core:** implement server-side validation for recommendations and enable opt-in feature ([060d0a0](https://github.com/vtex/faststore/commit/060d0a0a151faa8494d1ae781f18baad5505b149))
19
+ - **api, core:** return StoreProduct from recommendations for consistent interface ([1ea6afa](https://github.com/vtex/faststore/commit/1ea6afacbc768c1395b3b46e735bac6a0cfed73e))
20
+ - **core:** add RecommendationShelf component for personalized product recommendations ([3214947](https://github.com/vtex/faststore/commit/3214947496a3ca28282af1b8a07a8f0567be01e2))
21
+ - **core:** add RecommendationShelf section with personalization tracking ([6c426a8](https://github.com/vtex/faststore/commit/6c426a80bd3e408eac989b00d4b10d45b74f2967))
22
+ - **core:** B2B contract switcher in the account drawer ([#3390](https://github.com/vtex/faststore/issues/3390)) ([380396a](https://github.com/vtex/faststore/commit/380396a7405f7bdb472b1219274d84807c61e153)), closes [#3354](https://github.com/vtex/faststore/issues/3354)
23
+ - **core:** enhance RecommendationShelf with configurable items context and carousel settings ([7b4e2d2](https://github.com/vtex/faststore/commit/7b4e2d274d8acb07b74f6a29c34e806eff311b1f))
24
+ - **core:** make RecommendationShelf carousel and product card configurable ([402816e](https://github.com/vtex/faststore/commit/402816e0dda8529ea081d9dcfd50626d889bf4f8))
25
+
26
+ # [4.5.0-dev.0](https://github.com/vtex/faststore/compare/v4.4.1-dev.0...v4.5.0-dev.0) (2026-07-03)
27
+
28
+ ### Features
29
+
30
+ - quotes list for B2B buyers in My Account ([#3388](https://github.com/vtex/faststore/issues/3388)) ([a6c1ef6](https://github.com/vtex/faststore/commit/a6c1ef6d13abd1f525832ccca9a5c0dc6a4b1a87)), closes [faststore-dx-spec-kit#13](https://github.com/faststore-dx-spec-kit/issues/13)
31
+
6
32
  ## [4.4.1-dev.0](https://github.com/vtex/faststore/compare/v4.4.0...v4.4.1-dev.0) (2026-07-02)
7
33
 
8
34
  **Note:** Version bump only for package @faststore/core
@@ -0,0 +1,86 @@
1
+ {
2
+ "$extends": ["#/$defs/base-component"],
3
+ "$componentKey": "RecommendationShelf",
4
+ "$componentTitle": "Recommendation Shelf",
5
+ "title": "Recommendation Shelf",
6
+ "description": "Display a carousel of personalized product recommendations from a VTEX Recommendations campaign.",
7
+ "type": "object",
8
+ "required": ["campaignVrn"],
9
+ "properties": {
10
+ "title": {
11
+ "title": "Title",
12
+ "description": "Override the shelf title. If not set, the campaign title will be used.",
13
+ "type": "string"
14
+ },
15
+ "campaignVrn": {
16
+ "title": "Campaign VRN",
17
+ "description": "Recommendation campaign VRN (e.g. vrn:recommendations:my-account:rec-persona-v2:abc123).",
18
+ "type": "string",
19
+ "pattern": "^vrn:recommendations:[^:]+:(rec-cross-v2|rec-similar-v2|rec-persona-v2|rec-last-v2|rec-top-items-v2|rec-search-v2|rec-next-v2|rec-visual-v2):[^:]+$"
20
+ },
21
+ "itemsContext": {
22
+ "title": "Items context",
23
+ "description": "Source of the products used as context for the recommendation request. 'Product page' uses the product currently being viewed; 'Cart' uses the items currently in the cart (useful for cross-sell shelves on the cart page). Only affects context-based campaigns such as cross-sell, similar items, visual similarity and next interaction.",
24
+ "type": "string",
25
+ "default": "PDP",
26
+ "enum": ["PDP", "CART"],
27
+ "enumNames": ["Product page", "Cart"]
28
+ },
29
+ "carouselConfiguration": {
30
+ "title": "Carousel Configuration",
31
+ "type": "object",
32
+ "properties": {
33
+ "itemsPerPageDesktop": {
34
+ "title": "Items per page (desktop)",
35
+ "description": "Number of products shown per page on desktop viewports.",
36
+ "type": "number",
37
+ "default": 4
38
+ },
39
+ "itemsPerPageMobile": {
40
+ "title": "Items per page (mobile)",
41
+ "description": "Number of products shown per page on mobile and tablet viewports.",
42
+ "type": "number",
43
+ "default": 2
44
+ },
45
+ "variant": {
46
+ "title": "Carousel track variant",
47
+ "description": "How the carousel navigates between items.",
48
+ "type": "string",
49
+ "default": "scroll",
50
+ "enum": ["slide", "scroll"],
51
+ "enumNames": ["Slide", "Scroll"]
52
+ },
53
+ "infiniteMode": {
54
+ "title": "Infinite navigation?",
55
+ "description": "Only applies to the 'slide' variant.",
56
+ "type": "boolean",
57
+ "default": false
58
+ },
59
+ "controls": {
60
+ "title": "Navigation controls",
61
+ "description": "Which navigation elements should be visible.",
62
+ "type": "string",
63
+ "default": "complete",
64
+ "enum": ["complete", "navigationArrows", "paginationBullets"],
65
+ "enumNames": ["Arrows and bullets", "Arrows only", "Bullets only"]
66
+ }
67
+ }
68
+ },
69
+ "productCardConfiguration": {
70
+ "title": "Product Card Configuration",
71
+ "type": "object",
72
+ "properties": {
73
+ "showDiscountBadge": {
74
+ "title": "Show discount badge?",
75
+ "type": "boolean",
76
+ "default": true
77
+ },
78
+ "bordered": {
79
+ "title": "Cards should be bordered?",
80
+ "type": "boolean",
81
+ "default": true
82
+ }
83
+ }
84
+ }
85
+ }
86
+ }