@envive-ai/react-hooks 0.3.4 → 0.3.5

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 (277) hide show
  1. package/dist/application/commerce-api.cjs +1 -1
  2. package/dist/application/commerce-api.js +1 -1
  3. package/dist/application/models/chatElementDisplayLocationV3.cjs +7 -1
  4. package/dist/application/models/chatElementDisplayLocationV3.d.cts +7 -1
  5. package/dist/application/models/chatElementDisplayLocationV3.d.ts +7 -1
  6. package/dist/application/models/chatElementDisplayLocationV3.js +7 -1
  7. package/dist/application/models/featureGates.cjs +6 -2
  8. package/dist/application/models/featureGates.d.cts +6 -2
  9. package/dist/application/models/featureGates.d.ts +6 -2
  10. package/dist/application/models/featureGates.js +6 -2
  11. package/dist/application/models/guards/api/isApiFormResponse.cjs +1 -1
  12. package/dist/application/models/guards/api/isApiFormResponse.js +1 -1
  13. package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.cjs +1 -1
  14. package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.js +1 -1
  15. package/dist/application/models/guards/api/isApiOrderResponseAttributes.cjs +1 -1
  16. package/dist/application/models/guards/api/isApiOrderResponseAttributes.js +1 -1
  17. package/dist/application/models/guards/api/isApiPDPEventAttributes.cjs +2 -2
  18. package/dist/application/models/guards/api/isApiPDPEventAttributes.js +2 -2
  19. package/dist/application/models/guards/api/isApiProductResponseAttributes.cjs +1 -1
  20. package/dist/application/models/guards/api/isApiProductResponseAttributes.js +1 -1
  21. package/dist/application/models/guards/api/isApiResponse.cjs +1 -1
  22. package/dist/application/models/guards/api/isApiResponse.js +1 -1
  23. package/dist/application/utils/analyticsUtils.cjs +1 -1
  24. package/dist/application/utils/analyticsUtils.js +1 -1
  25. package/dist/atoms/app/index.cjs +3 -1
  26. package/dist/atoms/app/index.d.cts +3 -3
  27. package/dist/atoms/app/index.d.ts +9 -9
  28. package/dist/atoms/app/index.js +3 -3
  29. package/dist/atoms/app/variant.cjs +2 -1
  30. package/dist/atoms/app/variant.d.cts +14 -6
  31. package/dist/atoms/app/variant.d.ts +17 -9
  32. package/dist/atoms/app/variant.js +2 -2
  33. package/dist/atoms/chat/chatState.d.cts +1 -1
  34. package/dist/atoms/chat/chatState.d.ts +18 -18
  35. package/dist/atoms/chat/form.d.cts +2 -2
  36. package/dist/atoms/chat/form.d.ts +2 -2
  37. package/dist/atoms/chat/index.d.cts +1 -1
  38. package/dist/atoms/chat/index.d.ts +3 -3
  39. package/dist/atoms/chat/lastMessage.d.cts +2 -2
  40. package/dist/atoms/chat/lastMessage.d.ts +2 -2
  41. package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
  42. package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
  43. package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
  44. package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
  45. package/dist/atoms/chat/replies.d.cts +1 -1
  46. package/dist/atoms/chat/replies.d.ts +3 -3
  47. package/dist/atoms/chat/suggestions.d.cts +2 -2
  48. package/dist/atoms/chat/suggestions.d.ts +2 -2
  49. package/dist/atoms/envive/enviveConfig.cjs +1 -11
  50. package/dist/atoms/envive/enviveConfig.js +1 -11
  51. package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
  52. package/dist/atoms/globalSearch/globalSearch.d.ts +5 -5
  53. package/dist/atoms/org/customerService.d.cts +6 -6
  54. package/dist/atoms/org/graphqlConfig.d.cts +4 -4
  55. package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
  56. package/dist/atoms/org/orgAnalyticsConfig.d.ts +5 -5
  57. package/dist/atoms/search/chatSearch.d.ts +17 -17
  58. package/dist/atoms/search/productRetrievalAPI.cjs +1 -7
  59. package/dist/atoms/search/productRetrievalAPI.js +1 -7
  60. package/dist/atoms/search/productRetrievalAdapter.cjs +4 -4
  61. package/dist/atoms/search/productRetrievalAdapter.js +4 -4
  62. package/dist/atoms/search/searchAPI.d.ts +13 -13
  63. package/dist/atoms/search/types.d.cts +1 -1
  64. package/dist/atoms/search/types.d.ts +1 -1
  65. package/dist/atoms/search/utils.d.cts +1 -1
  66. package/dist/atoms/search/utils.d.ts +1 -1
  67. package/dist/atoms/widget/chatPreviewLoading.d.cts +2 -2
  68. package/dist/contexts/enviveContext/enviveContext.cjs +14 -11
  69. package/dist/contexts/enviveContext/enviveContext.d.cts +2 -1
  70. package/dist/contexts/enviveContext/enviveContext.d.ts +2 -1
  71. package/dist/contexts/enviveContext/enviveContext.js +14 -11
  72. package/dist/contexts/enviveContext/types.d.ts +1 -1
  73. package/dist/contexts/featureFlagContext/featureFlagContext.cjs +1 -1
  74. package/dist/contexts/featureFlagContext/featureFlagContext.js +1 -1
  75. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.cjs +1 -1
  76. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.js +1 -1
  77. package/dist/contexts/graphqlContext/graphqlContext.cjs +87 -6
  78. package/dist/contexts/graphqlContext/graphqlContext.js +87 -6
  79. package/dist/contexts/graphqlContext/mockV3Config.cjs +56 -14
  80. package/dist/contexts/graphqlContext/mockV3Config.js +56 -14
  81. package/dist/contexts/hardcopyContext/hardcopyContext.cjs +33 -20
  82. package/dist/contexts/hardcopyContext/hardcopyContext.d.cts +2 -2
  83. package/dist/contexts/hardcopyContext/hardcopyContext.d.ts +2 -2
  84. package/dist/contexts/hardcopyContext/hardcopyContext.js +33 -20
  85. package/dist/contexts/pageContext/index.cjs +1 -0
  86. package/dist/contexts/pageContext/index.d.cts +2 -2
  87. package/dist/contexts/pageContext/index.d.ts +2 -2
  88. package/dist/contexts/pageContext/index.js +2 -2
  89. package/dist/contexts/pageContext/mapping.cjs +91 -1
  90. package/dist/contexts/pageContext/mapping.d.cts +5 -2
  91. package/dist/contexts/pageContext/mapping.d.ts +5 -2
  92. package/dist/contexts/pageContext/mapping.js +90 -2
  93. package/dist/contexts/pageContext/pageContext.cjs +33 -5
  94. package/dist/contexts/pageContext/pageContext.d.cts +2 -1
  95. package/dist/contexts/pageContext/pageContext.d.ts +2 -1
  96. package/dist/contexts/pageContext/pageContext.js +34 -6
  97. package/dist/contexts/pageContext/types.d.cts +2 -2
  98. package/dist/contexts/pageContext/types.d.ts +2 -2
  99. package/dist/contexts/salesAgentContext/chatAPI.cjs +4 -1
  100. package/dist/contexts/salesAgentContext/chatAPI.d.cts +4 -1
  101. package/dist/contexts/salesAgentContext/chatAPI.d.ts +4 -1
  102. package/dist/contexts/salesAgentContext/chatAPI.js +4 -1
  103. package/dist/contexts/salesAgentContext/index.d.cts +2 -2
  104. package/dist/contexts/salesAgentContext/index.d.ts +2 -2
  105. package/dist/contexts/salesAgentContext/salesAgentContext.cjs +4 -2
  106. package/dist/contexts/salesAgentContext/salesAgentContext.d.cts +2 -2
  107. package/dist/contexts/salesAgentContext/salesAgentContext.d.ts +2 -2
  108. package/dist/contexts/salesAgentContext/salesAgentContext.js +4 -2
  109. package/dist/contexts/salesAgentContext/salesAgentService.cjs +7 -4
  110. package/dist/contexts/salesAgentContext/salesAgentService.js +8 -5
  111. package/dist/contexts/systemSettingsContext/systemSettingsContext.d.cts +2 -2
  112. package/dist/contexts/types.d.cts +1 -1
  113. package/dist/contexts/types.d.ts +1 -1
  114. package/dist/contexts/typesV3.cjs +20 -17
  115. package/dist/contexts/typesV3.d.cts +39 -12
  116. package/dist/contexts/typesV3.d.ts +39 -12
  117. package/dist/contexts/typesV3.js +5 -2
  118. package/dist/hooks/ChatToggle/useChatToggle.cjs +1 -1
  119. package/dist/hooks/ChatToggle/useChatToggle.d.cts +5 -5
  120. package/dist/hooks/ChatToggle/useChatToggle.d.ts +5 -5
  121. package/dist/hooks/ChatToggle/useChatToggle.js +1 -1
  122. package/dist/hooks/ElementObserver/useElementObserver.cjs +10 -10
  123. package/dist/hooks/ElementObserver/useElementObserver.js +10 -10
  124. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.cts +2 -2
  125. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.ts +2 -2
  126. package/dist/hooks/Search/useSearch.cjs +1 -1
  127. package/dist/hooks/Search/useSearch.js +1 -1
  128. package/dist/hooks/utils.d.cts +1 -1
  129. package/dist/merchants/domInsertion.cjs +1 -1
  130. package/dist/merchants/domInsertion.d.cts +1 -1
  131. package/dist/merchants/domInsertion.d.ts +1 -1
  132. package/dist/merchants/domInsertion.js +1 -1
  133. package/dist/packages/components-v3/dist/ChatHeader/ChatHeader.cjs +2 -0
  134. package/dist/packages/components-v3/dist/ChatHeader/ChatHeader.js +4 -0
  135. package/dist/packages/components-v3/dist/ChatHeader/components/CloseButton.cjs +16 -0
  136. package/dist/packages/components-v3/dist/ChatHeader/components/CloseButton.js +17 -0
  137. package/dist/packages/components-v3/dist/ChatHeader/components/Handle.cjs +6 -0
  138. package/dist/packages/components-v3/dist/ChatHeader/components/Handle.js +8 -0
  139. package/dist/packages/components-v3/dist/ChatHeader/components/Layout.cjs +4 -0
  140. package/dist/packages/components-v3/dist/ChatHeader/components/Layout.js +6 -0
  141. package/dist/packages/components-v3/dist/ChatHeader/components/Logo.cjs +3 -0
  142. package/dist/packages/components-v3/dist/ChatHeader/components/Logo.js +5 -0
  143. package/dist/packages/components-v3/dist/ChatHeader/components/Toggle.cjs +7 -0
  144. package/dist/packages/components-v3/dist/ChatHeader/components/Toggle.js +9 -0
  145. package/dist/packages/components-v3/dist/ChatHeader/components/ToggleItem.cjs +6 -0
  146. package/dist/packages/components-v3/dist/ChatHeader/components/ToggleItem.js +8 -0
  147. package/dist/packages/components-v3/dist/ChatHeader/components/index.cjs +6 -0
  148. package/dist/packages/components-v3/dist/ChatHeader/components/index.js +8 -0
  149. package/dist/packages/components-v3/dist/ChatHeader/hooks/useGetCloseButtonProperties.cjs +22 -0
  150. package/dist/packages/components-v3/dist/ChatHeader/hooks/useGetCloseButtonProperties.js +23 -0
  151. package/dist/packages/components-v3/dist/ChatHeader/hooks/useGetHandleProperties.cjs +58 -0
  152. package/dist/packages/components-v3/dist/ChatHeader/hooks/useGetHandleProperties.js +59 -0
  153. package/dist/packages/components-v3/dist/ChatHeader/hooks/useGetLayoutProperties.cjs +8 -0
  154. package/dist/packages/components-v3/dist/ChatHeader/hooks/useGetLayoutProperties.js +9 -0
  155. package/dist/packages/components-v3/dist/ChatHeader/hooks/useGetToggleOptionProperties.cjs +1 -0
  156. package/dist/packages/components-v3/dist/ChatHeader/hooks/useGetToggleOptionProperties.js +3 -0
  157. package/dist/packages/components-v3/dist/ChatHeader/hooks/useGetToggleProperties.cjs +12 -0
  158. package/dist/packages/components-v3/dist/ChatHeader/hooks/useGetToggleProperties.js +13 -0
  159. package/dist/packages/components-v3/dist/ChatHeader/index.cjs +2 -0
  160. package/dist/packages/components-v3/dist/ChatHeader/index.js +4 -0
  161. package/dist/packages/components-v3/dist/ChatHeader/types/index.cjs +11 -0
  162. package/dist/packages/components-v3/dist/ChatHeader/types/index.js +10 -0
  163. package/dist/packages/components-v3/dist/ImageGallery/components/Layout.cjs +2 -2
  164. package/dist/packages/components-v3/dist/ImageGallery/components/Layout.js +2 -2
  165. package/dist/packages/components-v3/dist/PromptButton/PromptButton.cjs +1 -1
  166. package/dist/packages/components-v3/dist/PromptButton/PromptButton.js +1 -1
  167. package/dist/packages/components-v3/dist/PromptButton/components/Layout.cjs +1 -1
  168. package/dist/packages/components-v3/dist/PromptButton/components/Layout.js +1 -1
  169. package/dist/packages/components-v3/dist/PromptButton/hooks/useGetLayoutBaseProperties.cjs +1 -1
  170. package/dist/packages/components-v3/dist/PromptButton/hooks/useGetLayoutBaseProperties.js +1 -1
  171. package/dist/packages/components-v3/dist/Tokens/index.cjs +11 -0
  172. package/dist/packages/components-v3/dist/Tokens/index.js +13 -0
  173. package/dist/packages/components-v3/dist/WelcomeMessage/WelcomeMessage.cjs +2 -0
  174. package/dist/packages/components-v3/dist/WelcomeMessage/WelcomeMessage.js +4 -0
  175. package/dist/packages/components-v3/dist/WelcomeMessage/components/Container.cjs +14 -0
  176. package/dist/packages/components-v3/dist/WelcomeMessage/components/Container.js +15 -0
  177. package/dist/packages/components-v3/dist/WelcomeMessage/components/SparkleIcon.cjs +3 -0
  178. package/dist/packages/components-v3/dist/WelcomeMessage/components/SparkleIcon.js +5 -0
  179. package/dist/packages/components-v3/dist/WelcomeMessage/components/Text.cjs +3 -0
  180. package/dist/packages/components-v3/dist/WelcomeMessage/components/Text.js +5 -0
  181. package/dist/packages/components-v3/dist/WelcomeMessage/components/Title.cjs +3 -0
  182. package/dist/packages/components-v3/dist/WelcomeMessage/components/Title.js +5 -0
  183. package/dist/packages/components-v3/dist/WelcomeMessage/components/index.cjs +4 -0
  184. package/dist/packages/components-v3/dist/WelcomeMessage/components/index.js +6 -0
  185. package/dist/packages/components-v3/dist/WelcomeMessage/hooks/useGetContainerProperties.cjs +1 -0
  186. package/dist/packages/components-v3/dist/WelcomeMessage/hooks/useGetContainerProperties.js +3 -0
  187. package/dist/packages/components-v3/dist/WelcomeMessage/hooks/useGetSparkleIconProperties.cjs +1 -0
  188. package/dist/packages/components-v3/dist/WelcomeMessage/hooks/useGetSparkleIconProperties.js +3 -0
  189. package/dist/packages/components-v3/dist/WelcomeMessage/index.cjs +2 -0
  190. package/dist/packages/components-v3/dist/WelcomeMessage/index.js +4 -0
  191. package/dist/packages/components-v3/dist/WelcomeMessage/types/types.cjs +14 -0
  192. package/dist/packages/components-v3/dist/WelcomeMessage/types/types.js +14 -0
  193. package/dist/packages/components-v3/dist/src/models/colorsConfig.cjs +26 -0
  194. package/dist/packages/components-v3/dist/src/models/colorsConfig.js +25 -0
  195. package/dist/packages/components-v3/dist/tokens/aspectRatio/aspectRatio.cjs +16 -0
  196. package/dist/packages/components-v3/dist/tokens/aspectRatio/aspectRatio.js +17 -0
  197. package/dist/packages/components-v3/dist/tokens/breakpoints/breakpoints.cjs +25 -0
  198. package/dist/packages/components-v3/dist/tokens/breakpoints/breakpoints.js +23 -0
  199. package/dist/packages/components-v3/dist/tokens/colors/colors.cjs +51 -0
  200. package/dist/packages/components-v3/dist/tokens/colors/colors.js +51 -0
  201. package/dist/packages/components-v3/dist/tokens/radius/radius.cjs +64 -0
  202. package/dist/packages/components-v3/dist/tokens/radius/radius.js +65 -0
  203. package/dist/packages/components-v3/dist/tokens/theme/theme.cjs +13 -0
  204. package/dist/packages/components-v3/dist/tokens/theme/theme.js +12 -0
  205. package/dist/packages/components-v3/dist/tokens/typography/fontFamily.cjs +25 -0
  206. package/dist/packages/components-v3/dist/tokens/typography/fontFamily.js +25 -0
  207. package/dist/packages/components-v3/dist/tokens/typography/fontSize.cjs +37 -0
  208. package/dist/packages/components-v3/dist/tokens/typography/fontSize.js +38 -0
  209. package/dist/packages/components-v3/dist/tokens/typography/fontWeight.cjs +17 -0
  210. package/dist/packages/components-v3/dist/tokens/typography/fontWeight.js +18 -0
  211. package/dist/packages/components-v3/dist/tokens/typography/letterSpacing.cjs +15 -0
  212. package/dist/packages/components-v3/dist/tokens/typography/letterSpacing.js +16 -0
  213. package/dist/packages/components-v3/dist/tokens/typography/lineHeight.cjs +31 -0
  214. package/dist/packages/components-v3/dist/tokens/typography/lineHeight.js +32 -0
  215. package/dist/packages/components-v3/dist/tokens/typography/typography.cjs +5 -0
  216. package/dist/packages/components-v3/dist/tokens/typography/typography.js +7 -0
  217. package/dist/packages/components-v3/dist/tokens/utils.cjs +7 -0
  218. package/dist/packages/components-v3/dist/tokens/utils.js +6 -0
  219. package/dist/packages/components-v3/dist/utils/useResponsiveValue.cjs +2 -2
  220. package/dist/packages/components-v3/dist/utils/useResponsiveValue.js +2 -2
  221. package/dist/packages/icons/dist/IconCloseRounded.cjs +22 -0
  222. package/dist/packages/icons/dist/IconCloseRounded.js +22 -0
  223. package/dist/packages/icons/dist/IconCloseSharp.cjs +31 -0
  224. package/dist/packages/icons/dist/IconCloseSharp.js +31 -0
  225. package/dist/packages/icons/dist/IconCloseTransparent.cjs +24 -0
  226. package/dist/packages/icons/dist/IconCloseTransparent.js +24 -0
  227. package/dist/packages/icons/dist/Sparkles.cjs +8 -0
  228. package/dist/packages/icons/dist/Sparkles.js +9 -0
  229. package/dist/types/customerService.cjs +20 -0
  230. package/dist/types/customerService.js +19 -0
  231. package/package.json +1 -5
  232. package/src/application/models/chatElementDisplayLocationV3.ts +6 -0
  233. package/src/application/models/featureGates.ts +6 -1
  234. package/src/application/models/guards/api/isApiPDPEventAttributes.ts +5 -1
  235. package/src/atoms/app/index.ts +7 -1
  236. package/src/atoms/app/variant.ts +3 -2
  237. package/src/atoms/envive/enviveConfig.ts +0 -11
  238. package/src/atoms/search/productRetrievalAPI.ts +0 -8
  239. package/src/atoms/search/productRetrievalAdapter.ts +6 -10
  240. package/src/contexts/amplitudeContext/__tests__/amplitudeContext.test.tsx +0 -1
  241. package/src/contexts/enviveContext/enviveContext.tsx +5 -3
  242. package/src/contexts/graphqlContext/graphqlContext.tsx +128 -9
  243. package/src/contexts/graphqlContext/mockV3Config.ts +53 -12
  244. package/src/contexts/hardcopyContext/hardcopyContext.tsx +29 -13
  245. package/src/contexts/pageContext/__tests__/pageContext.test.tsx +119 -69
  246. package/src/contexts/pageContext/mapping.ts +184 -2
  247. package/src/contexts/pageContext/pageContext.tsx +30 -5
  248. package/src/contexts/pageContext/types.ts +1 -2
  249. package/src/contexts/salesAgentContext/chatAPI.ts +9 -0
  250. package/src/contexts/salesAgentContext/salesAgentContext.tsx +10 -3
  251. package/src/contexts/salesAgentContext/salesAgentService.ts +13 -1
  252. package/src/contexts/typesV3.ts +52 -20
  253. package/src/contexts/uiConfigContext/__tests__/uiConfigContext.test.tsx +14 -6
  254. package/src/contexts/widgetConfigContext/__tests__/widgetConfigContext.test.tsx +1 -1
  255. package/src/hooks/ChatToggle/useChatToggle.ts +4 -4
  256. package/src/hooks/ElementObserver/useElementObserver.ts +9 -9
  257. package/src/merchants/domInsertion.ts +0 -16
  258. package/dist/hooks/ChatToggleAnalytics/index.cjs +0 -3
  259. package/dist/hooks/ChatToggleAnalytics/index.d.cts +0 -2
  260. package/dist/hooks/ChatToggleAnalytics/index.d.ts +0 -2
  261. package/dist/hooks/ChatToggleAnalytics/index.js +0 -3
  262. package/dist/hooks/ChatToggleAnalytics/useChatToggleAnalytics.cjs +0 -19
  263. package/dist/hooks/ChatToggleAnalytics/useChatToggleAnalytics.d.cts +0 -9
  264. package/dist/hooks/ChatToggleAnalytics/useChatToggleAnalytics.d.ts +0 -9
  265. package/dist/hooks/ChatToggleAnalytics/useChatToggleAnalytics.js +0 -18
  266. package/dist/packages/components-v3/dist/packages/components-v3/tokens/breakpoints/breakpoints.cjs +0 -25
  267. package/dist/packages/components-v3/dist/packages/components-v3/tokens/breakpoints/breakpoints.js +0 -23
  268. package/src/application/utils/cdnUtils.ts +0 -8
  269. package/src/config/divIds.ts +0 -31
  270. package/src/config/locators/components/chat/entrypoints.ts +0 -13
  271. package/src/config/locators/components/chat/preview.ts +0 -12
  272. package/src/config/locators/components/report-issue.ts +0 -21
  273. package/src/config/socialProofClasses.ts +0 -12
  274. package/src/events/registerAnalyticsListeners.ts +0 -44
  275. package/src/hooks/ChatToggleAnalytics/index.ts +0 -1
  276. package/src/hooks/ChatToggleAnalytics/useChatToggleAnalytics.ts +0 -15
  277. package/src/types/FilterAttribute.ts +0 -32
