@envive-ai/react-widgets-v3 0.3.14 → 0.3.15-alpha.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 (336) hide show
  1. package/dist/debug/chatEmbed.cjs +1 -1
  2. package/dist/debug/chatEmbed.js +1 -1
  3. package/dist/debug/reportIssue.cjs +1 -1
  4. package/dist/debug/reportIssue.js +1 -1
  5. package/dist/hocs/withBaseWidget/types.d.cts +3 -3
  6. package/dist/hocs/withBaseWidget/types.d.ts +5 -3
  7. package/dist/hocs/withBaseWidget/withBaseWidget.d.cts +2 -2
  8. package/dist/hocs/withBaseWidget/withBaseWidget.d.ts +2 -2
  9. package/dist/hooks/dist/application/models/api/widgetText.d.cts +8 -0
  10. package/dist/hooks/dist/contexts/hardcopyContext/hardcopyContext.d.cts +12 -0
  11. package/dist/hooks/dist/contexts/types.d.cts +38 -0
  12. package/dist/hooks/dist/contexts/typesV3.d.cts +230 -0
  13. package/dist/hooks/dist/services/amplitudeService/eventNames.d.cts +43 -0
  14. package/dist/hooks/dist/types/customerService.d.cts +21 -0
  15. package/dist/node_modules/@spiffy-ai/commerce-api-client/dist/models/WidgetType.cjs +1 -0
  16. package/dist/packages/hooks/dist/application/models/api/orgConfigResults.d.ts +1 -0
  17. package/dist/packages/hooks/dist/application/models/api/widgetText.d.ts +8 -0
  18. package/dist/packages/hooks/dist/application/models/frontendConfig.d.ts +1 -0
  19. package/dist/packages/hooks/dist/contexts/amplitudeContext/amplitudeContext.d.ts +2 -0
  20. package/dist/packages/hooks/dist/contexts/amplitudeContext/index.d.ts +2 -0
  21. package/dist/packages/hooks/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.d.ts +2 -0
  22. package/dist/packages/hooks/dist/contexts/hardcopyContext/hardcopyContext.d.ts +14 -0
  23. package/dist/packages/hooks/dist/contexts/hardcopyContext/index.d.ts +1 -0
  24. package/dist/packages/hooks/dist/contexts/types.d.ts +42 -0
  25. package/dist/packages/hooks/dist/contexts/typesV3.d.ts +230 -0
  26. package/dist/packages/hooks/dist/services/amplitudeService/amplitudeService.d.ts +1 -0
  27. package/dist/packages/hooks/dist/services/amplitudeService/eventNames.d.ts +43 -0
  28. package/dist/packages/hooks/dist/types/customerService.d.ts +21 -0
  29. package/dist/packages/icons/dist/IconCloseVariant.cjs +5 -6
  30. package/dist/packages/icons/dist/IconCloseVariant.js +4 -6
  31. package/dist/packages/widgets/dist/SearchResults/SearchResults.d.ts +4 -3
  32. package/dist/packages/widgets/dist/SearchResults/SearchResultsWidget.d.ts +2 -2
  33. package/dist/packages/widgets/dist/SearchZeroState/SearchZeroStateWidget.d.ts +2 -2
  34. package/dist/packages/widgets/dist/SearchZeroState/index.d.ts +2 -1
  35. package/dist/packages/widgets/dist/SearchZeroState/types.d.ts +2 -2
  36. package/dist/packages/widgets/dist/SuggestionBar/SuggestionBar.d.ts +3 -3
  37. package/dist/packages/widgets/dist/SuggestionButtonContainer/index.d.ts +2 -0
  38. package/dist/packages/widgets/dist/SuggestionButtonContainer/types.d.ts +3 -2
  39. package/dist/packages/widgets/dist/packages/hooks/dist/application/models/api/response.d.ts +14 -0
  40. package/dist/packages/widgets/dist/packages/hooks/dist/application/models/api/search.d.ts +15 -0
  41. package/dist/packages/widgets/dist/packages/hooks/dist/application/models/utilityTypes/camelCase.d.ts +73 -0
  42. package/dist/packages/widgets/dist/packages/hooks/dist/application/models/utilityTypes/camelCasedPropertiesDeep.d.ts +61 -0
  43. package/dist/packages/widgets/dist/packages/hooks/dist/application/models/utilityTypes/internal.d.ts +25 -0
  44. package/dist/packages/widgets/dist/packages/hooks/dist/application/models/utilityTypes/splitWords.d.ts +35 -0
  45. package/dist/packages/widgets/dist/packages/hooks/dist/application/models/utilityTypes/trim.d.ts +32 -0
  46. package/dist/packages/widgets/dist/packages/hooks/dist/application/models/utilityTypes/unknownArray.d.ts +32 -0
  47. package/dist/packages/widgets/dist/packages/hooks/dist/application/models/variantInfo/variantInfo.d.ts +1 -0
  48. package/dist/packages/widgets/dist/packages/hooks/dist/atoms/search/searchAPI.d.ts +15 -0
  49. package/dist/packages/widgets/dist/packages/hooks/dist/contexts/hardcopyContext/hardcopyContext.d.ts +1 -0
  50. package/dist/packages/widgets/dist/packages/hooks/dist/contexts/types.d.ts +63 -0
  51. package/dist/packages/widgets/dist/packages/hooks/dist/hooks/Search/useSearch.d.ts +60 -0
  52. package/dist/packages/widgets/dist/packages/hooks/dist/hooks/utils.d.ts +13 -0
  53. package/dist/packages/widgets/dist/packages/hooks/dist/types/OrgInfo.d.ts +1 -0
  54. package/dist/packages/widgets/dist/packages/hooks/dist/types/index.d.ts +1 -0
  55. package/dist/packages/widgets/dist/packages/hooks/dist/types/search-filter-types.d.ts +28 -0
  56. package/dist/packages/widgets/dist/packages/hooks/dist/types/test-types.d.ts +10 -0
  57. package/dist/src/CXIntegration/hooks/useUnifiedCXButton.d.ts +10 -0
  58. package/dist/src/CXIntegration/hooks/useUnifiedCXButton.js +29 -0
  59. package/dist/src/CXIntegration/implementations/useDefaultUnifiedCXButton.d.ts +2 -0
  60. package/dist/src/CXIntegration/implementations/useDefaultUnifiedCXButton.js +6 -0
  61. package/dist/src/CXIntegration/implementations/useEightByEightUnifiedCXButton.d.ts +5 -0
  62. package/dist/src/CXIntegration/implementations/useEightByEightUnifiedCXButton.js +63 -0
  63. package/dist/src/CXIntegration/implementations/useGladlyUnifiedCXButton.d.ts +5 -0
  64. package/dist/src/CXIntegration/implementations/useGladlyUnifiedCXButton.js +23 -0
  65. package/dist/src/CXIntegration/implementations/useGorgiasUnifiedCXButton.d.ts +5 -0
  66. package/dist/src/CXIntegration/implementations/useGorgiasUnifiedCXButton.js +54 -0
  67. package/dist/src/CXIntegration/implementations/useGrooveUnifiedCXButton.d.ts +18 -0
  68. package/dist/src/CXIntegration/implementations/useGrooveUnifiedCXButton.js +48 -0
  69. package/dist/src/CXIntegration/implementations/useHelpScoutUnifiedCXButton.d.ts +5 -0
  70. package/dist/src/CXIntegration/implementations/useHelpScoutUnifiedCXButton.js +84 -0
  71. package/dist/src/CXIntegration/implementations/useKustomerUnifiedCXButton.d.ts +5 -0
  72. package/dist/src/CXIntegration/implementations/useKustomerUnifiedCXButton.js +86 -0
  73. package/dist/src/CXIntegration/implementations/useReDoUnifiedCXButton.d.ts +5 -0
  74. package/dist/src/CXIntegration/implementations/useReDoUnifiedCXButton.js +59 -0
  75. package/dist/src/CXIntegration/implementations/useRichpanelUnifiedCXButton.d.ts +5 -0
  76. package/dist/src/CXIntegration/implementations/useRichpanelUnifiedCXButton.js +62 -0
  77. package/dist/src/CXIntegration/implementations/useShopifyChatUnifiedCXButton.d.ts +5 -0
  78. package/dist/src/CXIntegration/implementations/useShopifyChatUnifiedCXButton.js +49 -0
  79. package/dist/src/CXIntegration/implementations/useTalkdeskUnifiedCXButton.d.ts +5 -0
  80. package/dist/src/CXIntegration/implementations/useTalkdeskUnifiedCXButton.js +77 -0
  81. package/dist/src/CXIntegration/implementations/useTidioUnifiedCXButton.d.ts +13 -0
  82. package/dist/src/CXIntegration/implementations/useTidioUnifiedCXButton.js +20 -0
  83. package/dist/src/CXIntegration/implementations/useZendeskUnifiedCXButton.d.ts +5 -0
  84. package/dist/src/CXIntegration/implementations/useZendeskUnifiedCXButton.js +55 -0
  85. package/dist/src/CXIntegration/implementations/useZowieUnifiedCXButton.d.ts +13 -0
  86. package/dist/src/CXIntegration/implementations/useZowieUnifiedCXButton.js +20 -0
  87. package/dist/src/CXIntegration/types.d.ts +26 -0
  88. package/dist/src/CXIntegration/types.js +17 -0
  89. package/dist/src/CXIntegration/utils/functions.d.ts +2 -0
  90. package/dist/src/CXIntegration/utils/functions.js +57 -0
  91. package/dist/src/debug/GenericSelect.d.ts +11 -0
  92. package/dist/src/debug/GenericSelect.js +151 -0
  93. package/dist/src/debug/MessageContent.d.ts +4 -0
  94. package/dist/src/debug/MessageContent.js +87 -0
  95. package/dist/src/debug/chatEmbed.d.ts +2 -0
  96. package/dist/src/debug/chatEmbed.js +58 -0
  97. package/dist/src/debug/debugBar.d.ts +1 -0
  98. package/dist/src/debug/debugBar.js +9 -0
  99. package/dist/src/debug/reportIssue.d.ts +1 -0
  100. package/dist/src/debug/reportIssue.js +322 -0
  101. package/dist/src/hocs/withBaseWidget/__tests__/withBaseWidget.test.d.ts +1 -0
  102. package/dist/src/hocs/withBaseWidget/__tests__/withBaseWidget.test.js +452 -0
  103. package/dist/src/hocs/withBaseWidget/index.d.ts +2 -0
  104. package/dist/src/hocs/withBaseWidget/index.js +1 -0
  105. package/dist/src/hocs/withBaseWidget/types.d.ts +33 -0
  106. package/dist/src/hocs/withBaseWidget/types.js +0 -0
  107. package/dist/src/hocs/withBaseWidget/withBaseWidget.d.ts +5 -0
  108. package/dist/src/hocs/withBaseWidget/withBaseWidget.js +80 -0
  109. package/dist/src/stories/FloatingChatWidget.stories.d.ts +25 -0
  110. package/dist/src/stories/FloatingChatWidget.stories.js +44 -0
  111. package/dist/src/stories/FullPageSalesAgentWidget.stories.d.ts +31 -0
  112. package/dist/src/stories/FullPageSalesAgentWidget.stories.js +51 -0
  113. package/dist/src/stories/ProductCardWidget.stories.d.ts +31 -0
  114. package/dist/src/stories/ProductCardWidget.stories.js +44 -0
  115. package/dist/src/stories/PromptButtonCarouselWithImageWidget.stories.d.ts +31 -0
  116. package/dist/src/stories/PromptButtonCarouselWithImageWidget.stories.js +40 -0
  117. package/dist/src/stories/PromptCarouselWidget.stories.d.ts +31 -0
  118. package/dist/src/stories/PromptCarouselWidget.stories.js +40 -0
  119. package/dist/src/stories/SalesAgentTest/SalesAgentTest.d.ts +1 -0
  120. package/dist/src/stories/SalesAgentTest/SalesAgentTest.js +40 -0
  121. package/dist/src/stories/SalesAgentTest/SalesAgentTest.stories.d.ts +12 -0
  122. package/dist/src/stories/SalesAgentTest/SalesAgentTest.stories.js +12 -0
  123. package/dist/src/stories/SalesAgentTest/index.d.ts +0 -0
  124. package/dist/src/stories/SalesAgentTest/index.js +0 -0
  125. package/dist/src/stories/SearchResults.stories.d.ts +6 -0
  126. package/dist/src/stories/SearchResults.stories.js +23 -0
  127. package/dist/src/stories/SearchZeroState.stories.d.ts +38 -0
  128. package/dist/src/stories/SearchZeroState.stories.js +42 -0
  129. package/dist/src/stories/SocialProofFlowWidget.stories.d.ts +35 -0
  130. package/dist/src/stories/SocialProofFlowWidget.stories.js +60 -0
  131. package/dist/src/stories/SuggestionBar.stories.d.ts +7 -0
  132. package/dist/src/stories/SuggestionBar.stories.js +36 -0
  133. package/dist/src/stories/TitledPromptCarouselWidget.stories.d.ts +32 -0
  134. package/dist/src/stories/TitledPromptCarouselWidget.stories.js +55 -0
  135. package/dist/src/stories/TypingAnimationFlowWidget.stories.d.ts +34 -0
  136. package/dist/src/stories/TypingAnimationFlowWidget.stories.js +51 -0
  137. package/dist/src/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.d.ts +12 -0
  138. package/dist/src/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.js +112 -0
  139. package/dist/src/widgets/ChatPreviewComparisonWidget/index.d.ts +3 -0
  140. package/dist/src/widgets/ChatPreviewComparisonWidget/index.js +2 -0
  141. package/dist/src/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.d.ts +9 -0
  142. package/dist/src/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.js +34 -0
  143. package/dist/src/widgets/ChatPreviewLoadingWidget/index.d.ts +3 -0
  144. package/dist/src/widgets/ChatPreviewLoadingWidget/index.js +2 -0
  145. package/dist/src/widgets/ChatPreviewWidget/ChatPreviewWidget.d.ts +12 -0
  146. package/dist/src/widgets/ChatPreviewWidget/ChatPreviewWidget.js +111 -0
  147. package/dist/src/widgets/ChatPreviewWidget/__tests__/ChatPreviewWidget.test.d.ts +1 -0
  148. package/dist/src/widgets/ChatPreviewWidget/__tests__/ChatPreviewWidget.test.js +97 -0
  149. package/dist/src/widgets/ChatPreviewWidget/index.d.ts +3 -0
  150. package/dist/src/widgets/ChatPreviewWidget/index.js +2 -0
  151. package/dist/src/widgets/FloatingChatWidget/FloatingChatOverlay.d.ts +14 -0
  152. package/dist/src/widgets/FloatingChatWidget/FloatingChatOverlay.js +44 -0
  153. package/dist/src/widgets/FloatingChatWidget/FloatingChatWidget.d.ts +8 -0
  154. package/dist/src/widgets/FloatingChatWidget/FloatingChatWidget.js +134 -0
  155. package/dist/src/widgets/FloatingChatWidget/__tests__/FloatingChatWidget.test.d.ts +1 -0
  156. package/dist/src/widgets/FloatingChatWidget/__tests__/FloatingChatWidget.test.js +100 -0
  157. package/dist/src/widgets/FloatingChatWidget/constants.d.ts +1 -0
  158. package/dist/src/widgets/FloatingChatWidget/constants.js +1 -0
  159. package/dist/src/widgets/FloatingChatWidget/hooks/useAutoPopup.d.ts +4 -0
  160. package/dist/src/widgets/FloatingChatWidget/hooks/useAutoPopup.js +51 -0
  161. package/dist/src/widgets/FloatingChatWidget/hooks/useFloatingButtonVisibility.d.ts +11 -0
  162. package/dist/src/widgets/FloatingChatWidget/hooks/useFloatingButtonVisibility.js +21 -0
  163. package/dist/src/widgets/FloatingChatWidget/index.d.ts +4 -0
  164. package/dist/src/widgets/FloatingChatWidget/index.js +3 -0
  165. package/dist/src/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.d.ts +12 -0
  166. package/dist/src/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.js +14 -0
  167. package/dist/src/widgets/FullPageSalesAgentWidget/index.d.ts +1 -0
  168. package/dist/src/widgets/FullPageSalesAgentWidget/index.js +1 -0
  169. package/dist/src/widgets/ProductCardWidget/ProductCardWidget.d.ts +7 -0
  170. package/dist/src/widgets/ProductCardWidget/ProductCardWidget.js +94 -0
  171. package/dist/src/widgets/ProductCardWidget/__tests__/ProductCardWidget.test.d.ts +1 -0
  172. package/dist/src/widgets/ProductCardWidget/__tests__/ProductCardWidget.test.js +106 -0
  173. package/dist/src/widgets/ProductCardWidget/index.d.ts +2 -0
  174. package/dist/src/widgets/ProductCardWidget/index.js +1 -0
  175. package/dist/src/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.d.ts +12 -0
  176. package/dist/src/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.js +88 -0
  177. package/dist/src/widgets/PromptButtonCarouselWithImageWidget/__tests__/PromptButtonCarouselWithImageWidget.test.d.ts +1 -0
  178. package/dist/src/widgets/PromptButtonCarouselWithImageWidget/__tests__/PromptButtonCarouselWithImageWidget.test.js +132 -0
  179. package/dist/src/widgets/PromptButtonCarouselWithImageWidget/index.d.ts +2 -0
  180. package/dist/src/widgets/PromptButtonCarouselWithImageWidget/index.js +2 -0
  181. package/dist/src/widgets/PromptCarouselWidget/PromptCarouselWidget.d.ts +7 -0
  182. package/dist/src/widgets/PromptCarouselWidget/PromptCarouselWidget.js +74 -0
  183. package/dist/src/widgets/PromptCarouselWidget/__tests__/PromptCarouselWidget.test.d.ts +1 -0
  184. package/dist/src/widgets/PromptCarouselWidget/__tests__/PromptCarouselWidget.test.js +106 -0
  185. package/dist/src/widgets/PromptCarouselWidget/index.d.ts +2 -0
  186. package/dist/src/widgets/PromptCarouselWidget/index.js +1 -0
  187. package/dist/src/widgets/SocialProofFlowWidget/SocialProofFlowWidget.d.ts +7 -0
  188. package/dist/src/widgets/SocialProofFlowWidget/SocialProofFlowWidget.js +25 -0
  189. package/dist/src/widgets/SocialProofFlowWidget/index.d.ts +3 -0
  190. package/dist/src/widgets/SocialProofFlowWidget/index.js +2 -0
  191. package/dist/src/widgets/SocialProofWidget/SocialProofWidget.d.ts +12 -0
  192. package/dist/src/widgets/SocialProofWidget/SocialProofWidget.js +203 -0
  193. package/dist/src/widgets/SocialProofWidget/__tests__/SocialProofWidget.test.d.ts +1 -0
  194. package/dist/src/widgets/SocialProofWidget/__tests__/SocialProofWidget.test.js +135 -0
  195. package/dist/src/widgets/SocialProofWidget/index.d.ts +2 -0
  196. package/dist/src/widgets/SocialProofWidget/index.js +1 -0
  197. package/dist/src/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.d.ts +7 -0
  198. package/dist/src/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.js +75 -0
  199. package/dist/src/widgets/TitledPromptCarouselWidget/__tests__/TitledPromptCarouselWidget.test.d.ts +1 -0
  200. package/dist/src/widgets/TitledPromptCarouselWidget/__tests__/TitledPromptCarouselWidget.test.js +106 -0
  201. package/dist/src/widgets/TitledPromptCarouselWidget/index.d.ts +2 -0
  202. package/dist/src/widgets/TitledPromptCarouselWidget/index.js +1 -0
  203. package/dist/src/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.d.ts +7 -0
  204. package/dist/src/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.js +25 -0
  205. package/dist/src/widgets/TypingAnimationFlowWidget/index.d.ts +3 -0
  206. package/dist/src/widgets/TypingAnimationFlowWidget/index.js +2 -0
  207. package/dist/src/widgets/TypingAnimationWidget/TypingAnimationWidget.d.ts +12 -0
  208. package/dist/src/widgets/TypingAnimationWidget/TypingAnimationWidget.js +126 -0
  209. package/dist/src/widgets/TypingAnimationWidget/__tests__/TypingAnimationWidget.test.d.ts +1 -0
  210. package/dist/src/widgets/TypingAnimationWidget/__tests__/TypingAnimationWidget.test.js +118 -0
  211. package/dist/src/widgets/TypingAnimationWidget/index.d.ts +2 -0
  212. package/dist/src/widgets/TypingAnimationWidget/index.js +1 -0
  213. package/dist/src/widgets/__tests__/testUtils.d.ts +60 -0
  214. package/dist/src/widgets/__tests__/testUtils.js +46 -0
  215. package/dist/src/widgets/__tests__/trackEventCanary.test.d.ts +1 -0
  216. package/dist/src/widgets/__tests__/trackEventCanary.test.js +37 -0
  217. package/dist/src/widgets/hooks/useGetWidgetStatus.d.ts +7 -0
  218. package/dist/src/widgets/hooks/useGetWidgetStatus.js +17 -0
  219. package/dist/src/widgets/utils/functions.d.ts +16 -0
  220. package/dist/src/widgets/utils/functions.js +87 -0
  221. package/dist/src/widgets-v2/SearchResults/index.d.ts +2 -0
  222. package/dist/src/widgets-v2/SearchResults/index.js +2 -0
  223. package/dist/src/widgets-v2/SearchZeroState/index.d.ts +2 -0
  224. package/dist/src/widgets-v2/SearchZeroState/index.js +2 -0
  225. package/dist/src/widgets-v2/SuggestionBar/index.d.ts +2 -0
  226. package/dist/src/widgets-v2/SuggestionBar/index.js +2 -0
  227. package/dist/src/widgets-v2/SuggestionButtonContainer/index.d.ts +2 -0
  228. package/dist/src/widgets-v2/SuggestionButtonContainer/index.js +2 -0
  229. package/dist/tsdown.config.d.ts +2 -0
  230. package/dist/tsdown.config.js +12 -0
  231. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.cjs +36 -5
  232. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.d.ts +3 -3
  233. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.js +36 -5
  234. package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.d.cts +3 -3
  235. package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.d.ts +3 -3
  236. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.cjs +34 -4
  237. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.d.cts +3 -3
  238. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.d.ts +3 -3
  239. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.js +35 -5
  240. package/dist/widgets/FloatingChatWidget/FloatingChatOverlay.cjs +0 -2
  241. package/dist/widgets/FloatingChatWidget/FloatingChatOverlay.js +0 -2
  242. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.cjs +31 -7
  243. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.d.cts +2 -2
  244. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.js +32 -8
  245. package/dist/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.d.cts +2 -2
  246. package/dist/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.d.ts +2 -2
  247. package/dist/widgets/ProductCardWidget/ProductCardWidget.cjs +25 -3
  248. package/dist/widgets/ProductCardWidget/ProductCardWidget.d.cts +2 -2
  249. package/dist/widgets/ProductCardWidget/ProductCardWidget.d.ts +2 -2
  250. package/dist/widgets/ProductCardWidget/ProductCardWidget.js +25 -3
  251. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.cjs +23 -4
  252. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.d.cts +3 -3
  253. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.d.ts +3 -3
  254. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.js +23 -4
  255. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.cjs +15 -3
  256. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.d.cts +2 -2
  257. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.d.ts +2 -2
  258. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.js +17 -5
  259. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.d.cts +2 -2
  260. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.d.ts +2 -2
  261. package/dist/widgets/SocialProofWidget/SocialProofWidget.cjs +53 -6
  262. package/dist/widgets/SocialProofWidget/SocialProofWidget.d.ts +3 -3
  263. package/dist/widgets/SocialProofWidget/SocialProofWidget.js +54 -7
  264. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.cjs +10 -1
  265. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.d.cts +2 -2
  266. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.d.ts +2 -2
  267. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.js +11 -2
  268. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.d.ts +2 -2
  269. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.cjs +24 -3
  270. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.d.cts +3 -3
  271. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.d.ts +3 -3
  272. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.js +25 -4
  273. package/dist/widgets/dist/SearchResults/SearchResults.d.cts +4 -3
  274. package/dist/widgets/dist/SearchResults/SearchResultsWidget.d.cts +2 -2
  275. package/dist/widgets/dist/SearchZeroState/SearchZeroStateWidget.d.cts +2 -2
  276. package/dist/widgets/dist/SearchZeroState/types.d.cts +2 -2
  277. package/dist/widgets/dist/SuggestionBar/SuggestionBar.d.cts +3 -3
  278. package/dist/widgets/dist/SuggestionButtonContainer/types.d.cts +3 -2
  279. package/dist/widgets/dist/packages/hooks/dist/application/models/api/response.d.cts +14 -0
  280. package/dist/widgets/dist/packages/hooks/dist/application/models/api/search.d.cts +15 -0
  281. package/dist/widgets/dist/packages/hooks/dist/application/models/utilityTypes/camelCase.d.cts +73 -0
  282. package/dist/widgets/dist/packages/hooks/dist/application/models/utilityTypes/camelCasedPropertiesDeep.d.cts +61 -0
  283. package/dist/widgets/dist/packages/hooks/dist/application/models/utilityTypes/internal.d.cts +25 -0
  284. package/dist/widgets/dist/packages/hooks/dist/application/models/utilityTypes/splitWords.d.cts +35 -0
  285. package/dist/widgets/dist/packages/hooks/dist/application/models/utilityTypes/trim.d.cts +32 -0
  286. package/dist/widgets/dist/packages/hooks/dist/application/models/utilityTypes/unknownArray.d.cts +32 -0
  287. package/dist/widgets/dist/packages/hooks/dist/atoms/search/searchAPI.d.cts +14 -0
  288. package/dist/widgets/dist/packages/hooks/dist/contexts/types.d.cts +61 -0
  289. package/dist/widgets/dist/packages/hooks/dist/hooks/Search/useSearch.d.cts +60 -0
  290. package/dist/widgets/dist/packages/hooks/dist/hooks/utils.d.cts +12 -0
  291. package/dist/widgets/dist/packages/hooks/dist/types/search-filter-types.d.cts +28 -0
  292. package/dist/widgets/dist/packages/hooks/dist/types/test-types.d.cts +10 -0
  293. package/dist/widgets/hooks/useGetWidgetStatus.cjs +1 -1
  294. package/dist/widgets/hooks/useGetWidgetStatus.js +1 -1
  295. package/dist/widgets/utils/functions.cjs +0 -14
  296. package/dist/widgets/utils/functions.js +1 -14
  297. package/dist/widgets-v2/SearchZeroState/index.d.cts +2 -1
  298. package/dist/widgets-v2/SearchZeroState/index.d.ts +2 -1
  299. package/dist/widgets-v2/SuggestionButtonContainer/index.d.ts +1 -0
  300. package/package.json +4 -4
  301. package/src/hocs/withBaseWidget/__tests__/withBaseWidget.test.tsx +68 -302
  302. package/src/hocs/withBaseWidget/types.ts +6 -6
  303. package/src/hocs/withBaseWidget/withBaseWidget.tsx +46 -61
  304. package/src/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.tsx +59 -8
  305. package/src/widgets/ChatPreviewWidget/ChatPreviewWidget.tsx +54 -18
  306. package/src/widgets/ChatPreviewWidget/__tests__/ChatPreviewWidget.test.tsx +11 -5
  307. package/src/widgets/FloatingChatWidget/FloatingChatOverlay.tsx +48 -19
  308. package/src/widgets/FloatingChatWidget/FloatingChatWidget.tsx +100 -52
  309. package/src/widgets/FloatingChatWidget/__tests__/FloatingChatWidget.test.tsx +11 -5
  310. package/src/widgets/ProductCardWidget/ProductCardWidget.tsx +37 -16
  311. package/src/widgets/ProductCardWidget/__tests__/ProductCardWidget.test.tsx +12 -8
  312. package/src/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.tsx +38 -19
  313. package/src/widgets/PromptButtonCarouselWithImageWidget/__tests__/PromptButtonCarouselWithImageWidget.test.tsx +19 -8
  314. package/src/widgets/PromptCarouselWidget/PromptCarouselWidget.tsx +32 -19
  315. package/src/widgets/PromptCarouselWidget/__tests__/PromptCarouselWidget.test.tsx +21 -8
  316. package/src/widgets/SocialProofWidget/SocialProofWidget.tsx +77 -18
  317. package/src/widgets/SocialProofWidget/__tests__/SocialProofWidget.test.tsx +19 -8
  318. package/src/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.tsx +23 -19
  319. package/src/widgets/TitledPromptCarouselWidget/__tests__/TitledPromptCarouselWidget.test.tsx +19 -8
  320. package/src/widgets/TypingAnimationWidget/TypingAnimationWidget.tsx +45 -21
  321. package/src/widgets/TypingAnimationWidget/__tests__/TypingAnimationWidget.test.tsx +19 -8
  322. package/src/widgets/__tests__/trackEventCanary.test.ts +1 -1
  323. package/dist/packages/icons/dist/_virtual/rolldown_runtime.cjs +0 -27
  324. package/dist/packages/icons/dist/_virtual/rolldown_runtime.js +0 -25
  325. package/dist/packages/icons/dist/node_modules/react/cjs/react-jsx-runtime.development.cjs +0 -696
  326. package/dist/packages/icons/dist/node_modules/react/cjs/react-jsx-runtime.development.js +0 -696
  327. package/dist/packages/icons/dist/node_modules/react/cjs/react-jsx-runtime.production.min.cjs +0 -43
  328. package/dist/packages/icons/dist/node_modules/react/cjs/react-jsx-runtime.production.min.js +0 -43
  329. package/dist/packages/icons/dist/node_modules/react/cjs/react.development.cjs +0 -1528
  330. package/dist/packages/icons/dist/node_modules/react/cjs/react.development.js +0 -1528
  331. package/dist/packages/icons/dist/node_modules/react/cjs/react.production.min.cjs +0 -329
  332. package/dist/packages/icons/dist/node_modules/react/cjs/react.production.min.js +0 -329
  333. package/dist/packages/icons/dist/node_modules/react/index.cjs +0 -13
  334. package/dist/packages/icons/dist/node_modules/react/index.js +0 -13
  335. package/dist/packages/icons/dist/node_modules/react/jsx-runtime.cjs +0 -13
  336. package/dist/packages/icons/dist/node_modules/react/jsx-runtime.js +0 -13
