@envive-ai/react-hooks 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (385) hide show
  1. package/LICENSE +2 -0
  2. package/README.md +2 -0
  3. package/dist/GridInsertionService-CEYo9pGj.js +22 -0
  4. package/dist/GridInsertionService-CS_bnPh0.cjs +28 -0
  5. package/dist/bandolier-Ble8jEa8.js +1221 -0
  6. package/dist/bandolier-Bm2xAt_j.cjs +1221 -0
  7. package/dist/carpe-Da7b-LCW.cjs +599 -0
  8. package/dist/carpe-W13mhRRP.js +597 -0
  9. package/dist/cdnService-CZ-aXcY6.cjs +23 -0
  10. package/dist/cdnService-zQfKk3Eb.js +18 -0
  11. package/dist/chatElementDisplayLocation-CX8fuNao.d.cts +239 -0
  12. package/dist/chatElementDisplayLocation-CwptS9tx.d.ts +239 -0
  13. package/dist/chunk-CUT6urMc.cjs +30 -0
  14. package/dist/contexts/index.cjs +13 -0
  15. package/dist/contexts/index.d.cts +65 -0
  16. package/dist/contexts/index.d.ts +66 -0
  17. package/dist/contexts/index.js +7 -0
  18. package/dist/contexts-BRjfVq_k.js +5064 -0
  19. package/dist/contexts-BYArqZtK.cjs +5164 -0
  20. package/dist/coterie-3y0D9ko4.cjs +229 -0
  21. package/dist/coterie-DOWcJAYv.js +229 -0
  22. package/dist/custservice-types-CFIFwZ-r.js +10 -0
  23. package/dist/custservice-types-CkfxZiHY.cjs +16 -0
  24. package/dist/default-C2fEZKXk.js +175 -0
  25. package/dist/default-CBUq6Q6G.cjs +4 -0
  26. package/dist/default-CGIFZK6m.js +4 -0
  27. package/dist/default-D_KPZdPJ.cjs +198 -0
  28. package/dist/divIds-Bss-btao.js +49 -0
  29. package/dist/divIds-DnZNd7rA.cjs +223 -0
  30. package/dist/dreamlandBaby-DCIsuU9R.cjs +338 -0
  31. package/dist/dreamlandBaby-DvSaZGrz.js +338 -0
  32. package/dist/entrypoints-D_JUvkgy.cjs +18 -0
  33. package/dist/entrypoints-YLQsbBRD.js +6 -0
  34. package/dist/enviveConfigContext-CUGLpPGU.js +34 -0
  35. package/dist/enviveConfigContext-Dfr2VH6u.cjs +48 -0
  36. package/dist/fiveCbd-B1SESMCO.js +605 -0
  37. package/dist/fiveCbd-CkOlVby_.cjs +605 -0
  38. package/dist/forLoveAndLemons-CfYPMnKS.cjs +660 -0
  39. package/dist/forLoveAndLemons-DmwYZIk0.js +658 -0
  40. package/dist/greenpan-Bsl3ir59.cjs +389 -0
  41. package/dist/greenpan-BtOi45lf.js +389 -0
  42. package/dist/grooveLife-6_dtYsRk.js +334 -0
  43. package/dist/grooveLife-Cmm1PSCL.cjs +334 -0
  44. package/dist/homegrownCannabis-C-kw-74X.js +400 -0
  45. package/dist/homegrownCannabis-CO0uY_mp.cjs +400 -0
  46. package/dist/hooks/index.cjs +16 -0
  47. package/dist/hooks/index.d.cts +357 -0
  48. package/dist/hooks/index.d.ts +357 -0
  49. package/dist/hooks/index.js +7 -0
  50. package/dist/jackArcher-CLVmwwpI.js +719 -0
  51. package/dist/jackArcher-DdYTIzAV.cjs +719 -0
  52. package/dist/jordanCraig-Am-Oor-O.js +1778 -0
  53. package/dist/jordanCraig-_u3-w4Hp.cjs +1778 -0
  54. package/dist/kindredBravely-CWovIDSc.cjs +482 -0
  55. package/dist/kindredBravely-eWp-ud_E.js +482 -0
  56. package/dist/kutFromTheKloth-BMV4BuGQ.js +361 -0
  57. package/dist/kutFromTheKloth-Q589bAOC.cjs +361 -0
  58. package/dist/larryAndSerges-BMUlTgI-.js +252 -0
  59. package/dist/larryAndSerges-CEau764j.cjs +252 -0
  60. package/dist/leapsAndRebounds-DGMzPO7T.js +352 -0
  61. package/dist/leapsAndRebounds-DHAtRTJD.cjs +352 -0
  62. package/dist/logger-Dln20ans.cjs +25 -0
  63. package/dist/logger-pdEEY8T2.js +19 -0
  64. package/dist/longevityrx-CZW8Hxzi.cjs +312 -0
  65. package/dist/longevityrx-jH2JLhNH.js +312 -0
  66. package/dist/lookOptic-BGXP5P_V.js +274 -0
  67. package/dist/lookOptic-CA6RwLbG.cjs +274 -0
  68. package/dist/mantraBrand-Cm9_PBCT.js +742 -0
  69. package/dist/mantraBrand-DByNqpnL.cjs +742 -0
  70. package/dist/medterra-B0wxj_PV.js +575 -0
  71. package/dist/medterra-DnPN2ksU.cjs +575 -0
  72. package/dist/modells-Bmz8Ag5M.js +476 -0
  73. package/dist/modells-CoYgkLSp.cjs +476 -0
  74. package/dist/models-DHdb7QWn.js +51 -0
  75. package/dist/models-ixxUsGL_.cjs +69 -0
  76. package/dist/pressedFloral-DSKs_oVG.js +653 -0
  77. package/dist/pressedFloral-DjBiSoUl.cjs +653 -0
  78. package/dist/skinPerfection-B_3xzVNS.cjs +326 -0
  79. package/dist/skinPerfection-IDrBuAPt.js +326 -0
  80. package/dist/snapSupplements-BJk5T5ba.js +277 -0
  81. package/dist/snapSupplements-BStTsdOZ.cjs +277 -0
  82. package/dist/socialProofClasses-Bhv2Vulz.js +9 -0
  83. package/dist/socialProofClasses-CrQBWdSA.cjs +39 -0
  84. package/dist/spanx-BYg0LE7R.js +653 -0
  85. package/dist/spanx-LwU1zSzq.cjs +655 -0
  86. package/dist/spanxStaging-CfSmuKYB.js +837 -0
  87. package/dist/spanxStaging-OZLV9qix.cjs +840 -0
  88. package/dist/suggestionBarV2-types-BllzwsBD.js +34 -0
  89. package/dist/suggestionBarV2-types-CaovchMP.cjs +46 -0
  90. package/dist/supergoop-BqPXDnKk.cjs +327 -0
  91. package/dist/supergoop-CIlrHND_.js +325 -0
  92. package/dist/types-C4T5UOIW.cjs +230 -0
  93. package/dist/types-CYNvLeSA.js +176 -0
  94. package/dist/uniqueVintage-B30mOqbH.cjs +1205 -0
  95. package/dist/uniqueVintage-CFueJOhO.js +1203 -0
  96. package/dist/venaCbd-DHGZy49P.cjs +357 -0
  97. package/dist/venaCbd-T0CqVD4k.js +357 -0
  98. package/dist/westonJonBoucher-BdMzs_Yg.cjs +414 -0
  99. package/dist/westonJonBoucher-b4TCQ4ev.js +414 -0
  100. package/dist/wineEnthusiast-BLGlOjgr.cjs +932 -0
  101. package/dist/wineEnthusiast-BqR0i_54.js +932 -0
  102. package/dist/wolfMattress-CyyO-LoC.js +362 -0
  103. package/dist/wolfMattress-DNGZOivg.cjs +362 -0
  104. package/dist/wolfTactical-3Mm2fvVF.js +341 -0
  105. package/dist/wolfTactical-BmXYlFjr.cjs +341 -0
  106. package/package.json +66 -0
  107. package/src/adapters/amplitude/amplitudeAdapter.ts +454 -0
  108. package/src/adapters/amplitude/index.ts +2 -0
  109. package/src/adapters/amplitude/stubAmplitudeAdapter.ts +34 -0
  110. package/src/adapters/spiffy/commerce/api.ts +596 -0
  111. package/src/adapters/spiffy/commerce/exceptions/sessionExceptions.ts +6 -0
  112. package/src/adapters/spiffy/commerce/exceptions/unsupportedProductExceptions.ts +6 -0
  113. package/src/adapters/spiffy/commerce/graphql.ts +184 -0
  114. package/src/application/config/generalStaticConfig.ts +37 -0
  115. package/src/application/logging/logger.ts +29 -0
  116. package/src/application/models/api/context.ts +4 -0
  117. package/src/application/models/api/generationParams.ts +4 -0
  118. package/src/application/models/api/nextMessageRequest.ts +11 -0
  119. package/src/application/models/api/orgAnalyticsConfig.ts +19 -0
  120. package/src/application/models/api/orgConfigResults.ts +40 -0
  121. package/src/application/models/api/organizationConfig.ts +12 -0
  122. package/src/application/models/api/response.ts +132 -0
  123. package/src/application/models/api/responseGenerics.ts +67 -0
  124. package/src/application/models/api/search.ts +26 -0
  125. package/src/application/models/api/suggestion.ts +4 -0
  126. package/src/application/models/api/supportedEventRequest.ts +8 -0
  127. package/src/application/models/api/userEvent.ts +101 -0
  128. package/src/application/models/cachedValue.ts +8 -0
  129. package/src/application/models/chatElementDisplayLocation.ts +22 -0
  130. package/src/application/models/clientDetails.ts +18 -0
  131. package/src/application/models/colorsConfig.ts +28 -0
  132. package/src/application/models/conversationalSearchIds.ts +5 -0
  133. package/src/application/models/dataLayer.ts +45 -0
  134. package/src/application/models/domMutationContinuation.ts +7 -0
  135. package/src/application/models/domObservationStrategy.ts +9 -0
  136. package/src/application/models/events.ts +5 -0
  137. package/src/application/models/featureGates.ts +23 -0
  138. package/src/application/models/frontendConfig.ts +14 -0
  139. package/src/application/models/googleAnalyticsEvents.ts +8 -0
  140. package/src/application/models/graphql/index.ts +2 -0
  141. package/src/application/models/graphql/queries/getMerchantColorsQuery.ts +37 -0
  142. package/src/application/models/graphql/queries/getMerchantFrontendConfigQuery.ts +103 -0
  143. package/src/application/models/graphql/queries/getMerchantOrgIdQuery.ts +11 -0
  144. package/src/application/models/guards/api/index.ts +12 -0
  145. package/src/application/models/guards/api/isApiFormResponse.ts +90 -0
  146. package/src/application/models/guards/api/isApiFormSubmittedResponseAttributes.ts +37 -0
  147. package/src/application/models/guards/api/isApiOrderResponseAttributes.ts +155 -0
  148. package/src/application/models/guards/api/isApiOrgConfigResults.ts +277 -0
  149. package/src/application/models/guards/api/isApiOrganizationConfig.ts +207 -0
  150. package/src/application/models/guards/api/isApiPDPEventAttributes.ts +21 -0
  151. package/src/application/models/guards/api/isApiPLPEventAttributes.ts +41 -0
  152. package/src/application/models/guards/api/isApiPageResponseAttributes.ts +21 -0
  153. package/src/application/models/guards/api/isApiProductResponseAttributes.ts +85 -0
  154. package/src/application/models/guards/api/isApiProductSearchAttributes.ts +23 -0
  155. package/src/application/models/guards/api/isApiProductSearchFilterAttributes.ts +15 -0
  156. package/src/application/models/guards/api/isApiQueryTypedEventAttributes.ts +4 -0
  157. package/src/application/models/guards/api/isApiResponse.ts +39 -0
  158. package/src/application/models/guards/api/isApiReviewResponseAttributes.ts +30 -0
  159. package/src/application/models/guards/api/isApiReviewRichInformation.ts +37 -0
  160. package/src/application/models/guards/api/isApiSearchEventAttributes.ts +28 -0
  161. package/src/application/models/guards/api/isApiSuggestion.ts +36 -0
  162. package/src/application/models/guards/api/isApiSuggestionClickedEventAttributes.ts +9 -0
  163. package/src/application/models/guards/api/isApiTextResponseAttributes.ts +9 -0
  164. package/src/application/models/guards/api/isApiUserEvent.ts +25 -0
  165. package/src/application/models/guards/graphQL/isGraphQLColorsConfig.ts +50 -0
  166. package/src/application/models/guards/isBaseEcommerceEvent.ts +17 -0
  167. package/src/application/models/guards/isGA4EcommerceEvent.ts +17 -0
  168. package/src/application/models/guards/isLegacyUAEcommerceEvent.ts +17 -0
  169. package/src/application/models/guards/isMobilePLPChatPlacementParameter.ts +11 -0
  170. package/src/application/models/guards/isSpanxTakeAQuizCtaParameter.ts +4 -0
  171. package/src/application/models/guards/isVariantInfo.ts +37 -0
  172. package/src/application/models/guards/utils.ts +43 -0
  173. package/src/application/models/index.ts +20 -0
  174. package/src/application/models/localStorageEventListener.ts +4 -0
  175. package/src/application/models/message.ts +146 -0
  176. package/src/application/models/mobilePLPChatPlacementParameter.ts +3 -0
  177. package/src/application/models/orgsEnum.ts +36 -0
  178. package/src/application/models/productExperiment.ts +5 -0
  179. package/src/application/models/spanxTakeAQuizCtaParameter.ts +4 -0
  180. package/src/application/models/spiffyWidgets.ts +16 -0
  181. package/src/application/models/supportedOrgs.ts +137 -0
  182. package/src/application/models/utilityTypes/camelCase.ts +87 -0
  183. package/src/application/models/utilityTypes/camelCasedPropertiesDeep.ts +80 -0
  184. package/src/application/models/utilityTypes/delimiterCase.ts +121 -0
  185. package/src/application/models/utilityTypes/delimiterCasedPropertiesDeep.ts +98 -0
  186. package/src/application/models/utilityTypes/index.ts +1 -0
  187. package/src/application/models/utilityTypes/internal.ts +93 -0
  188. package/src/application/models/utilityTypes/primitive.ts +8 -0
  189. package/src/application/models/utilityTypes/snakeCasedPropertiesDeep.ts +49 -0
  190. package/src/application/models/utilityTypes/splitWords.ts +76 -0
  191. package/src/application/models/utilityTypes/trim.ts +28 -0
  192. package/src/application/models/utilityTypes/unknownArray.ts +25 -0
  193. package/src/application/models/utils/snakeToCamelTransformer.ts +90 -0
  194. package/src/application/models/utils/stringToFulfillmentDisplayStatusEnumValue.ts +68 -0
  195. package/src/application/models/validators/validateGraphQLColorsConfig.ts +29 -0
  196. package/src/application/models/validators/validateGraphQLFrontendConfig.ts +594 -0
  197. package/src/application/models/validators/validateGraphQLOrgId.ts +7 -0
  198. package/src/application/models/validators/validateMobilePLPChatPlacementParameter.ts +14 -0
  199. package/src/application/models/validators/validateOrgConfigResults.ts +47 -0
  200. package/src/application/models/validators/validateOrganizationConfig.ts +37 -0
  201. package/src/application/models/validators/validateResponse.ts +187 -0
  202. package/src/application/models/validators/validateSuggestion.ts +16 -0
  203. package/src/application/models/validators/validateUserEvent.ts +110 -0
  204. package/src/application/models/variantInfo/index.ts +1 -0
  205. package/src/application/models/variantInfo/pageVisitInfo.ts +6 -0
  206. package/src/application/models/variantInfo/plpInfo.ts +3 -0
  207. package/src/application/models/variantInfo/productInfo.ts +5 -0
  208. package/src/application/models/variantInfo/variantInfo.ts +23 -0
  209. package/src/application/service/cachingService.ts +84 -0
  210. package/src/application/service/cdnService.ts +18 -0
  211. package/src/application/service/customerService/index.ts +8 -0
  212. package/src/application/service/customerService/providers/UnsupportedCustomerService.ts +15 -0
  213. package/src/application/service/customerService/types.ts +31 -0
  214. package/src/application/service/domMutationObserver.ts +320 -0
  215. package/src/application/service/domMutations/GridInsertionService.ts +123 -0
  216. package/src/application/service/domMutations/dataLayer/dataLayerEventsListener.ts +99 -0
  217. package/src/application/service/domMutations/domInsertionService.ts +90 -0
  218. package/src/application/service/domMutations/domMutationListener.ts +15 -0
  219. package/src/application/service/domMutations/domMutationListenerState.ts +52 -0
  220. package/src/application/service/domMutations/floatingChat/embeddedChatsPlacementsListener.ts +41 -0
  221. package/src/application/service/domMutations/gladly/gladlyListener.ts +61 -0
  222. package/src/application/service/domMutations/spiffy/orgs/common/kustomerVisibilityListener.ts +41 -0
  223. package/src/application/service/domMutations/spiffy/orgs/common/orgsCommonDataLayerListener.ts +119 -0
  224. package/src/application/service/environmentService.ts +51 -0
  225. package/src/application/service/featureFlagService.ts +130 -0
  226. package/src/application/service/kustomerIntegrationService.ts +111 -0
  227. package/src/application/service/localStorageService.ts +77 -0
  228. package/src/application/service/pageVariantService.ts +779 -0
  229. package/src/application/service/searchService.ts +140 -0
  230. package/src/application/service/sessionStorageService.ts +27 -0
  231. package/src/application/service/shopifyUrlService.ts +63 -0
  232. package/src/application/service/userIdentityService.ts +114 -0
  233. package/src/application/service/windowChatToggleService.ts +71 -0
  234. package/src/application/service/windowDataLayerService.ts +181 -0
  235. package/src/application/service/windowFrontendConfigService.ts +104 -0
  236. package/src/application/utils/__tests__/divideArrays.test.ts +14 -0
  237. package/src/application/utils/analyticsUtils.ts +110 -0
  238. package/src/application/utils/coreContextToApiContext.ts +11 -0
  239. package/src/application/utils/coreUserEventToApiUserEvent.ts +106 -0
  240. package/src/application/utils/divideArray.ts +7 -0
  241. package/src/application/utils/domObserver.ts +96 -0
  242. package/src/application/utils/elementObserver.ts +246 -0
  243. package/src/application/utils/imageFilter.ts +12 -0
  244. package/src/application/utils/index.ts +3 -0
  245. package/src/application/utils/merchantUtils.ts +16 -0
  246. package/src/application/utils/messageFromFormSubmittedEvent.ts +31 -0
  247. package/src/application/utils/messageFromQueryEvent.ts +38 -0
  248. package/src/application/utils/messageFromResponse.ts +133 -0
  249. package/src/application/utils/messageFromSuggestionEvent.ts +32 -0
  250. package/src/application/utils/mouseEventTypes.ts +1 -0
  251. package/src/application/utils/mutationHelper.ts +51 -0
  252. package/src/application/utils/nextMessageRequestToApiRequest.ts +31 -0
  253. package/src/application/utils/nodeSelector.ts +133 -0
  254. package/src/application/utils/overrides.ts +196 -0
  255. package/src/application/utils/stringUtils.ts +55 -0
  256. package/src/application/utils/supportedEventRequestToApiRequest.ts +12 -0
  257. package/src/application/utils/urlsParser.ts +53 -0
  258. package/src/application/utils/validation.ts +5 -0
  259. package/src/atoms/app/index.ts +57 -0
  260. package/src/atoms/app/variant.ts +261 -0
  261. package/src/atoms/atomStore.ts +34 -0
  262. package/src/atoms/chat/chatState.ts +44 -0
  263. package/src/atoms/chat/form.ts +19 -0
  264. package/src/atoms/chat/index.ts +38 -0
  265. package/src/atoms/chat/lastMessage.ts +11 -0
  266. package/src/atoms/chat/messageQueue.ts +65 -0
  267. package/src/atoms/chat/performanceMetrics.ts +84 -0
  268. package/src/atoms/chat/renderedWidgetRefs.ts +28 -0
  269. package/src/atoms/chat/replies.ts +51 -0
  270. package/src/atoms/chat/suggestions.ts +36 -0
  271. package/src/atoms/globalSearch.ts +12 -0
  272. package/src/atoms/index.ts +5 -0
  273. package/src/atoms/org/customerService.ts +13 -0
  274. package/src/atoms/org/graphqlConfig.ts +27 -0
  275. package/src/atoms/org/index.ts +7 -0
  276. package/src/atoms/org/merchantCss.ts +44 -0
  277. package/src/atoms/org/org.ts +256 -0
  278. package/src/atoms/org/orgAnalyticsConfig.ts +28 -0
  279. package/src/atoms/org/orgPageConfig.ts +38 -0
  280. package/src/atoms/org/orgUIConfig.ts +122 -0
  281. package/src/atoms/search/chatSearch.ts +293 -0
  282. package/src/atoms/search/index.ts +2 -0
  283. package/src/atoms/search/productFilters.ts +207 -0
  284. package/src/atoms/search/productSorter.ts +23 -0
  285. package/src/atoms/search/searchAPI.ts +194 -0
  286. package/src/atoms/search/types.ts +55 -0
  287. package/src/atoms/search/utils.ts +18 -0
  288. package/src/config/divIds.ts +27 -0
  289. package/src/config/locators/components/chat/entrypoints.ts +13 -0
  290. package/src/config/locators/components/chat/index.ts +23 -0
  291. package/src/config/locators/components/chat/preview.ts +13 -0
  292. package/src/config/locators/components/chat/variants/index.ts +16 -0
  293. package/src/config/locators/components/common/buttons.ts +6 -0
  294. package/src/config/locators/components/common/cards.ts +18 -0
  295. package/src/config/locators/components/common/links.ts +1 -0
  296. package/src/config/locators/components/common/tables.ts +2 -0
  297. package/src/config/locators/components/floating-button.ts +2 -0
  298. package/src/config/locators/components/index.ts +3 -0
  299. package/src/config/locators/components/report-issue.ts +21 -0
  300. package/src/config/locators/components/search/index.ts +5 -0
  301. package/src/config/locators/components/shadow-dom.ts +1 -0
  302. package/src/config/locators/embedded.ts +21 -0
  303. package/src/config/locators/index.ts +3 -0
  304. package/src/config/socialProofClasses.ts +17 -0
  305. package/src/contexts/chatContext.tsx +451 -0
  306. package/src/contexts/enviveConfigContext.tsx +70 -0
  307. package/src/contexts/index.ts +4 -0
  308. package/src/contexts/systemSettingsContext.tsx +61 -0
  309. package/src/contexts/types.ts +1059 -0
  310. package/src/enabled-features.ts +83 -0
  311. package/src/events/event-types.ts +11 -0
  312. package/src/events/index.ts +52 -0
  313. package/src/events/registerAnalyticsListeners.ts +49 -0
  314. package/src/extension.ts +63 -0
  315. package/src/hooks/index.ts +22 -0
  316. package/src/hooks/useBlockBackButton.ts +29 -0
  317. package/src/hooks/useChatToggle.ts +66 -0
  318. package/src/hooks/useCustomerSupportHandoff.ts +39 -0
  319. package/src/hooks/useDebounce.ts +17 -0
  320. package/src/hooks/useDynamicVariants.ts +210 -0
  321. package/src/hooks/useElementObserver.ts +245 -0
  322. package/src/hooks/useFileUpload.ts +61 -0
  323. package/src/hooks/useGrabAndScroll.ts +133 -0
  324. package/src/hooks/useHideElements.ts +82 -0
  325. package/src/hooks/useHorizontalScrollAnimation.ts +115 -0
  326. package/src/hooks/useImageResolver.ts +51 -0
  327. package/src/hooks/useIntersection.ts +28 -0
  328. package/src/hooks/useIsSmallScreen.ts +23 -0
  329. package/src/hooks/useMessageFilter.ts +49 -0
  330. package/src/hooks/useMessageScrollObserver.ts +47 -0
  331. package/src/hooks/useReducedMotionWithOverride.ts +15 -0
  332. package/src/hooks/useSearch.tsx +433 -0
  333. package/src/hooks/useSnapCalculator.ts +38 -0
  334. package/src/hooks/useSnapControl.ts +155 -0
  335. package/src/hooks/useSystemSettingsContext.ts +12 -0
  336. package/src/hooks/useTrackComponentVisibleEvent.ts +52 -0
  337. package/src/hooks/useUpdateAnalyticsProps.ts +56 -0
  338. package/src/hooks/utils.ts +153 -0
  339. package/src/index.ts +31 -0
  340. package/src/initialize.ts +163 -0
  341. package/src/interceptors/types.ts +6 -0
  342. package/src/interceptors/useFormEscalation.ts +40 -0
  343. package/src/interceptors/useMessageInterceptor.ts +32 -0
  344. package/src/main.ts +85 -0
  345. package/src/main.tsx +123 -0
  346. package/src/merchants/bandolier/bandolier.ts +1389 -0
  347. package/src/merchants/carpe/carpe.ts +656 -0
  348. package/src/merchants/coterie/coterie.ts +280 -0
  349. package/src/merchants/default.ts +193 -0
  350. package/src/merchants/dreamlandBaby/dreamlandBaby.ts +375 -0
  351. package/src/merchants/fiveCbd/fiveCbd.ts +697 -0
  352. package/src/merchants/forLoveAndLemons/forLoveAndLemons.ts +721 -0
  353. package/src/merchants/greenpan/greenpan.ts +440 -0
  354. package/src/merchants/grooveLife/grooveLife.ts +386 -0
  355. package/src/merchants/homegrownCannabis/homegrownCannabis.ts +468 -0
  356. package/src/merchants/init-merchant.sh +53 -0
  357. package/src/merchants/jackArcher/jackArcher.ts +974 -0
  358. package/src/merchants/jordanCraig/jordanCraig.ts +1927 -0
  359. package/src/merchants/kindredBravely/kindredBravely.ts +529 -0
  360. package/src/merchants/kutFromTheKloth/kutFromTheKloth.ts +418 -0
  361. package/src/merchants/larryAndSerges/larryAndSerges.ts +314 -0
  362. package/src/merchants/leapsAndRebounds/leapsAndRebounds.ts +424 -0
  363. package/src/merchants/longevityrx/longevityrx.ts +368 -0
  364. package/src/merchants/lookOptic/lookOptic.ts +323 -0
  365. package/src/merchants/mantraBrand/mantraBrand.ts +838 -0
  366. package/src/merchants/medterra/medterra.ts +670 -0
  367. package/src/merchants/modells/modells.ts +546 -0
  368. package/src/merchants/pressedFloral/pressedFloral.ts +734 -0
  369. package/src/merchants/skinPerfection/skinPerfection.ts +379 -0
  370. package/src/merchants/snapSupplements/snapSupplements.ts +325 -0
  371. package/src/merchants/spanx/spanx.ts +810 -0
  372. package/src/merchants/spanx/spanxStaging.ts +942 -0
  373. package/src/merchants/supergoop/supergoop.ts +376 -0
  374. package/src/merchants/uniqueVintage/uniqueVintage.ts +1314 -0
  375. package/src/merchants/uniqueVintage/views/useUniqueVintageChatSearch.ts +147 -0
  376. package/src/merchants/venaCbd/venaCbd.ts +410 -0
  377. package/src/merchants/westonJonBoucher/westonJonBoucher.ts +473 -0
  378. package/src/merchants/wineEnthusiast/wineEnthusiast.ts +990 -0
  379. package/src/merchants/wolfMattress/wolfMattress.ts +411 -0
  380. package/src/merchants/wolfTactical/wolfTactical.ts +389 -0
  381. package/src/types/custservice-types.ts +28 -0
  382. package/src/types/search-filter-types.ts +111 -0
  383. package/src/types/suggestionBarV2-types.ts +4 -0
  384. package/src/types/test-types.ts +3 -0
  385. package/src/types.ts +66 -0