@@ -1,11 +1,16 @@
1
- import { PageVisitCategory, UserEvent } from '@spiffy-ai/commerce-api-client';
1
+ import { PageVisitCategory, UserEventCategory } from '@spiffy-ai/commerce-api-client';
2
2
  import { act, render, screen, waitFor } from '@testing-library/react';
3
3
  import { Provider, useAtom } from 'jotai';
4
4
  import React from 'react';
5
5
  import CommerceApiClient from 'src/application/commerce-api';
6
6
  import Logger from 'src/application/logging/logger';
7
7
  import { VariantTypeEnum } from 'src/application/models';
8
- import { UrlResolverResponse, urlResolverAtom } from 'src/atoms/app/variant';
8
+ import {
9
+ UrlResolverResponse,
10
+ pageUserEventAtom,
11
+ pageVariantInfoAtom,
12
+ urlResolverAtom,
13
+ } from 'src/atoms/app/variant';
9
14
  import { mapUrlResolverResponseToVariantInfo } from '../mapping';
10
15
  import { PageProvider, usePage } from '../pageContext';
11
16
 
@@ -35,6 +40,7 @@ const MockComponent: React.FC = () => {
35
40
  <div data-testid="user-event">
36
41
  {context.userEvent ? JSON.stringify(context.userEvent) : 'undefined'}
37
42
  </div>
43
+ <div data-testid="is-loading">{context.isLoading ? 'true' : 'false'}</div>
38
44
  </div>
39
45
  );