@@ -0,0 +1,452 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { render, screen, waitFor } from '@testing-library/react';
3
+ import { SpiffyMetricsEventName } from '@envive-ai/react-hooks/contexts/amplitudeContext';
4
+ import { WidgetTypeV3 } from '@envive-ai/react-hooks/contexts/typesV3';
5
+ import { UserEventCategory } from '@spiffy-ai/commerce-api-client';
6
+ import { withBaseWidget } from '../withBaseWidget';
7
+ // Mock IntersectionObserver
8
+ class MockIntersectionObserver {
9
+ observe = vi.fn();
10
+ disconnect = vi.fn();
11
+ unobserve = vi.fn();
12
+ root = null;
13
+ rootMargin = '';
14
+ thresholds = [];
15
+ callback;
16
+ options;
17
+ constructor(callback, options) {
18
+ this.callback = callback;
19
+ this.options = options;
20
+ if (options) {
21
+ this.rootMargin = options.rootMargin || '';
22
+ }
23
+ }
24
+ // Helper method to trigger intersection
25
+ triggerIntersection(isIntersecting, target) {
26
+ const entry = {
27
+ isIntersecting,
28
+ intersectionRatio: isIntersecting ? 1 : 0,
29
+ boundingClientRect: {},
30
+ rootBounds: {},
31
+ target: target || {},
32
+ time: Date.now(),
33
+ };
34
+ this.callback([entry]);
35
+ }
36
+ // Helper method to get options
37
+ getOptions() {
38
+ return this.options;
39
+ }
40
+ // Required by IntersectionObserver interface but not used in tests
41
+ // eslint-disable-next-line class-methods-use-this
42
+ takeRecords() {
43
+ return [];
44
+ }
45
+ }
46
+ // Mock the contexts
47
+ const mockTrackEvent = vi.fn();
48
+ const mockGetHardcopy = vi.fn();
49
+ vi.mock('@envive-ai/react-hooks/contexts/amplitudeContext', () => ({
50
+ useAmplitude: () => ({
51
+ trackEvent: mockTrackEvent,
52
+ isReady: true,
53
+ }),
54
+ SpiffyMetricsEventName: {
55
+ ChatComponentVisible: 'Chat Component Visible',
56
+ SearchComponentVisible: 'Search Component Visible',
57
+ },
58
+ }));
59
+ vi.mock('@envive-ai/react-hooks/contexts/hardcopyContext', () => ({
60
+ useHardcopy: () => ({
61
+ getHardcopy: mockGetHardcopy,
62
+ }),
63
+ }));
64
+ vi.mock('@envive-ai/react-hooks/contexts/pageContext', () => ({
65
+ usePage: () => ({
66
+ userEvent: {
67
+ id: 'test-user-event-id',
68
+ category: UserEventCategory.PageVisit,
69
+ created_at: '2025-01-01T00:00:00Z',
70
+ event_id: 'test-event-id',
71
+ },
72
+ }),
73
+ }));
74
+ vi.mock('@envive-ai/react-hooks/contexts/widgetConfigContext', () => ({
75
+ useWidgetConfig: () => ({
76
+ getWidgetConfig: vi.fn().mockResolvedValue({}),
77
+ }),
78
+ }));
79
+ vi.mock('@envive-ai/react-hooks/contexts/uiConfigContext', () => ({
80
+ useUiConfig: () => ({
81
+ getUiConfig: vi.fn().mockResolvedValue({}),
82
+ }),
83
+ }));
84
+ const TestWidget = ({ widgetConfigId, widgetType, hardcopyContent, observedWidget, testId = 'test-widget', children, }) => {
85
+ // Attach the ref to the root div so IntersectionObserver can observe it
86
+ // Note: The ref type is RefObject<HTMLDivElement> but BaseWidgetProps expects RefObject<BaseWidgetProps>
87
+ // This is a type mismatch in the implementation, but we handle it for testing
88
+ const ref = observedWidget;
89
+ return (_jsxs("div", { ref: ref, "data-testid": testId, children: [_jsx("div", { "data-testid": "widget-config-id", children: widgetConfigId }), _jsx("div", { "data-testid": "widget-type", children: widgetType }), hardcopyContent && (_jsxs("div", { "data-testid": "hardcopy-content", children: [_jsx("div", { "data-testid": "hardcopy-language", children: hardcopyContent.language }), _jsx("div", { "data-testid": "hardcopy-values", children: JSON.stringify(hardcopyContent.values) })] })), observedWidget && _jsx("div", { "data-testid": "observed-widget-ref", children: "Ref attached" }), children] }));
90
+ };
91
+ describe('withBaseWidget', () => {
92
+ let mockObserver;
93
+ let mockObservers;
94
+ let originalIntersectionObserver;
95
+ beforeEach(() => {
96
+ vi.clearAllMocks();
97
+ mockObservers = [];
98
+ // Set default mock for getHardcopy to return a resolved promise
99
+ mockGetHardcopy.mockResolvedValue({
100
+ language: 'en',
101
+ values: {},
102
+ });
103
+ // Store original IntersectionObserver
104
+ originalIntersectionObserver = global.IntersectionObserver;
105
+ // Replace IntersectionObserver with mock class
106
+ global.IntersectionObserver = class extends MockIntersectionObserver {
107
+ constructor(callback, options) {
108
+ super(callback, options);
109
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
110
+ mockObserver = this;
111
+ mockObservers.push(this);
112
+ }
113
+ };
114
+ });
115
+ afterEach(() => {
116
+ // Restore original IntersectionObserver
117
+ global.IntersectionObserver = originalIntersectionObserver;
118
+ });
119
+ describe('IntersectionObserver setup', () => {
120
+ it('should create an IntersectionObserver with default rootMargin', () => {
121
+ const WrappedWidget = withBaseWidget(TestWidget);
122
+ render(_jsx(WrappedWidget, { widgetConfigId: "test-config-1", widgetType: WidgetTypeV3.PromptCarouselV3 }));
123
+ expect(mockObserver).toBeDefined();
124
+ expect(mockObserver.rootMargin).toBe('0px');
125
+ });
126
+ it('should create an IntersectionObserver with custom rootMargin', () => {
127
+ const WrappedWidget = withBaseWidget(TestWidget, {
128
+ rootMargin: '100px',
129
+ });
130
+ render(_jsx(WrappedWidget, { widgetConfigId: "test-config-2", widgetType: WidgetTypeV3.ChatPreviewV3 }));
131
+ expect(mockObserver).toBeDefined();
132
+ expect(mockObserver.rootMargin).toBe('100px');
133
+ });
134
+ it('should observe the widget element', () => {
135
+ const WrappedWidget = withBaseWidget(TestWidget);
136
+ render(_jsx(WrappedWidget, { widgetConfigId: "test-config-3", widgetType: WidgetTypeV3.PromptCarouselV3 }));
137
+ expect(mockObserver.observe).toHaveBeenCalled();
138
+ });
139
+ });
140
+ describe('Amplitude event tracking', () => {
141
+ it('should track default event when widget becomes visible', async () => {
142
+ const WrappedWidget = withBaseWidget(TestWidget);
143
+ const { container } = render(_jsx(WrappedWidget, { widgetConfigId: "test-config-4", widgetType: WidgetTypeV3.PromptCarouselV3 }));
144
+ const widgetElement = container.querySelector('[data-testid="test-widget"]');
145
+ // Trigger intersection with the actual element
146
+ mockObserver.triggerIntersection(true, widgetElement);
147
+ await waitFor(() => {
148
+ expect(mockTrackEvent).toHaveBeenCalledWith({
149
+ eventName: SpiffyMetricsEventName.ChatComponentVisible,
150
+ eventProps: {
151
+ widget_config_id: 'test-config-4',
152
+ widget_type: WidgetTypeV3.PromptCarouselV3,
153
+ },
154
+ });
155
+ });
156
+ });
157
+ it('should track custom event when widget becomes visible', async () => {
158
+ const WrappedWidget = withBaseWidget(TestWidget, {
159
+ visibilityEventName: SpiffyMetricsEventName.SearchComponentVisible,
160
+ });
161
+ const { container } = render(_jsx(WrappedWidget, { widgetConfigId: "test-config-5", widgetType: WidgetTypeV3.ChatPreviewV3 }));
162
+ const widgetElement = container.querySelector('[data-testid="test-widget"]');
163
+ // Trigger intersection
164
+ mockObserver.triggerIntersection(true, widgetElement);
165
+ await waitFor(() => {
166
+ expect(mockTrackEvent).toHaveBeenCalledWith({
167
+ eventName: SpiffyMetricsEventName.SearchComponentVisible,
168
+ eventProps: {
169
+ widget_config_id: 'test-config-5',
170
+ widget_type: WidgetTypeV3.ChatPreviewV3,
171
+ },
172
+ });
173
+ });
174
+ });
175
+ it('should include custom event props when tracking', async () => {
176
+ const WrappedWidget = withBaseWidget(TestWidget, {
177
+ visibilityEventProps: {
178
+ custom_prop: 'custom_value',
179
+ another_prop: 123,
180
+ },
181
+ });
182
+ const { container } = render(_jsx(WrappedWidget, { widgetConfigId: "test-config-6", widgetType: WidgetTypeV3.SocialProofV3 }));
183
+ const widgetElement = container.querySelector('[data-testid="test-widget"]');
184
+ // Trigger intersection
185
+ mockObserver.triggerIntersection(true, widgetElement);
186
+ await waitFor(() => {
187
+ expect(mockTrackEvent).toHaveBeenCalledWith({
188
+ eventName: SpiffyMetricsEventName.ChatComponentVisible,
189
+ eventProps: {
190
+ widget_config_id: 'test-config-6',
191
+ widget_type: WidgetTypeV3.SocialProofV3,
192
+ custom_prop: 'custom_value',
193
+ another_prop: 123,
194
+ },
195
+ });
196
+ });
197
+ });
198
+ it('should only track event once even if intersection happens multiple times', async () => {
199
+ const WrappedWidget = withBaseWidget(TestWidget);
200
+ const { container } = render(_jsx(WrappedWidget, { widgetConfigId: "test-config-7", widgetType: WidgetTypeV3.PromptCarouselV3 }));
201
+ const widgetElement = container.querySelector('[data-testid="test-widget"]');
202
+ // Trigger intersection multiple times
203
+ mockObserver.triggerIntersection(true, widgetElement);
204
+ mockObserver.triggerIntersection(false, widgetElement);
205
+ mockObserver.triggerIntersection(true, widgetElement);
206
+ await waitFor(() => {
207
+ expect(mockTrackEvent).toHaveBeenCalledTimes(1);
208
+ });
209
+ });
210
+ it('should disconnect observer after tracking event', async () => {
211
+ const WrappedWidget = withBaseWidget(TestWidget);
212
+ const { container } = render(_jsx(WrappedWidget, { widgetConfigId: "test-config-8", widgetType: WidgetTypeV3.PromptCarouselV3 }));
213
+ const widgetElement = container.querySelector('[data-testid="test-widget"]');
214
+ // Trigger intersection
215
+ mockObserver.triggerIntersection(true, widgetElement);
216
+ await waitFor(() => {
217
+ expect(mockObserver.disconnect).toHaveBeenCalled();
218
+ });
219
+ });
220
+ it('should not track event if widget is not intersecting', async () => {
221
+ const WrappedWidget = withBaseWidget(TestWidget);
222
+ const { container } = render(_jsx(WrappedWidget, { widgetConfigId: "test-config-9", widgetType: WidgetTypeV3.PromptCarouselV3 }));
223
+ const widgetElement = container.querySelector('[data-testid="test-widget"]');
224
+ // Trigger non-intersection
225
+ mockObserver.triggerIntersection(false, widgetElement);
226
+ // Wait a bit to ensure no event is tracked
227
+ await new Promise(resolve => {
228
+ setTimeout(resolve, 100);
229
+ });
230
+ expect(mockTrackEvent).not.toHaveBeenCalled();
231
+ });
232
+ });
233
+ describe('Hardcopy content fetching', () => {
234
+ it('should fetch hardcopy content when widget mounts', async () => {
235
+ const mockHardcopy = {
236
+ responseId: 'mock-response-id',
237
+ language: 'en',
238
+ values: {
239
+ suggestionBarButtons: ['Button 1', 'Button 2'],
240
+ },
241
+ };
242
+ mockGetHardcopy.mockResolvedValue(mockHardcopy);
243
+ const WrappedWidget = withBaseWidget(TestWidget);
244
+ render(_jsx(WrappedWidget, { widgetConfigId: "test-config-10", widgetType: WidgetTypeV3.PromptCarouselV3 }));
245
+ await waitFor(() => {
246
+ expect(mockGetHardcopy).toHaveBeenCalledWith({
247
+ widgetType: WidgetTypeV3.PromptCarouselV3,
248
+ userEvent: {
249
+ id: 'test-user-event-id',
250
+ category: UserEventCategory.PageVisit,
251
+ created_at: '2025-01-01T00:00:00Z',
252
+ event_id: 'test-event-id',
253
+ },
254
+ });
255
+ });
256
+ });
257
+ it('should pass hardcopy content to widget', async () => {
258
+ const mockHardcopy = {
259
+ responseId: 'mock-response-id',
260
+ language: 'en',
261
+ values: {
262
+ chatPreviewTitle: 'Chat Preview Title',
263
+ typewriterTextPrefix: 'Want to know',
264
+ },
265
+ };
266
+ mockGetHardcopy.mockResolvedValue(mockHardcopy);
267
+ const WrappedWidget = withBaseWidget(TestWidget);
268
+ render(_jsx(WrappedWidget, { widgetConfigId: "test-config-11", widgetType: WidgetTypeV3.ChatPreviewV3 }));
269
+ await waitFor(() => {
270
+ expect(screen.getByTestId('hardcopy-content')).toBeInTheDocument();
271
+ expect(screen.getByTestId('hardcopy-language')).toHaveTextContent('en');
272
+ expect(screen.getByTestId('hardcopy-values')).toHaveTextContent(JSON.stringify(mockHardcopy.values));
273
+ });
274
+ });
275
+ it('should not fetch hardcopy if widgetType is not provided', () => {
276
+ const WrappedWidget = withBaseWidget(TestWidget);
277
+ // @ts-expect-error - Testing invalid props
278
+ render(_jsx(WrappedWidget, { widgetConfigId: "test-config-12" }));
279
+ expect(mockGetHardcopy).not.toHaveBeenCalled();
280
+ });
281
+ it('should handle hardcopy fetch errors gracefully', async () => {
282
+ const error = new Error('Failed to fetch hardcopy');
283
+ mockGetHardcopy.mockRejectedValue(error);
284
+ const WrappedWidget = withBaseWidget(TestWidget);
285
+ render(_jsx(WrappedWidget, { widgetConfigId: "test-config-13", widgetType: WidgetTypeV3.PromptCarouselV3 }));
286
+ await waitFor(() => {
287
+ expect(mockGetHardcopy).toHaveBeenCalled();
288
+ });
289
+ // Wait a bit for the promise to reject and be handled
290
+ await new Promise(resolve => {
291
+ setTimeout(resolve, 100);
292
+ });
293
+ // Widget should still render without hardcopy
294
+ expect(screen.getByTestId('test-widget')).toBeInTheDocument();
295
+ expect(screen.queryByTestId('hardcopy-content')).not.toBeInTheDocument();
296
+ });
297
+ });
298
+ describe('Widget rendering', () => {
299
+ it('should render the wrapped widget with correct props', () => {
300
+ const WrappedWidget = withBaseWidget(TestWidget);
301
+ render(_jsx(WrappedWidget, { widgetConfigId: "test-config-14", widgetType: WidgetTypeV3.PromptCarouselV3 }));
302
+ expect(screen.getByTestId('test-widget')).toBeInTheDocument();
303
+ expect(screen.getByTestId('widget-config-id')).toHaveTextContent('test-config-14');
304
+ expect(screen.getByTestId('widget-type')).toHaveTextContent(WidgetTypeV3.PromptCarouselV3);
305
+ });
306
+ it('should pass observedWidget ref to the widget', () => {
307
+ const WrappedWidget = withBaseWidget(TestWidget);
308
+ render(_jsx(WrappedWidget, { widgetConfigId: "test-config-15", widgetType: WidgetTypeV3.PromptCarouselV3 }));
309
+ expect(screen.getByTestId('observed-widget-ref')).toBeInTheDocument();
310
+ });
311
+ it('should render widget children correctly', () => {
312
+ const WrappedWidget = withBaseWidget(TestWidget);
313
+ render(_jsx(WrappedWidget, { widgetConfigId: "test-config-16", widgetType: WidgetTypeV3.PromptCarouselV3, children: _jsx("div", { "data-testid": "child-content", children: "Child Content" }) }));
314
+ expect(screen.getByTestId('child-content')).toBeInTheDocument();
315
+ expect(screen.getByTestId('child-content')).toHaveTextContent('Child Content');
316
+ });
317
+ it('should render widget with hardcopy content when available', async () => {
318
+ const mockHardcopy = {
319
+ responseId: 'mock-response-id',
320
+ language: 'en',
321
+ values: {
322
+ imagePromptTitle: 'Image Prompt Title',
323
+ },
324
+ };
325
+ mockGetHardcopy.mockResolvedValue(mockHardcopy);
326
+ const WrappedWidget = withBaseWidget(TestWidget);
327
+ render(_jsx(WrappedWidget, { widgetConfigId: "test-config-17", widgetType: WidgetTypeV3.ImagePromptCardV3 }));
328
+ await waitFor(() => {
329
+ expect(screen.getByTestId('hardcopy-content')).toBeInTheDocument();
330
+ });
331
+ expect(screen.getByTestId('hardcopy-language')).toHaveTextContent('en');
332
+ expect(screen.getByTestId('hardcopy-values')).toHaveTextContent(JSON.stringify(mockHardcopy.values));
333
+ });
334
+ });
335
+ describe('Integration tests', () => {
336
+ it('should handle full flow: visibility tracking + hardcopy rendering', async () => {
337
+ const mockHardcopy = {
338
+ responseId: 'mock-response-id',
339
+ language: 'en',
340
+ values: {
341
+ suggestionBarButtons: ['Button 1', 'Button 2', 'Button 3'],
342
+ },
343
+ };
344
+ mockGetHardcopy.mockResolvedValue(mockHardcopy);
345
+ const WrappedWidget = withBaseWidget(TestWidget, {
346
+ visibilityEventName: SpiffyMetricsEventName.SearchComponentVisible,
347
+ visibilityEventProps: {
348
+ test_integration: true,
349
+ },
350
+ });
351
+ render(_jsx(WrappedWidget, { widgetConfigId: "test-config-integration", widgetType: WidgetTypeV3.PromptCarouselV3 }));
352
+ // Wait for hardcopy to be fetched and rendered
353
+ await waitFor(() => {
354
+ expect(screen.getByTestId('hardcopy-content')).toBeInTheDocument();
355
+ });
356
+ const widgetElement = screen.getByTestId('test-widget');
357
+ // Trigger intersection to track event
358
+ mockObserver.triggerIntersection(true, widgetElement);
359
+ // Verify both hardcopy and event tracking worked
360
+ await waitFor(() => {
361
+ expect(mockTrackEvent).toHaveBeenCalledWith({
362
+ eventName: SpiffyMetricsEventName.SearchComponentVisible,
363
+ eventProps: {
364
+ widget_config_id: 'test-config-integration',
365
+ widget_type: WidgetTypeV3.PromptCarouselV3,
366
+ test_integration: true,
367
+ },
368
+ });
369
+ });
370
+ expect(screen.getByTestId('hardcopy-language')).toHaveTextContent('en');
371
+ expect(screen.getByTestId('hardcopy-values')).toHaveTextContent(JSON.stringify(mockHardcopy.values));
372
+ });
373
+ it('should handle multiple widget instances independently', async () => {
374
+ const mockHardcopy1 = {
375
+ responseId: 'mock-response-id',
376
+ language: 'en',
377
+ values: { buttons: ['Button 1'] },
378
+ };
379
+ const mockHardcopy2 = {
380
+ responseId: 'mock-response-id',
381
+ language: 'en',
382
+ values: { buttons: ['Button 2'] },
383
+ };
384
+ mockGetHardcopy.mockResolvedValueOnce(mockHardcopy1).mockResolvedValueOnce(mockHardcopy2);
385
+ const WrappedWidget = withBaseWidget(TestWidget);
386
+ // Render both widgets simultaneously to test independence
387
+ render(_jsxs(_Fragment, { children: [_jsx(WrappedWidget, { widgetConfigId: "widget-1", widgetType: WidgetTypeV3.PromptCarouselV3, testId: "widget-1" }), _jsx(WrappedWidget, { widgetConfigId: "widget-2", widgetType: WidgetTypeV3.ChatPreviewV3, testId: "widget-2" })] }));
388
+ // Wait for both widgets to render and fetch hardcopy
389
+ await waitFor(() => {
390
+ expect(screen.getByTestId('widget-1')).toBeInTheDocument();
391
+ expect(screen.getByTestId('widget-2')).toBeInTheDocument();
392
+ });
393
+ // Verify both widgets have their own config IDs
394
+ const widget1ConfigId = screen
395
+ .getByTestId('widget-1')
396
+ .querySelector('[data-testid="widget-config-id"]');
397
+ const widget2ConfigId = screen
398
+ .getByTestId('widget-2')
399
+ .querySelector('[data-testid="widget-config-id"]');
400
+ expect(widget1ConfigId).toHaveTextContent('widget-1');
401
+ expect(widget2ConfigId).toHaveTextContent('widget-2');
402
+ // Verify both widgets fetched their own hardcopy independently
403
+ expect(mockGetHardcopy).toHaveBeenCalledWith({
404
+ widgetType: WidgetTypeV3.PromptCarouselV3,
405
+ userEvent: expect.any(Object),
406
+ });
407
+ expect(mockGetHardcopy).toHaveBeenCalledWith({
408
+ widgetType: WidgetTypeV3.ChatPreviewV3,
409
+ userEvent: expect.any(Object),
410
+ });
411
+ // Verify first widget can trigger intersection and track event
412
+ // When multiple widgets are rendered, each creates its own IntersectionObserver
413
+ // We need to find the observer that's observing widget-1's element
414
+ const widget1Element = screen.getByTestId('widget-1');
415
+ const widget2Element = screen.getByTestId('widget-2');
416
+ // Clear any previous calls to isolate this test
417
+ mockTrackEvent.mockClear();
418
+ // Find which observer is observing widget-1 by checking which one was called with widget1Element
419
+ // In our mock setup, the first observer should be for widget-1, second for widget-2
420
+ const widget1Observer = mockObservers[0];
421
+ const widget2Observer = mockObservers[1];
422
+ // Verify we have both observers
423
+ expect(widget1Observer).toBeDefined();
424
+ expect(widget2Observer).toBeDefined();
425
+ // Trigger intersection for widget-1 using its observer
426
+ widget1Observer.triggerIntersection(true, widget1Element);
427
+ await waitFor(() => {
428
+ // Verify that an event was tracked for widget-1
429
+ expect(mockTrackEvent).toHaveBeenCalled();
430
+ const { calls } = mockTrackEvent.mock;
431
+ // Find any call that matches widget-1's properties
432
+ const widget1Call = calls.find(
433
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
434
+ (call) => call[0]?.eventProps?.widget_config_id === 'widget-1' &&
435
+ call[0]?.eventProps?.widget_type === WidgetTypeV3.PromptCarouselV3);
436
+ expect(widget1Call).toBeDefined();
437
+ });
438
+ // Verify widget-2 can also track independently
439
+ mockTrackEvent.mockClear();
440
+ widget2Observer.triggerIntersection(true, widget2Element);
441
+ await waitFor(() => {
442
+ expect(mockTrackEvent).toHaveBeenCalled();
443
+ const { calls } = mockTrackEvent.mock;
444
+ const widget2Call = calls.find(
445
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
446
+ (call) => call[0]?.eventProps?.widget_config_id === 'widget-2' &&
447
+ call[0]?.eventProps?.widget_type === WidgetTypeV3.ChatPreviewV3);
448
+ expect(widget2Call).toBeDefined();
449
+ });
450
+ });
451
+ });
452
+ });
@@ -0,0 +1,2 @@
1
+ export { withBaseWidget } from './withBaseWidget';
2
+ export type { BaseWidgetProps, WithBaseWidgetOptions } from './types';
@@ -0,0 +1 @@
1
+ export { withBaseWidget } from './withBaseWidget';
@@ -0,0 +1,33 @@
1
+ import { RefObject } from 'react';
2
+ import { SpiffyMetricsEventName } from '@envive-ai/react-hooks/contexts/amplitudeContext';
3
+ import { HardcopyResponse } from '@envive-ai/react-hooks/contexts/hardcopyContext';
4
+ import { OrgUIConfigV3, WidgetConfigV3, WidgetTypeV3 } from '@envive-ai/react-hooks/contexts/typesV3';
5
+ export interface BaseWidgetProps {
6
+ widgetConfigId?: string;
7
+ widgetType: WidgetTypeV3;
8
+ observedWidget?: RefObject<BaseWidgetProps>;
9
+ hardcopyContent?: HardcopyResponse;
10
+ widgetConfig?: WidgetConfigV3;
11
+ uiConfig?: OrgUIConfigV3;
12
+ isLoading?: boolean;
13
+ isHardcopyLoading?: boolean;
14
+ isPageLoading?: boolean;
15
+ isWidgetConfigLoading?: boolean;
16
+ isUiConfigLoading?: boolean;
17
+ }
18
+ export interface WithBaseWidgetOptions {
19
+ /**
20
+ * The Amplitude event name to track when the widget becomes visible.
21
+ * Defaults to a generic component visible event if not provided.
22
+ */
23
+ visibilityEventName?: SpiffyMetricsEventName;
24
+ /**
25
+ * Additional properties to include with the visibility event.
26
+ */
27
+ visibilityEventProps?: Record<string, unknown>;
28
+ /**
29
+ * Root margin for the IntersectionObserver (e.g., '0px', '100px').
30
+ * Defaults to '0px'.
31
+ */
32
+ rootMargin?: string;
33
+ }
File without changes
@@ -0,0 +1,5 @@
1
+ import { BaseWidgetProps, WithBaseWidgetOptions } from './types';
2
+ export declare function withBaseWidget<P extends BaseWidgetProps>(Widget: React.ComponentType<P>, options?: WithBaseWidgetOptions): {
3
+ (props: P): import("react/jsx-runtime").JSX.Element;
4
+ displayName: string;
5
+ };
@@ -0,0 +1,80 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import { SpiffyMetricsEventName, useAmplitude, } from '@envive-ai/react-hooks/contexts/amplitudeContext';
4
+ import { useHardcopy } from '@envive-ai/react-hooks/contexts/hardcopyContext';
5
+ import { usePage } from '@envive-ai/react-hooks/contexts/pageContext';
6
+ import { useWidgetConfig } from '@envive-ai/react-hooks/contexts/widgetConfigContext';
7
+ import { useUiConfig } from '@envive-ai/react-hooks/contexts/uiConfigContext';
8
+ export function withBaseWidget(Widget, options) {
9
+ const WrappedWidget = (props) => {
10
+ const { widgetConfigId, widgetType } = props;
11
+ const widgetRef = useRef(null);
12
+ const hasTrackedEvent = useRef(false);
13
+ const { trackEvent, isReady } = useAmplitude();
14
+ const [hardcopyContent, setHardcopyContent] = useState(undefined);
15
+ const { getHardcopy, isLoading: isHardcopyLoading } = useHardcopy();
16
+ const { userEvent, isLoading: isPageLoading } = usePage();
17
+ const [widgetConfig, setWidgetConfig] = useState(undefined);
18
+ const { getWidgetConfig, isLoading: isWidgetConfigLoading } = useWidgetConfig();
19
+ const [uiConfig, setUiConfig] = useState(undefined);
20
+ const { getUiConfig, isLoading: isUiConfigLoading } = useUiConfig();
21
+ const isLoading = isHardcopyLoading || isPageLoading || isWidgetConfigLoading || isUiConfigLoading;
22
+ useEffect(() => {
23
+ if (!isReady || hasTrackedEvent.current || !widgetRef.current) {
24
+ return undefined;
25
+ }
26
+ const observer = new IntersectionObserver(([entry]) => {
27
+ if (entry.isIntersecting && !hasTrackedEvent.current) {
28
+ const eventName = options?.visibilityEventName || SpiffyMetricsEventName.ChatComponentVisible;
29
+ trackEvent({
30
+ eventName,
31
+ eventProps: {
32
+ widget_config_id: widgetConfigId,
33
+ widget_type: widgetType,
34
+ ...options?.visibilityEventProps,
35
+ },
36
+ });
37
+ hasTrackedEvent.current = true;
38
+ observer.disconnect();
39
+ }
40
+ }, {
41
+ rootMargin: options?.rootMargin || '0px',
42
+ });
43
+ observer.observe(widgetRef.current);
44
+ return () => {
45
+ observer.disconnect();
46
+ };
47
+ }, [isReady, widgetConfigId, widgetType, trackEvent]);
48
+ useEffect(() => {
49
+ if (!widgetType || !userEvent) {
50
+ return;
51
+ }
52
+ getHardcopy({ widgetType, userEvent })
53
+ .then(setHardcopyContent)
54
+ .catch(() => {
55
+ // Silently handle errors - widget will render without hardcopy content
56
+ });
57
+ }, [widgetConfigId, widgetType, getHardcopy, userEvent]);
58
+ useEffect(() => {
59
+ getUiConfig()
60
+ .then(setUiConfig)
61
+ .catch(() => {
62
+ // Silently handle errors - widget will render without ui config
63
+ });
64
+ }, [getUiConfig, widgetConfigId, widgetType]);
65
+ useEffect(() => {
66
+ if (!widgetConfigId || !widgetType) {
67
+ return;
68
+ }
69
+ getWidgetConfig({ widgetConfigId, widgetType })
70
+ .then(setWidgetConfig)
71
+ .catch(e => {
72
+ console.error('Error getting widget config', widgetConfigId, widgetType, e);
73
+ // Silently handle errors - widget will render without widget config
74
+ });
75
+ }, [widgetConfigId, widgetType, getWidgetConfig]);
76
+ return (_jsx(Widget, { ...props, isLoading: isLoading, isHardcopyLoading: isHardcopyLoading, isPageLoading: isPageLoading, isWidgetConfigLoading: isWidgetConfigLoading, isUiConfigLoading: isUiConfigLoading, uiConfig: uiConfig, widgetConfig: widgetConfig, hardcopyContent: hardcopyContent, observedWidget: widgetRef }));
77
+ };
78
+ WrappedWidget.displayName = `withBaseWidget(${Widget.displayName || Widget.name || 'Component'})`;
79
+ return WrappedWidget;
80
+ }
@@ -0,0 +1,25 @@
1
+ import type { StoryObj } from '@storybook/react-vite';
2
+ declare const meta: {
3
+ title: string;
4
+ component: {
5
+ ({ previewButtonOnly, previewChatAlwaysOpen, }?: import("../widgets/FloatingChatWidget").FloatingChatWidgetProps): import("react/jsx-runtime").JSX.Element;
6
+ displayName: string;
7
+ };
8
+ tags: string[];
9
+ args: {};
10
+ argTypes: {};
11
+ parameters: {
12
+ docs: {
13
+ description: {
14
+ component: string;
15
+ };
16
+ };
17
+ };
18
+ decorators: ((Story: import("storybook/internal/csf").PartialStoryFn<import("@storybook/react").ReactRenderer, {
19
+ previewButtonOnly?: boolean;
20
+ previewChatAlwaysOpen?: boolean;
21
+ }>) => import("react/jsx-runtime").JSX.Element)[];
22
+ };
23
+ export default meta;
24
+ type Story = StoryObj<typeof meta>;
25
+ export declare const Playground: Story;
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PageVisitCategory, useSalesAgent, } from '@envive-ai/react-hooks/contexts/salesAgentContext';
3
+ import { useEffect } from 'react';
4
+ import { v4 as uuid } from 'uuid';
5
+ import { UserEventCategory } from '@spiffy-ai/commerce-api-client';
6
+ import { FloatingChatWidget } from '../widgets/FloatingChatWidget';
7
+ const meta = {
8
+ title: 'Widgets V3/FloatingChatWidget',
9
+ component: FloatingChatWidget,
10
+ tags: ['autodocs'],
11
+ args: {},
12
+ argTypes: {},
13
+ parameters: {
14
+ docs: {
15
+ description: {
16
+ component: 'FloatingChatWidget is a widget wrapper around FloatingChat that includes base widget functionality such as visibility tracking, widget config fetching and hardcopy content fetching. The widget renders a floating chat interface that allows users to interact with the sales agent.',
17
+ },
18
+ },
19
+ },
20
+ decorators: [
21
+ Story => {
22
+ const { logPageVisit, logUserEvent } = useSalesAgent();
23
+ useEffect(() => {
24
+ logUserEvent({
25
+ eventId: uuid(),
26
+ category: UserEventCategory.AppLoaded,
27
+ createdAt: new Date().toISOString(),
28
+ });
29
+ logPageVisit({ pageVisitCategory: PageVisitCategory.Homepage });
30
+ }, []);
31
+ return _jsx(Story, {});
32
+ },
33
+ ],
34
+ };
35
+ export default meta;
36
+ export const Playground = {
37
+ parameters: {
38
+ docs: {
39
+ description: {
40
+ story: 'Experiment with different widgetConfigId values. The widget will fetch configuration from the widget config based on the widgetConfigId.',
41
+ },
42
+ },
43
+ },
44
+ };