@@ -0,0 +1,155 @@
1
+ import {
2
+ MotionValue,
3
+ transform,
4
+ useAnimate,
5
+ useMotionValue,
6
+ useTransform,
7
+ ValueAnimationTransition,
8
+ } from 'framer-motion';
9
+ import { useMemo, useState } from 'react';
10
+ import { Unit, useSnapCalculator } from './useSnapCalculator';
11
+
12
+ type SnapControl = {
13
+ animationKey?: MotionValue;
14
+ animation: ValueAnimationTransition;
15
+ height: number;
16
+ unit: Unit;
17
+ snaps: number[];
18
+ initSnap: number;
19
+ threshold?: number;
20
+ overlayOpacity: number;
21
+ onSnapComplete: (currentSnap: number, nextSnap: number, collapsed: boolean) => void;
22
+ };
23
+
24
+ const MIDDLE_SNAP_OFFSET = 5;
25
+ const SNAP_DISTANCE_OFFSET = 50;
26
+
27
+ export const useSnapControl = ({
28
+ animationKey,
29
+ animation,
30
+ height,
31
+ unit,
32
+ snaps,
33
+ initSnap,
34
+ onSnapComplete,
35
+ overlayOpacity,
36
+ }: SnapControl) => {
37
+ const [scope, animate] = useAnimate();
38
+ const animatedY = animationKey || useMotionValue(-1);
39
+
40
+ const { swipeviewHeightPx, snapsToPixels, viewportHeightPx, getPixelToSnap, getSnapToPixel } =
41
+ useSnapCalculator(snaps, height, unit);
42
+
43
+ const contentHeight = useTransform(animatedY, [0, swipeviewHeightPx], [swipeviewHeightPx, 0]);
44
+
45
+ const snapOverlayReference = useMemo(
46
+ () => [
47
+ getSnapToPixel(snaps[0]),
48
+ getSnapToPixel(snaps[1]) - MIDDLE_SNAP_OFFSET,
49
+ getSnapToPixel(snaps[2]),
50
+ ],
51
+ [],
52
+ );
53
+
54
+ const displayOverlay = useTransform(() =>
55
+ animatedY.get() === -1
56
+ ? 'none'
57
+ : transform(animatedY.get(), snapOverlayReference, ['none', 'none', 'block']),
58
+ );
59
+
60
+ const opacityOverlay = useTransform(() =>
61
+ animatedY.get() === -1
62
+ ? 0
63
+ : transform(animatedY.get(), snapOverlayReference, [0, 0, overlayOpacity]),
64
+ );
65
+
66
+ const initSnapInPixels = snapsToPixels?.[initSnap];
67
+ const getInitSnap = () => snaps?.[initSnap];
68
+ const [currentSnap, setCurrentSnap] = useState<number>(getInitSnap());
69
+ const between = (x: number, min: number, max: number) => x >= min && x <= max;
70
+
71
+ const defineNextSnapByPosition = () => {
72
+ const scopeEl = scope.current;
73
+ const currentSnapRef = Math.abs(
74
+ viewportHeightPx - (swipeviewHeightPx - getSnapToPixel(currentSnap)),
75
+ );
76
+
77
+ const realGestureY =
78
+ scopeEl.getBoundingClientRect().y +
79
+ scopeEl.getBoundingClientRect().height -
80
+ (window.innerHeight - document.documentElement.clientHeight);
81
+
82
+ const isGoingUp = realGestureY < currentSnapRef;
83
+
84
+ const snapsToPixelsClone = Array.from(snapsToPixels);
85
+ isGoingUp
86
+ ? snapsToPixelsClone.sort((a, b) => b - a) /* desc*/
87
+ : snapsToPixelsClone.sort((a, b) => a - b); /* asc */
88
+
89
+ if (realGestureY != currentSnapRef) {
90
+ const snapReference = snapsToPixelsClone.find((snap) => {
91
+ const current = Math.abs(viewportHeightPx - (swipeviewHeightPx - snap));
92
+ return isGoingUp ? current < realGestureY : current > realGestureY;
93
+ });
94
+
95
+ if (snapReference === undefined) {
96
+ return snapsToPixelsClone.slice(-1)[0];
97
+ }
98
+
99
+ const prevSnapIndex = snapsToPixelsClone.indexOf(snapReference ?? -1);
100
+ const prevSnap = snapsToPixelsClone[prevSnapIndex - 1];
101
+ const prevSnapPx = Math.abs(viewportHeightPx - (swipeviewHeightPx - prevSnap));
102
+ const adjacentSnap = between(
103
+ realGestureY,
104
+ prevSnapPx - SNAP_DISTANCE_OFFSET,
105
+ prevSnapPx + SNAP_DISTANCE_OFFSET,
106
+ );
107
+
108
+ return adjacentSnap ? prevSnap : snapReference;
109
+ }
110
+
111
+ return getSnapToPixel(currentSnap);
112
+ };
113
+
114
+ const jumpTo = (snapPx: number) => {
115
+ const collapsed = snapPx === swipeviewHeightPx;
116
+ const nextSnap = getPixelToSnap(snapPx);
117
+ animate(
118
+ scope.current,
119
+ { y: snapPx },
120
+ {
121
+ ...animation,
122
+ onComplete: () => {
123
+ onSnapComplete(currentSnap, nextSnap, collapsed);
124
+ setCurrentSnap(nextSnap);
125
+ },
126
+ },
127
+ );
128
+
129
+ return {
130
+ nextSnap,
131
+ collapsed,
132
+ };
133
+ };
134
+
135
+ const resetControls = () => {
136
+ setCurrentSnap(getInitSnap());
137
+ return 0;
138
+ };
139
+
140
+ return {
141
+ scope,
142
+ animatedY,
143
+ animate,
144
+ swipeviewHeightPx,
145
+ initSnapInPixels,
146
+ contentHeight,
147
+ currentSnap,
148
+ displayOverlay,
149
+ opacityOverlay,
150
+ getSnapToPixel,
151
+ jumpTo,
152
+ defineNextSnapByPosition,
153
+ resetControls,
154
+ };
155
+ };
@@ -0,0 +1,12 @@
1
+ import { useContext } from 'react';
2
+ import { SystemSettingsContext } from 'src/contexts';
3
+
4
+ export const useSystemSettingsContext = () => {
5
+ const context = useContext(SystemSettingsContext);
6
+
7
+ if (!context) {
8
+ throw new Error('useSystemSettingsContext must be used within a SystemSettingsContextProvider');
9
+ }
10
+
11
+ return { ...context };
12
+ };
@@ -0,0 +1,52 @@
1
+ import { RefObject, useEffect, useRef } from 'react';
2
+ import { SpiffyWidgets } from 'src/application/models/spiffyWidgets';
3
+ import { useIntersection } from 'src/hooks/useIntersection';
4
+ import { AmplitudeAdapter, SpiffyMetricsEventName } from 'src/adapters/amplitude';
5
+
6
+ /**
7
+ * Tracks a component and logs an event to Amplitude when the component is visible.
8
+ *
9
+ * @param component - The component to track.
10
+ * @param element - The element to track visibility of.
11
+ * @param eventProps - Additional properties to include with the event.
12
+ * @param eventName - The Amplitude event name to track (defaults to ChatComponentVisible).
13
+ */
14
+ export const useTrackComponentVisibleEvent = (
15
+ component: SpiffyWidgets,
16
+ element: RefObject<HTMLElement>,
17
+ eventProps?: Record<string, unknown>,
18
+ eventName: SpiffyMetricsEventName = SpiffyMetricsEventName.ChatComponentVisible,
19
+ ) => {
20
+ const isVisible = useIntersection(element, '0px');
21
+ const hasTrackedEvent = useRef(false);
22
+
23
+ const componentProps = (() => {
24
+ if (eventName === SpiffyMetricsEventName.ChatComponentVisible) {
25
+ return {
26
+ chat_component: component,
27
+ ...eventProps,
28
+ };
29
+ }
30
+ if (eventName === SpiffyMetricsEventName.SearchComponentVisible) {
31
+ return {
32
+ search_component: component,
33
+ ...eventProps,
34
+ };
35
+ }
36
+ // Default case for other event types
37
+ return {
38
+ component: component,
39
+ ...eventProps,
40
+ };
41
+ })();
42
+
43
+ useEffect(() => {
44
+ if (isVisible && !hasTrackedEvent.current) {
45
+ AmplitudeAdapter.trackEvent({
46
+ eventName: eventName,
47
+ eventProps: componentProps,
48
+ });
49
+ hasTrackedEvent.current = true;
50
+ }
51
+ }, [isVisible, component, eventProps, eventName, componentProps]);
52
+ };
@@ -0,0 +1,56 @@
1
+ import { useAtomValue } from 'jotai';
2
+ import { useEffect, useRef } from 'react';
3
+ import { AmplitudeAdapter, SpiffyMetricsEventName } from 'src/adapters/amplitude';
4
+ import { hasParsedVariantInfoAtom, variantInfoAtom } from 'src/atoms/app/variant';
5
+
6
+ /**
7
+ * Updates the default analytics properties whenever the variant info changes. This hook also
8
+ * triggers any events that should be sent once per page visit.
9
+ */
10
+ export const useUpdateAnalyticsProps = () => {
11
+ const variantInfo = useAtomValue(variantInfoAtom);
12
+ const amplitudeAdapterRef = useRef<AmplitudeAdapter | null>(null);
13
+ const hasInitialized = useRef(false);
14
+ const hasParsedVariantInfo = useAtomValue(hasParsedVariantInfoAtom);
15
+
16
+ useEffect(() => {
17
+ if (!amplitudeAdapterRef.current) {
18
+ amplitudeAdapterRef.current = AmplitudeAdapter.getSingletonInstanceOf();
19
+ }
20
+
21
+ const variantInfoWithPrefix = Object.fromEntries(
22
+ Object.entries(variantInfo).map(([key, value]) => [`variantInfo.${key}`, value]),
23
+ );
24
+
25
+ const defaultEventProperties: Record<string, unknown> = {
26
+ page_variant: variantInfo.variant, // TODO: should be removed over time, after migration
27
+ ...variantInfoWithPrefix,
28
+ };
29
+
30
+ // TODO: should be removed over time, after migration
31
+ if (variantInfo.variant === 'pdp') {
32
+ defaultEventProperties.product_id = variantInfo.productId;
33
+ }
34
+
35
+ // TODO: should be removed over time, after migration
36
+ if (variantInfo.variant === 'plp') {
37
+ defaultEventProperties.plp_id = variantInfo.plpId;
38
+ }
39
+
40
+ // TODO: should be removed over time, after migration
41
+ if (variantInfo.variant === 'page_visit') {
42
+ defaultEventProperties.page_visit_category = variantInfo.pageVisitCategory;
43
+ defaultEventProperties.page_visit_url = variantInfo.url;
44
+ }
45
+
46
+ amplitudeAdapterRef.current?.setSupplementalDefaultProps(defaultEventProperties);
47
+
48
+ // put any events that should be sent once per page visit here
49
+ if (!hasInitialized.current && hasParsedVariantInfo) {
50
+ AmplitudeAdapter.trackEvent({
51
+ eventName: SpiffyMetricsEventName.BundleLoaded,
52
+ });
53
+ hasInitialized.current = true;
54
+ }
55
+ }, [variantInfo, hasParsedVariantInfo]);
56
+ };
@@ -0,0 +1,153 @@
1
+ import {
2
+ PLPAttributeCategory,
3
+ UserEventCategory,
4
+ } from "@spiffy-ai/commerce-api-client";
5
+ import { SearchResult } from "src/application/models/api/search";
6
+ import { UserEvent, VariantInfo } from "src/application/models";
7
+ import { v4 as uuid } from "uuid";
8
+
9
+ export const isElementPartiallyVisible = (el?: HTMLDivElement | null) => {
10
+ if (!el) return false;
11
+
12
+ const rect = el.getBoundingClientRect();
13
+ const windowHeight =
14
+ window.innerHeight || document.documentElement.clientHeight;
15
+ const windowWidth = window.innerWidth || document.documentElement.clientWidth;
16
+ const verticallyVisible =
17
+ Math.round(rect.top) < windowHeight && Math.round(rect.bottom) > 0;
18
+ const horizontallyVisible =
19
+ Math.round(rect.left) < windowWidth && Math.round(rect.right) > 0;
20
+ return verticallyVisible && horizontallyVisible;
21
+ };
22
+
23
+ export const createAppLoadedEvent = (): UserEvent => ({
24
+ eventId: uuid(),
25
+ createdAt: new Date().toISOString(),
26
+ category: UserEventCategory.AppLoaded,
27
+ });
28
+
29
+ export const createVisitUserEvent = ({
30
+ variantInfo,
31
+ }: {
32
+ variantInfo: VariantInfo;
33
+ }): UserEvent | undefined => {
34
+ // this is a pdp visit event
35
+ if (variantInfo.variant === "pdp" && variantInfo.productId != null) {
36
+ return {
37
+ eventId: uuid(),
38
+ createdAt: new Date().toISOString(),
39
+ category: UserEventCategory.PdpVisit,
40
+ attributes: {
41
+ productId: variantInfo.productId,
42
+ parentProductId: variantInfo.parentProductId ?? "",
43
+ url: variantInfo.url ?? "",
44
+ },
45
+ };
46
+ }
47
+
48
+ // this is a plp visit event
49
+ if (variantInfo.variant === "plp" && variantInfo.plpId != null) {
50
+ return {
51
+ eventId: uuid(),
52
+ createdAt: new Date().toISOString(),
53
+ category: UserEventCategory.PlpVisit,
54
+ attributes: {
55
+ category: PLPAttributeCategory.Id,
56
+ attributes: {
57
+ id: variantInfo.plpId,
58
+ },
59
+ },
60
+ };
61
+ }
62
+
63
+ if (variantInfo.variant === "page_visit") {
64
+ return {
65
+ eventId: uuid(),
66
+ createdAt: new Date().toISOString(),
67
+ category: UserEventCategory.PageVisit,
68
+ attributes: {
69
+ url: variantInfo.url,
70
+ pageVisitCategory: variantInfo.pageVisitCategory,
71
+ },
72
+ };
73
+ }
74
+ return undefined;
75
+ };
76
+
77
+ const parseTime = (time: string, timeZone: string) => {
78
+ const times = time.match(/^([0-1]?\d):([0-5]\d)(AM|PM)$/i);
79
+ const hours = times?.[1];
80
+ const minutes = times?.[2];
81
+ const period = times?.[3];
82
+
83
+ if (hours && minutes && period) {
84
+ const date = new Date();
85
+
86
+ // Adjust hours for AM/PM
87
+ let adjustedHours = 0;
88
+ if (period.toUpperCase() === "PM" && hours !== "12") {
89
+ adjustedHours = parseInt(hours) + 12;
90
+ }
91
+
92
+ if (period.toUpperCase() === "AM" && hours !== "12") {
93
+ adjustedHours = parseInt(hours);
94
+ }
95
+
96
+ // Create the date string with time zone
97
+ const formattedDate = `${date.toISOString().split("T")[0]}T${String(
98
+ adjustedHours
99
+ ).padStart(2, "0")}:${minutes}:00`;
100
+ return new Date(`${formattedDate}${timeZone}`);
101
+ }
102
+ };
103
+
104
+ export const isWithinBusinessHours = (
105
+ startTime: string,
106
+ endTime: string,
107
+ timeZone: string
108
+ ) => {
109
+ // Parse start and end times
110
+ const start = parseTime(startTime, timeZone);
111
+ let end = parseTime(endTime, timeZone);
112
+
113
+ if (!start || !end) {
114
+ return false;
115
+ }
116
+
117
+ let now = new Date();
118
+
119
+ // If the end date is greater than the start date, add a day to both of them
120
+ // This handles configurations such as startTime = 10:00PM and endTime = 7:00AM
121
+ if (end < start) {
122
+ end = new Date(end.getTime() + 24 * 60 * 60 * 1000);
123
+ now = new Date(now.getTime() + 24 * 60 * 60 * 1000);
124
+ }
125
+
126
+ // If the date conversion shifts the end date to the next day, consider comparing it across midnight
127
+ if (end.getUTCDate() > start.getUTCDate()) {
128
+ const crossingMidnight = new Date(now.getTime() + 24 * 60 * 60 * 1000);
129
+ return start <= now || crossingMidnight <= end;
130
+ }
131
+
132
+ // Check if the current time falls between start and end
133
+ return now >= start && now <= end;
134
+ };
135
+
136
+ export const enum SearchResultsState {
137
+ Loading,
138
+ Results,
139
+ NoResults,
140
+ }
141
+
142
+ export const getSearchResultsState = (
143
+ isLoadingSearch: boolean,
144
+ searchData: SearchResult | null
145
+ ): SearchResultsState => {
146
+ if (isLoadingSearch) {
147
+ return SearchResultsState.Loading;
148
+ }
149
+ if (searchData) {
150
+ return SearchResultsState.Results;
151
+ }
152
+ return SearchResultsState.NoResults;
153
+ };
package/src/index.ts ADDED
@@ -0,0 +1,31 @@
1
+ import Logger from 'src/application/logging/logger';
2
+ import { EnvironmentService } from 'src/application/service/environmentService';
3
+ import { getAtomStore } from 'src/atoms/atomStore';
4
+ import {
5
+ appInitialStartTimeMsAtom,
6
+ pageLoadOffsetTimeAtom,
7
+ } from 'src/atoms/chat';
8
+ import { init } from 'src/initialize';
9
+
10
+ // store the initial start time of the app in session storage. This is used to calculate
11
+ // deltas for performance metrics downstream.
12
+ const atomStore = getAtomStore();
13
+ const appInitialStartTimeMs = Date.now();
14
+ const pageLoadOffsetTime = window.performance?.now();
15
+
16
+ Logger.logDebug(
17
+ `[spiffy-ai] storing appInitialStartTimeMs=${appInitialStartTimeMs} - offset ${pageLoadOffsetTime}`,
18
+ );
19
+ atomStore.set(appInitialStartTimeMsAtom, appInitialStartTimeMs.toString());
20
+ atomStore.set(pageLoadOffsetTimeAtom, pageLoadOffsetTime.toString());
21
+
22
+ const initApp = async () => {
23
+ const existing = window[EnvironmentService.getIdentifyingPrefix()] || {};
24
+ window[EnvironmentService.getIdentifyingPrefix()] = {
25
+ ...existing,
26
+ init,
27
+ };
28
+ await init();
29
+ };
30
+
31
+ initApp();
@@ -0,0 +1,163 @@
1
+ import Logger from "src/application/logging/logger";
2
+ // this import brings in amplitude and a bunch of other large libraries
3
+ import { EnvironmentService } from "src/application/service/environmentService";
4
+ import {
5
+ LocalStorageKeys,
6
+ LocalStorageService,
7
+ } from "src/application/service/localStorageService";
8
+ import { UserIdentityService } from "src/application/service/userIdentityService";
9
+ import { initWindowFrontendConfigOverridesApplyFunction } from "src/application/service/windowFrontendConfigService";
10
+ import {
11
+ initAmplitude,
12
+ initDataLayerWrapper,
13
+ } from "src/application/utils/analyticsUtils";
14
+ import { getAtomStore } from "src/atoms/atomStore";
15
+ import {
16
+ apiKeyAtom,
17
+ featureFlagServiceAtom,
18
+ getAsyncOrgConfig,
19
+ } from "src/atoms/org/org";
20
+ import { EnabledFeatures } from "src/enabled-features";
21
+ import {
22
+ EXTENSION_ID,
23
+ tellExtensionAboutInjectionError,
24
+ tellExtensionInjectionIsLoading,
25
+ } from "src/extension";
26
+
27
+ const handleSpiffyOn = () => {
28
+ const spiffyOn = new URLSearchParams(window.location.search).get(
29
+ LocalStorageKeys.SpiffyOnOverride
30
+ );
31
+ const enviveOn = new URLSearchParams(window.location.search).get(
32
+ LocalStorageKeys.EnviveOnOverride
33
+ );
34
+
35
+ const isOn = spiffyOn === "true" || enviveOn === "true";
36
+ if (spiffyOn == null && enviveOn == null) {
37
+ return;
38
+ }
39
+
40
+ if (isOn === true) {
41
+ LocalStorageService.setSpiffyOnFeatureFlag(true);
42
+ return;
43
+ }
44
+
45
+ LocalStorageService.setSpiffyOnFeatureFlag(false);
46
+ // Do nothing for missing or other values
47
+ };
48
+
49
+ const getEntryPoint = (): string => {
50
+ // If `spiffy_main_file` query param is set - use an alternate file for injection
51
+ const queryParamName = `${EnvironmentService.getIdentifyingPrefix()}_main_file`;
52
+ const overrideParam = new URLSearchParams(window.location.search).get(
53
+ queryParamName
54
+ );
55
+ if (overrideParam) {
56
+ return overrideParam;
57
+ }
58
+ // #if (VITE_IS_LOCAL_ENV=="true")
59
+ return "/src/main.tsx";
60
+ // #else
61
+ return new URL("./main.js", import.meta.url).toString();
62
+ // #endif
63
+ };
64
+
65
+ const loadAndInit = async () => {
66
+ // #if (VITE_SPLIT_BUILD=="true")
67
+ const script = document.createElement("script");
68
+ script.innerHTML = `
69
+ import('${getEntryPoint()}').then(async ({ initApp, tellExtensionAboutInjectionError }) => {
70
+ try {
71
+ if (document.readyState === 'loading') {
72
+ console.log('[spiffy-ai] document.body is not defined, waiting for DOMContentLoaded');
73
+ document.addEventListener('DOMContentLoaded', initApp);
74
+ } else {
75
+ await initApp();
76
+ }
77
+ } catch (e) {
78
+ await tellExtensionAboutInjectionError(e);
79
+ }
80
+ }).catch(async (e) => {
81
+ if (window.chrome && window.chrome.runtime) {
82
+ await window.chrome.runtime.sendMessage(
83
+ '${EXTENSION_ID}',
84
+ { msg: "spiffy-extension-info-update", error: e.message, isLoading: false, isInjected: false },
85
+ );
86
+ }
87
+ })`;
88
+ script.type = "module";
89
+ script.id = "spiffy-injection-script";
90
+ document.head.appendChild(script);
91
+ // #else
92
+ const { initApp } = await import("./main.tsx");
93
+ await initApp();
94
+ // #endif
95
+ };
96
+
97
+ /**
98
+ * Checks if Spiffy is enabled for the current merchant and initializes the main bundle.
99
+ * If Spiffy is disabled, it initializes analytics only.
100
+ *
101
+ * @param apiKeyOverride - Optional API key to use instead of the key configured for the
102
+ * merchant. This should only be used for local development to toggle between different
103
+ * merchants.
104
+ *
105
+ * @returns True if Spiffy is enabled, false otherwise.
106
+ */
107
+ export const init = async (apiKeyOverride?: string) => {
108
+ if (window[EnvironmentService.getIdentifyingPrefix()]?.isInitialized) {
109
+ Logger.logDebug(`[spiffy-ai] Spiffy is already initialized`);
110
+ return true;
111
+ }
112
+
113
+ try {
114
+ await tellExtensionInjectionIsLoading();
115
+
116
+ handleSpiffyOn();
117
+ const atomStore = getAtomStore();
118
+ const apiKey = apiKeyOverride ?? atomStore.get(apiKeyAtom);
119
+ const orgConfig = await getAsyncOrgConfig(apiKey);
120
+
121
+ if (!orgConfig.org) {
122
+ throw new Error("orgConfig is required but is undefined");
123
+ }
124
+
125
+ if (!window._spiffy) {
126
+ window._spiffy = {};
127
+ }
128
+
129
+ const featureFlagService = atomStore.get(featureFlagServiceAtom);
130
+
131
+ const enabledFeatures = await EnabledFeatures.get(
132
+ orgConfig,
133
+ featureFlagService
134
+ );
135
+
136
+ // Force initialization of the AmplitudeAdapter now,
137
+ // so that we automatically immediately send a Page Viewed event,
138
+ // regardless of whether Spiffy is enabled or not.
139
+ initAmplitude();
140
+ initDataLayerWrapper();
141
+ // Attach a function so callers can explicitly apply overrides to FrontendConfig
142
+ initWindowFrontendConfigOverridesApplyFunction();
143
+ await UserIdentityService.identifyUser();
144
+
145
+ if (enabledFeatures.envive) {
146
+ // #if (VITE_IS_CODE_SPLIT_BUILD=="true")
147
+ const { initApp } = await import("./main");
148
+ await initApp();
149
+ // #else
150
+ await loadAndInit();
151
+ // #endif
152
+ return true;
153
+ }
154
+
155
+ await tellExtensionAboutInjectionError({
156
+ message: "Spiffy is disabled",
157
+ } as Error);
158
+ return false;
159
+ } catch (error: any) {
160
+ await tellExtensionAboutInjectionError(error);
161
+ throw error;
162
+ }
163
+ };
@@ -0,0 +1,6 @@
1
+ import { Response } from 'src/application/models';
2
+
3
+ export interface MessageInterceptor {
4
+ execute: (response: Response) => void | Promise<void>;
5
+ blockExecution: () => boolean;
6
+ }
@@ -0,0 +1,40 @@
1
+ import { FormType, ResponseCategory } from '@spiffy-ai/commerce-api-client';
2
+ import { useAtomValue, useSetAtom } from 'jotai';
3
+ import { Response } from 'src/application/models';
4
+ import { handleFormSubmittedAtom } from 'src/atoms/chat';
5
+ import { apiKeyAtom, endpointURLAtom } from 'src/atoms/org/org';
6
+ import { orgCustomerServiceService } from 'src/atoms/org/orgUIConfig';
7
+ import { MessageInterceptor } from './types';
8
+
9
+ export const useFormEscalation = (): MessageInterceptor => {
10
+ const handleFormSubmitted = useSetAtom(handleFormSubmittedAtom);
11
+ const customerServiceIntegration = useAtomValue(orgCustomerServiceService);
12
+ const apiKey = useAtomValue(apiKeyAtom);
13
+ const apiEndpoint = useAtomValue(endpointURLAtom);
14
+
15
+ const blockExecution = () => true;
16
+
17
+ const execute = async (response: Response) => {
18
+ if (
19
+ response.category === ResponseCategory.Form &&
20
+ response.attributes.formCategory?.formType === FormType.Escalation
21
+ ) {
22
+ const isEnabled = customerServiceIntegration.isEnabled();
23
+ const isBusinessHours = await customerServiceIntegration.isBusinessHours(apiKey, apiEndpoint);
24
+
25
+ handleFormSubmitted({
26
+ formResponseId: response.id,
27
+ formType: FormType.Escalation,
28
+ filledSchema: {
29
+ is_in_business_hours: isBusinessHours,
30
+ is_integration_enabled: isEnabled,
31
+ },
32
+ });
33
+ }
34
+ };
35
+
36
+ return {
37
+ execute,
38
+ blockExecution,
39
+ };
40
+ };