40
46
  };
@@ -69,10 +75,10 @@ describe('PageProvider', () => {
69
75
  window.location = originalLocation;
70
76
  });
71
77
 
72
- const renderWithProviders = (children: React.ReactNode) => {
78
+ const renderWithProviders = (children: React.ReactNode, previewMode = false) => {
73
79
  return render(
74
80
  <Provider>
75
- <PageProvider>{children}</PageProvider>
81
+ <PageProvider previewMode={previewMode}>{children}</PageProvider>
76
82
  </Provider>,
77
83
  );
78
84
  };
@@ -89,9 +95,6 @@ describe('PageProvider', () => {
89
95
  });
90
96
 
91
97
  it('should handle missing window.location gracefully', async () => {
92
- // This test verifies that the component handles edge cases
93
- // In a real browser environment, window.location is always available
94
- // This test ensures the component doesn't crash in unusual test scenarios
95
98
  const originalLocation = window.location;
96
99
 
97
100
  // Temporarily remove location
@@ -108,7 +111,91 @@ describe('PageProvider', () => {
108
111
  });
109
112
  });
110
113
 
111
- describe('URL Resolution', () => {
114
+ describe('Preview Mode', () => {
115
+ it('should auto-initialize atoms when previewMode is true', async () => {
116
+ window.location.href = 'https://example.com/preview-page';
117
+
118
+ renderWithProviders(<MockComponent />, true);
119
+
120
+ await waitFor(() => {
121
+ const userEvent = screen.getByTestId('user-event').textContent;
122
+ expect(userEvent).toContain('preview-user-event');
123
+ expect(userEvent).toContain(UserEventCategory.PageVisit);
124
+ expect(userEvent).toContain(PageVisitCategory.Other);
125
+ });
126
+
127
+ await waitFor(() => {
128
+ const variantInfo = screen.getByTestId('variant-info').textContent;
129
+ expect(variantInfo).toContain(VariantTypeEnum.PageVisit);
130
+ expect(variantInfo).toContain('https://example.com/preview-page');
131
+ });
132
+ });
133
+
134
+ it('should skip API call when previewMode is true', async () => {
135
+ window.location.href = 'https://example.com/preview-test';
136
+
137
+ renderWithProviders(<MockComponent />, true);
138
+
139
+ // Wait for initialization
140
+ await waitFor(() => {
141
+ expect(screen.getByTestId('user-event').textContent).not.toBe('undefined');
142
+ });
143
+
144
+ // Should not call resolveUrl when in preview mode
145
+ expect(mockResolveUrl).not.toHaveBeenCalled();
146
+ });
147
+
148
+ it('should not overwrite existing atoms in preview mode', async () => {
149
+ window.location.href = 'https://example.com/existing-atoms';
150
+ // Set up existing atoms before preview mode
151
+ const TestWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
152
+ const [, setUserEvent] = useAtom(pageUserEventAtom);
153
+ const [, setVariantInfo] = useAtom(pageVariantInfoAtom);
154
+ React.useEffect(() => {
155
+ setUserEvent({
156
+ event_id: 'existing-event',
157
+ created_at: new Date().toISOString(),
158
+ category: UserEventCategory.PageVisit,
159
+ attributes: {
160
+ page_visit_category: PageVisitCategory.Other,
161
+ url: 'https://example.com/existing',
162
+ },
163
+ } as any);
164
+ setVariantInfo({
165
+ variantType: VariantTypeEnum.Pdp,
166
+ productId: 'existing-product',
167
+ url: 'https://example.com/existing',
168
+ } as any);
169
+ }, [setUserEvent, setVariantInfo]);
170
+ return <PageProvider previewMode>{children}</PageProvider>;
171
+ };
172
+ render(
173
+ <Provider>
174
+ <TestWrapper>
175
+ <MockComponent />
176
+ </TestWrapper>
177
+ </Provider>,
178
+ );
179
+ // Should keep existing atoms, not overwrite with preview values
180
+ await waitFor(() => {
181
+ const userEvent = screen.getByTestId('user-event').textContent;
182
+ expect(userEvent).toContain('existing-event');
183
+ expect(userEvent).not.toContain('preview-user-event');
184
+ });
185
+ });
186
+
187
+ it('should set isLoading to false in preview mode', async () => {
188
+ window.location.href = 'https://example.com/loading-test';
189
+
190
+ renderWithProviders(<MockComponent />, true);
191
+
192
+ await waitFor(() => {
193
+ expect(screen.getByTestId('is-loading').textContent).toBe('false');
194
+ });
195
+ });
196
+ });
197
+
198
+ describe('URL Resolution (Non-Preview Mode)', () => {
112
199
  it('should call CommerceApiClient.resolveUrl when pageUrl is set', async () => {
113
200
  const mockResponse: UrlResolverResponse = {
114
201
  variant_type: VariantTypeEnum.PageVisit,
@@ -120,7 +207,7 @@ describe('PageProvider', () => {
120
207
 
121
208
  window.location.href = 'https://example.com/test';
122
209
 
123
- renderWithProviders(<MockComponent />);
210
+ renderWithProviders(<MockComponent />, false);
124
211
 
125
212
  await waitFor(() => {
126
213
  expect(mockResolveUrl).toHaveBeenCalledWith('https://example.com/test');
@@ -138,7 +225,7 @@ describe('PageProvider', () => {
138
225
 
139
226
  window.location.href = ' HTTPS://EXAMPLE.COM/TEST ';
140
227
 
141
- renderWithProviders(<MockComponent />);
228
+ renderWithProviders(<MockComponent />, false);
142
229
 
143
230
  await waitFor(() => {
144
231
  expect(mockResolveUrl).toHaveBeenCalledWith('https://example.com/test');
@@ -169,7 +256,7 @@ describe('PageProvider', () => {
169
256
  });
170
257
  }, [setUrlResolver]);
171
258
 
172
- return <PageProvider>{children}</PageProvider>;
259
+ return <PageProvider previewMode={false}>{children}</PageProvider>;
173
260
  };
174
261
 
175
262
  render(
@@ -197,7 +284,7 @@ describe('PageProvider', () => {
197
284
  // Test with an empty URL string
198
285
  window.location.href = '';
199
286
 
200
- renderWithProviders(<MockComponent />);
287
+ renderWithProviders(<MockComponent />, false);
201
288
 
202
289
  // Wait for initial render
203
290
  await waitFor(() => {
@@ -205,7 +292,6 @@ describe('PageProvider', () => {
205
292
  });
206
293
 
207
294
  // Empty string is falsy, so resolveUrl should not be called
208
- // The component checks `if (!pageUrl)` which treats empty string as falsy
209
295
  await act(async () => {
210
296
  await new Promise<void>(resolve => {
211
297
  setTimeout(resolve, 100);
@@ -231,7 +317,7 @@ describe('PageProvider', () => {
231
317
  mockResolveUrl.mockResolvedValue(mockResponse);
232
318
  window.location.href = 'https://example.com/product';
233
319
 
234
- renderWithProviders(<MockComponent />);
320
+ renderWithProviders(<MockComponent />, false);
235
321
 
236
322
  await waitFor(() => {
237
323
  const variantInfo = screen.getByTestId('variant-info').textContent;
@@ -257,7 +343,7 @@ describe('PageProvider', () => {
257
343
  mockResolveUrl.mockResolvedValue(mockResponse);
258
344
  window.location.href = 'https://example.com/category';
259
345
 
260
- renderWithProviders(<MockComponent />);
346
+ renderWithProviders(<MockComponent />, false);
261
347
 
262
348
  await waitFor(() => {
263
349
  const variantInfo = screen.getByTestId('variant-info').textContent;
@@ -277,7 +363,7 @@ describe('PageProvider', () => {
277
363
  mockResolveUrl.mockResolvedValue(mockResponse);
278
364
  window.location.href = 'https://example.com/page';
279
365
 
280
- renderWithProviders(<MockComponent />);
366
+ renderWithProviders(<MockComponent />, false);
281
367
 
282
368
  await waitFor(() => {
283
369
  const variantInfo = screen.getByTestId('variant-info').textContent;
@@ -298,7 +384,7 @@ describe('PageProvider', () => {
298
384
  mockResolveUrl.mockResolvedValue(mockResponse);
299
385
  window.location.href = 'https://example.com/product';
300
386
 
301
- renderWithProviders(<MockComponent />);
387
+ renderWithProviders(<MockComponent />, false);
302
388
 
303
389
  await waitFor(() => {
304
390
  const variantInfo = screen.getByTestId('variant-info').textContent;
@@ -319,7 +405,7 @@ describe('PageProvider', () => {
319
405
  mockResolveUrl.mockResolvedValue(mockResponse);
320
406
  window.location.href = 'https://example.com/category';
321
407
 
322
- renderWithProviders(<MockComponent />);
408
+ renderWithProviders(<MockComponent />, false);
323
409
 
324
410
  await waitFor(() => {
325
411
  const variantInfo = screen.getByTestId('variant-info').textContent;
@@ -334,7 +420,13 @@ describe('PageProvider', () => {
334
420
  const mockUserEvent = {
335
421
  event_id: 'event-123',
336
422
  event_type: PageVisitCategory.Other,
337
- } as unknown as UserEvent;
423
+ created_at: new Date().toISOString(),
424
+ category: UserEventCategory.PageVisit,
425
+ attributes: {
426
+ url: 'https://example.com/page',
427
+ page_visit_category: PageVisitCategory.Other,
428
+ },
429
+ };
338
430
 
339
431
  const mockResponse: UrlResolverResponse = {
340
432
  variant_type: VariantTypeEnum.PageVisit,
@@ -346,7 +438,7 @@ describe('PageProvider', () => {
346
438
  mockResolveUrl.mockResolvedValue(mockResponse);
347
439
  window.location.href = 'https://example.com/page';
348
440
 
349
- renderWithProviders(<MockComponent />);
441
+ renderWithProviders(<MockComponent />, false);
350
442
 
351
443
  await waitFor(() => {
352
444
  const userEvent = screen.getByTestId('user-event').textContent;
@@ -365,7 +457,7 @@ describe('PageProvider', () => {
365
457
  mockResolveUrl.mockResolvedValue(mockResponse);
366
458
  window.location.href = 'https://example.com/page';
367
459
 
368
- renderWithProviders(<MockComponent />);
460
+ renderWithProviders(<MockComponent />, false);
369
461
 
370
462
  await waitFor(() => {
371
463
  const userEvent = screen.getByTestId('user-event').textContent;
@@ -382,7 +474,7 @@ describe('PageProvider', () => {
382
474
 
383
475
  window.location.href = 'https://example.com/error-page';
384
476
 
385
- renderWithProviders(<MockComponent />);
477
+ renderWithProviders(<MockComponent />, false);
386
478
 
387
479
  await waitFor(() => {
388
480
  expect(errorSpy).toHaveBeenCalledWith('Failed to resolve page URL', error, {
@@ -395,8 +487,6 @@ describe('PageProvider', () => {
395
487
  });
396
488
 
397
489
  it('should handle invalid variant type gracefully', async () => {
398
- // This test verifies that the mapping function throws an error for invalid types
399
- // The error should be caught and logged
400
490
  const errorSpy = vi.spyOn(Logger, 'logError');
401
491
 
402
492
  const invalidResponse = {
@@ -408,7 +498,7 @@ describe('PageProvider', () => {
408
498
  mockResolveUrl.mockResolvedValue(invalidResponse);
409
499
  window.location.href = 'https://example.com/invalid';
410
500
 
411
- renderWithProviders(<MockComponent />);
501
+ renderWithProviders(<MockComponent />, false);
412
502
 
413
503
  // The mapping function should throw, which will be caught in the useEffect
414
504
  await waitFor(() => {
@@ -443,48 +533,13 @@ describe('PageProvider', () => {
443
533
  mockResolveUrl.mockResolvedValue(mockResponse);
444
534
  window.location.href = 'https://example.com/test';
445
535
 
446
- renderWithProviders(<MockComponent />);
536
+ renderWithProviders(<MockComponent />, false);
447
537
 
448
538
  await waitFor(() => {
449
539
  expect(screen.getByTestId('page-url').textContent).toBe('https://example.com/test');
450
540
  expect(screen.getByTestId('variant-info').textContent).not.toBe('undefined');
451
541
  });
452
542
  });
453
-
454
- it('should update context when pageUrl changes', async () => {
455
- const mockResponse1: UrlResolverResponse = {
456
- variant_type: VariantTypeEnum.PageVisit,
457
- specific_details: {},
458
- ready: true,
459
- };
460
-
461
- const mockResponse2: UrlResolverResponse = {
462
- variant_type: VariantTypeEnum.Pdp,
463
- specific_details: {
464
- pdp_attributes: {
465
- product_id: 'product-789',
466
- },
467
- },
468
- ready: true,
469
- };
470
-
471
- mockResolveUrl.mockResolvedValueOnce(mockResponse1).mockResolvedValueOnce(mockResponse2);
472
-
473
- window.location.href = 'https://example.com/page1';
474
-
475
- const { rerender } = renderWithProviders(<MockComponent />);
476
-
477
- await waitFor(() => {
478
- expect(screen.getByTestId('page-url').textContent).toBe('https://example.com/page1');
479
- });
480
-
481
- // Change the URL
482
- window.location.href = 'https://example.com/page2';
483
-
484
- // Note: In a real SPA, the URL change would trigger the useEffect
485
- // For testing, we need to manually trigger or test the effect differently
486
- // This test demonstrates the expected behavior
487
- });
488
543
  });
489
544
 
490
545
  describe('Context Value Memoization', () => {
@@ -505,7 +560,7 @@ describe('PageProvider', () => {
505
560
  return <div data-testid="count">{renderCount}</div>;
506
561
  };
507
562
 
508
- renderWithProviders(<CountingComponent />);
563
+ renderWithProviders(<CountingComponent />, false);
509
564
 
510
565
  await waitFor(() => {
511
566
  expect(screen.getByTestId('count')).toBeInTheDocument();
@@ -521,8 +576,7 @@ describe('PageProvider', () => {
521
576
  });
522
577
  });
523
578
 
524
- // The context value should be memoized, so additional renders
525
- // should be minimal (only from initial setup)
579
+ // The context value should be memoized
526
580
  expect(renderCount).toBeGreaterThanOrEqual(initialCount);
527
581
  });
528
582
  });
@@ -544,7 +598,7 @@ describe('PageProvider', () => {
544
598
 
545
599
  render(
546
600
  <Provider>
547
- <PageProvider>
601
+ <PageProvider previewMode={false}>
548
602
  <MockComponent />
549
603
  <AtomReaderComponent />
550
604
  </PageProvider>
@@ -554,10 +608,6 @@ describe('PageProvider', () => {
554
608
  await waitFor(() => {
555
609
  expect(mockResolveUrl).toHaveBeenCalled();
556
610
  });
557
-
558
- // The atom should eventually contain the cached response
559
- // Note: The actual caching happens in the atom setter, which may
560
- // require additional setup to test directly
561
611
  });
562
612
  });
563
613
  });
@@ -1,6 +1,19 @@
1
1
  import { UrlResolverResponse } from 'src/atoms/app/variant';
2
-
3
- import { VariantTypeEnum } from 'src/application/models';
2
+ import {
3
+ UserEvent as ApiUserEvent,
4
+ PageVisitCategory,
5
+ UserEventCategory,
6
+ } from '@spiffy-ai/commerce-api-client';
7
+ import { UserEvent, VariantTypeEnum } from 'src/application/models';
8
+ import { isApiPDPAttributes } from 'src/application/models/guards/api/isApiPDPEventAttributes';
9
+ import {
10
+ isApiPLPEventAttributes,
11
+ isApiPLPIdAttribute,
12
+ } from 'src/application/models/guards/api/isApiPLPEventAttributes';
13
+ import { isApiQueryTypedAttributes } from 'src/application/models/guards/api/isApiQueryTypedEventAttributes';
14
+ import { isApiSearchAttributes } from 'src/application/models/guards/api/isApiSearchEventAttributes';
15
+ import { isApiSuggestionClickedAttributes } from 'src/application/models/guards/api/isApiSuggestionClickedEventAttributes';
16
+ import { isApiFormSubmittedResponseAttributes } from 'src/application/models/guards/api/isApiFormSubmittedResponseAttributes';
4
17
 
5
18
  import { PageVariantInfo, VisitPageVariantInfo } from './types';
6
19
 
@@ -40,3 +53,172 @@ export const mapUrlResolverResponseToVariantInfo = (
40
53
  }
41
54
  throw new Error('Invalid variant type');
42
55
  };
56
+
57
+ const isApiPageVisitAttributes = (
58
+ data: unknown,
59
+ ): data is { url: string; page_visit_category: PageVisitCategory } => {
60
+ if (data == null || typeof data !== 'object') {
61
+ return false;
62
+ }
63
+
64
+ if (!('url' in data) || typeof data.url !== 'string') {
65
+ return false;
66
+ }
67
+
68
+ if (
69
+ !('page_visit_category' in data) ||
70
+ typeof data.page_visit_category !== 'string' ||
71
+ !Object.values(PageVisitCategory).includes(data.page_visit_category as PageVisitCategory)
72
+ ) {
73
+ return false;
74
+ }
75
+
76
+ return true;
77
+ };
78
+
79
+ export const mapApiUserEventToUserEvent = (
80
+ userEvent: ApiUserEvent | undefined,
81
+ ): UserEvent | undefined => {
82
+ if (!userEvent) {
83
+ return undefined;
84
+ }
85
+ // Handle PdpVisit and AddToCart (they share the same attributes structure)
86
+ if (
87
+ (userEvent.category === UserEventCategory.PdpVisit ||
88
+ userEvent.category === UserEventCategory.AddToCart) &&
89
+ isApiPDPAttributes(userEvent.attributes)
90
+ ) {
91
+ return {
92
+ eventId: userEvent.event_id,
93
+ createdAt: userEvent.created_at,
94
+ category: userEvent.category,
95
+ attributes: {
96
+ productId: userEvent.attributes.product_id,
97
+ parentProductId:
98
+ userEvent.attributes.parent_product_id !== null
99
+ ? userEvent.attributes.parent_product_id
100
+ : '',
101
+ url: userEvent.attributes.url,
102
+ },
103
+ };
104
+ }
105
+
106
+ // Handle PlpVisit
107
+ if (
108
+ userEvent.category === UserEventCategory.PlpVisit &&
109
+ isApiPLPEventAttributes(userEvent.attributes)
110
+ ) {
111
+ if (isApiPLPIdAttribute(userEvent.attributes.attributes)) {
112
+ return {
113
+ eventId: userEvent.event_id,
114
+ createdAt: userEvent.created_at,
115
+ category: UserEventCategory.PlpVisit,
116
+ attributes: {
117
+ category: userEvent.attributes.category,
118
+ attributes: {
119
+ id: userEvent.attributes.attributes.id,
120
+ },
121
+ },
122
+ };
123
+ }
124
+ }
125
+
126
+ // Handle QueryTyped
127
+ if (
128
+ userEvent.category === UserEventCategory.QueryTyped &&
129
+ isApiQueryTypedAttributes(userEvent.attributes)
130
+ ) {
131
+ return {
132
+ eventId: userEvent.event_id,
133
+ createdAt: userEvent.created_at,
134
+ category: UserEventCategory.QueryTyped,
135
+ attributes: {
136
+ query: userEvent.attributes.query,
137
+ },
138
+ };
139
+ }
140
+
141
+ // Handle Search
142
+ if (
143
+ userEvent.category === UserEventCategory.Search &&
144
+ isApiSearchAttributes(userEvent.attributes)
145
+ ) {
146
+ return {
147
+ eventId: userEvent.event_id,
148
+ createdAt: userEvent.created_at,
149
+ category: UserEventCategory.Search,
150
+ attributes: {
151
+ searchTerm: userEvent.attributes.search_term,
152
+ selectedFilters: userEvent.attributes.selected_filters,
153
+ },
154
+ };
155
+ }
156
+
157
+ // Handle SuggestionClicked
158
+ if (
159
+ userEvent.category === UserEventCategory.SuggestionClicked &&
160
+ isApiSuggestionClickedAttributes(userEvent.attributes)
161
+ ) {
162
+ return {
163
+ eventId: userEvent.event_id,
164
+ createdAt: userEvent.created_at,
165
+ category: UserEventCategory.SuggestionClicked,
166
+ attributes: {
167
+ suggestionId: userEvent.attributes.suggestion_id,
168
+ },
169
+ };
170
+ }
171
+
172
+ // Handle PageVisit
173
+ if (
174
+ userEvent.category === UserEventCategory.PageVisit &&
175
+ isApiPageVisitAttributes(userEvent.attributes)
176
+ ) {
177
+ return {
178
+ eventId: userEvent.event_id,
179
+ createdAt: userEvent.created_at,
180
+ category: UserEventCategory.PageVisit,
181
+ attributes: {
182
+ url: userEvent.attributes.url,
183
+ pageVisitCategory: userEvent.attributes.page_visit_category,
184
+ },
185
+ };
186
+ }
187
+
188
+ // Handle FormSubmitted
189
+ if (
190
+ userEvent.category === UserEventCategory.FormSubmitted &&
191
+ isApiFormSubmittedResponseAttributes(userEvent.attributes)
192
+ ) {
193
+ return {
194
+ eventId: userEvent.event_id,
195
+ createdAt: userEvent.created_at,
196
+ category: UserEventCategory.FormSubmitted,
197
+ attributes: {
198
+ filledSchema: { ...userEvent.attributes.filled_schema },
199
+ formResponseId: userEvent.attributes.form_response_id,
200
+ formType: userEvent.attributes.form_type,
201
+ },
202
+ };
203
+ }
204
+
205
+ // Handle AppLoaded (no attributes)
206
+ if (userEvent.category === UserEventCategory.AppLoaded) {
207
+ return {
208
+ eventId: userEvent.event_id,
209
+ createdAt: userEvent.created_at,
210
+ category: UserEventCategory.AppLoaded,
211
+ };
212
+ }
213
+
214
+ // Handle AppUnloaded (no attributes)
215
+ if (userEvent.category === UserEventCategory.AppUnloaded) {
216
+ return {
217
+ eventId: userEvent.event_id,
218
+ createdAt: userEvent.created_at,
219
+ category: UserEventCategory.AppUnloaded,
220
+ };
221
+ }
222
+
223
+ throw new Error(`Invalid user event category: ${userEvent.category}`);
224
+ };
@@ -16,7 +16,9 @@ import {
16
16
  import { useAtom } from 'jotai';
17
17
  import CommerceApiClient from 'src/application/commerce-api';
18
18
  import Logger from 'src/application/logging/logger';
19
- import { mapUrlResolverResponseToVariantInfo } from './mapping';
19
+ import { PageVisitCategory, UserEventCategory } from '@spiffy-ai/commerce-api-client';
20
+ import { VariantTypeEnum } from 'src/application/models';
21
+ import { mapApiUserEventToUserEvent, mapUrlResolverResponseToVariantInfo } from './mapping';
20
22
  import { PageDetails } from './types';
21
23
 
22
24
  const PageContext = createContext<
@@ -25,7 +27,8 @@ const PageContext = createContext<
25
27
 
26
28
  export const PageProvider: React.FC<{
27
29
  children: ReactNode;
28
- }> = ({ children }) => {
30
+ previewMode: boolean;
31
+ }> = ({ children, previewMode = false }) => {
29
32
  const [pageUrl, setPageUrl] = useState<string | undefined>(undefined);
30
33
  const [urlResolverResponse, setUrlResolverResponse] = useAtom(urlResolverAtom);
31
34
  const [isLoading, setIsLoading] = useState(false);
@@ -37,10 +40,31 @@ export const PageProvider: React.FC<{
37
40
  setPageUrl(window.location.href);
38
41
  }, []);
39
42
 
43
+ // Auto-initialize atoms for preview mode
44
+ useEffect(() => {
45
+ if (previewMode && !userEvent && !variantInfo) {
46
+ const url = typeof window !== 'undefined' ? window.location.href : '';
47
+ setUserEvent({
48
+ event_id: 'preview-user-event',
49
+ created_at: new Date().toISOString(),
50
+ category: UserEventCategory.PageVisit,
51
+ attributes: {
52
+ page_visit_category: PageVisitCategory.Other,
53
+ url,
54
+ },
55
+ } as any);
56
+
57
+ setVariantInfo({
58
+ variantType: VariantTypeEnum.PageVisit,
59
+ url,
60
+ });
61
+ }
62
+ }, [previewMode, userEvent, variantInfo, setUserEvent, setVariantInfo]);
63
+
40
64
  const setVariantFromUrlResolver = useCallback(
41
65
  (url: string, response: UrlResolverResponse) => {
42
66
  const newVariantInfo = mapUrlResolverResponseToVariantInfo(url, response);
43
- const newUserEvent = response.user_event ?? undefined;
67
+ const newUserEvent = mapApiUserEventToUserEvent(response.user_event ?? undefined);
44
68
  setVariantInfo(newVariantInfo);
45
69
  setUserEvent(newUserEvent);
46
70
  },
@@ -56,8 +80,8 @@ export const PageProvider: React.FC<{
56
80
  return;
57
81
  }
58
82
 
59
- // If atoms are already set (e.g., by storybook), skip API call
60
- if (userEvent || variantInfo) {
83
+ // If in preview mode or atoms are already set (e.g., by storybook), skip API call
84
+ if (previewMode || userEvent || variantInfo) {
61
85
  setIsLoading(false);
62
86
  return;
63
87
  }
@@ -82,6 +106,7 @@ export const PageProvider: React.FC<{
82
106
  setVariantFromUrlResolver,
83
107
  userEvent,
84
108
  variantInfo,
109
+ previewMode,
85
110
  ]);
86
111
 
87
112
  const value = useMemo(
@@ -1,5 +1,4 @@
1
- import { UserEvent } from '@spiffy-ai/commerce-api-client';
2
- import { VariantTypeEnum } from 'src/application/models';
1
+ import { UserEvent, VariantTypeEnum } from 'src/application/models';
3
2
 
4
3
  export type PDPPageVariantInfo = {
5
4
  variantType: VariantTypeEnum.Pdp;
@@ -9,6 +9,7 @@ import { queueUserEventAtom } from 'src/atoms/chat/messageQueue';
9
9
 
10
10
  export interface SalesAgentChatAPI {
11
11
  logPageVisit: ({ pageVisitCategory }: { pageVisitCategory: PageVisitCategory }) => void;
12
+ logUserEvent: (event: UserEvent) => void;
12
13
  onSuggestionClicked: (suggestion: Suggestion) => void;
13
14
  onTypedMessageSubmitted: ({ query }: { query: string }) => void;
14
15
  onFormResponseSubmitted: (formResponse: any) => void; // TODO: Figure out the right type
@@ -34,6 +35,13 @@ export const useSalesAgentChatAPI = () => {
34
35
  },
35
36
  [queueUserEvent],
36
37
  );
38
+
39
+ const logUserEvent = useCallback(
40
+ (event: UserEvent) => {
41
+ queueUserEvent(event);
42
+ },
43
+ [queueUserEvent],
44
+ );
37
45
  const onSuggestionClicked = useCallback(
38
46
  (suggestion: Suggestion) => {
39
47
  const event: UserEvent = {
@@ -69,6 +77,7 @@ export const useSalesAgentChatAPI = () => {
69
77
 
70
78
  return {
71
79
  logPageVisit,
80
+ logUserEvent,
72
81
  onSuggestionClicked,
73
82
  onTypedMessageSubmitted,
74
83
  onFormResponseSubmitted,