@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,52 @@
1
+ import { DomMutationListener } from './domMutationListener';
2
+ import { DomMutationObserverContinuation } from '../../models/domMutationContinuation';
3
+
4
+ class DomMutationListenerState {
5
+
6
+ private readonly listener: DomMutationListener;
7
+
8
+ private currentState: DomMutationObserverContinuation;
9
+
10
+ private attached: boolean;
11
+
12
+ private currentTryCount: number;
13
+
14
+ constructor(listener: DomMutationListener) {
15
+ this.listener = listener;
16
+ this.currentState = DomMutationObserverContinuation.CONTINUE;
17
+ this.attached = false;
18
+ this.currentTryCount = 0;
19
+ }
20
+
21
+ getListener(): DomMutationListener {
22
+ return this.listener;
23
+ }
24
+
25
+ setCurrentState(state: DomMutationObserverContinuation): void {
26
+ this.currentState = state;
27
+ }
28
+
29
+ getCurrentState(): DomMutationObserverContinuation {
30
+ return this.currentState;
31
+ }
32
+
33
+ getIsAttached(): boolean {
34
+ return this.attached;
35
+ }
36
+
37
+ setIsAttached(attached: boolean): void {
38
+ this.attached = attached;
39
+ }
40
+
41
+ getCurrentTryCount(): number {
42
+ return this.currentTryCount;
43
+ }
44
+
45
+ incrementCurrentTryCount(): void {
46
+ this.currentTryCount++;
47
+ }
48
+ }
49
+
50
+ export {
51
+ DomMutationListenerState
52
+ }
@@ -0,0 +1,41 @@
1
+ import { DomMutationListener } from '../domMutationListener';
2
+ import { DomMutationObserverContinuation } from '../../../models/domMutationContinuation';
3
+ import Logger from '../../../logging/logger';
4
+
5
+ class EmbeddedChatsPlacementsListener implements DomMutationListener {
6
+
7
+ private readonly findPlacementNodes: () => DomMutationObserverContinuation;
8
+
9
+ constructor(
10
+ findPlacementNodes: () => DomMutationObserverContinuation
11
+ ) {
12
+ Logger.logDebug('[spiffy-ai] EmbeddedChatsPlacementsListener created', undefined);
13
+ this.findPlacementNodes = findPlacementNodes;
14
+ }
15
+
16
+ runOnceImmediately(): boolean {
17
+ return true;
18
+ }
19
+
20
+ onDomChange(): DomMutationObserverContinuation {
21
+ // Too verbose - Logger.logDebug('[spiffy-ai] EmbeddedChatsPlacementsListener onDomChange', undefined);
22
+ const continuation = this.findPlacementNodes();
23
+ if (continuation === DomMutationObserverContinuation.STOP) {
24
+ Logger.logDebug('[spiffy-ai] EmbeddedChatsPlacementsListener [STOP requested]', undefined);
25
+ }
26
+ return continuation;
27
+ }
28
+
29
+ getName(): string {
30
+ return 'EmbeddedChatsPlacementsListener';
31
+ }
32
+
33
+ triesMax(): number {
34
+ return -1;
35
+ }
36
+ }
37
+
38
+
39
+ export {
40
+ EmbeddedChatsPlacementsListener,
41
+ };
@@ -0,0 +1,61 @@
1
+ import Logger from '../../../logging/logger';
2
+ import { DomMutationObserverContinuation } from '../../../models/domMutationContinuation';
3
+ import { DomMutationListener } from '../domMutationListener';
4
+
5
+ declare global {
6
+ interface Window {
7
+ Gladly: {
8
+ show: () => void;
9
+ getUser: () => { identity: string } | undefined;
10
+ getAvailability: () => string;
11
+ on: (eventName: string, callback: () => void) => void;
12
+ };
13
+ }
14
+ }
15
+
16
+ class GladlyListener implements DomMutationListener {
17
+ private readonly onGladlyAvailable: () => void;
18
+
19
+ private static readonly GLADLY_RETRIES_MAX = 25;
20
+
21
+ private static readonly GLADLY_CONVERSATION_STARTED_EVENT_NAME = 'conversation:started';
22
+
23
+ constructor(onGladlyAvailable: () => void) {
24
+ Logger.logDebug('[spiffy-ai] GladlyListener created', undefined);
25
+ this.onGladlyAvailable = onGladlyAvailable;
26
+ }
27
+
28
+ runOnceImmediately(): boolean {
29
+ return false;
30
+ }
31
+
32
+ triesMax(): number {
33
+ return GladlyListener.GLADLY_RETRIES_MAX;
34
+ }
35
+
36
+ onDomChange(): DomMutationObserverContinuation {
37
+ if (
38
+ window.Gladly &&
39
+ window.Gladly.getUser != null &&
40
+ window.Gladly.on != null &&
41
+ window.Gladly.show != null
42
+ ) {
43
+ Logger.logDebug(
44
+ `[spiffy-ai] subscribing to Gladly ${GladlyListener.GLADLY_CONVERSATION_STARTED_EVENT_NAME} event`,
45
+ );
46
+ window.Gladly.on(
47
+ GladlyListener.GLADLY_CONVERSATION_STARTED_EVENT_NAME,
48
+ this.onGladlyAvailable,
49
+ );
50
+ return DomMutationObserverContinuation.STOP;
51
+ }
52
+
53
+ return DomMutationObserverContinuation.CONTINUE;
54
+ }
55
+
56
+ getName(): string {
57
+ return 'GladlyListener';
58
+ }
59
+ }
60
+
61
+ export { GladlyListener };
@@ -0,0 +1,41 @@
1
+ import Logger from 'src/application/logging/logger';
2
+ import { DomMutationObserverContinuation } from 'src/application/models/domMutationContinuation';
3
+ import { DomMutationListener } from 'src/application/service/domMutations/domMutationListener';
4
+ import { KustomerIntegrationService } from 'src/application/service/kustomerIntegrationService';
5
+
6
+ class KustomerVisibilityListener implements DomMutationListener {
7
+ kustomerIntegrationService: KustomerIntegrationService;
8
+
9
+ constructor() {
10
+ Logger.logDebug('[spiffy-ai] KustomerVisibilityListener created');
11
+ this.kustomerIntegrationService = new KustomerIntegrationService();
12
+ }
13
+
14
+ runOnceImmediately(): boolean {
15
+ return true;
16
+ }
17
+
18
+ triesMax(): number {
19
+ return -1;
20
+ }
21
+
22
+ disconnect(): void {
23
+ this.kustomerIntegrationService.disconnect();
24
+ }
25
+
26
+ onDomChange(): DomMutationObserverContinuation {
27
+ this.kustomerIntegrationService.initOnce();
28
+
29
+ if (this.kustomerIntegrationService.updateVisibility()) {
30
+ return DomMutationObserverContinuation.STOP;
31
+ }
32
+
33
+ return DomMutationObserverContinuation.CONTINUE;
34
+ }
35
+
36
+ getName(): string {
37
+ return 'KustomerVisibilityListener';
38
+ }
39
+ }
40
+
41
+ export { KustomerVisibilityListener };
@@ -0,0 +1,119 @@
1
+ import Logger from 'src/application/logging/logger';
2
+ import { OrgAnalyticsConfig } from 'src/application/models/api/orgAnalyticsConfig';
3
+ import { DataLayerEventsListener } from 'src/application/service/domMutations/dataLayer/dataLayerEventsListener';
4
+ import { ChatElementDisplayLocation } from 'src/application/models/chatElementDisplayLocation';
5
+ import { GoogleAnalyticsEvents } from 'src/application/models/googleAnalyticsEvents';
6
+ import { AmplitudeAdapter, SpiffyMetricsEventName } from 'src/adapters/amplitude';
7
+
8
+ /*
9
+ Event Example:
10
+ {
11
+ "event":"add_to_cart",
12
+ "ecommerce":{
13
+ "currency":"USD",
14
+ "value":196,
15
+ "items":[
16
+ {
17
+ "item_name":"OnCore Open-Bust Mid-Thigh Bodysuit",
18
+ "price":98,
19
+ "item_brand":"Spanx",
20
+ "item_variant":"Very Black / Regular / M",
21
+ "index":0,
22
+ "item_id":39773564534995,
23
+ "quantity":2,
24
+ "item_category":"Shapewear",
25
+ "item_list_name":"Shapewear",
26
+ "item_list_id":"",
27
+ "item_colors":"Very Black",
28
+ "item_inseam_length":"",
29
+ "item_size":"M",
30
+ "item_band_size":"",
31
+ "item_cup_size":""
32
+ }
33
+ ]
34
+ },
35
+ "gtm.uniqueEventId":379
36
+ }
37
+ */
38
+ class OrgsCommonDataLayerListener {
39
+ private static dataLayerCache: { [p: string]: DataLayerEventsListener } = {};
40
+
41
+ static resetDataLayerCache() {
42
+ OrgsCommonDataLayerListener.dataLayerCache = {};
43
+ }
44
+
45
+ static getSingletonDataLayerListenerCallbackCombo(
46
+ orgShortName: string,
47
+ orgAnalyticsConfig: OrgAnalyticsConfig,
48
+ ) {
49
+ // dataLayer event listener and the onMetricsContextInit are tightly coupled to each other. So
50
+ // repeated calls to this function MUST return the same instance of the listener and the callback
51
+ // combo. PM 01/27/2024
52
+
53
+ if (!orgAnalyticsConfig.googleAnalytics) {
54
+ Logger.logError(
55
+ `[spiffy-ai] Google Analytics config is required for dataLayer event listener`,
56
+ orgAnalyticsConfig,
57
+ );
58
+ return undefined;
59
+ }
60
+
61
+ const allCachedDataLayerListeners = Object.keys(
62
+ OrgsCommonDataLayerListener.dataLayerCache,
63
+ )?.length;
64
+ if (allCachedDataLayerListeners > 1) {
65
+ // This is expected to be always == 1 max. If it is more than 1, then there is a bug in the code.
66
+ Logger.logError(
67
+ `[spiffy-ai] dataLayer listeners cache size: ${allCachedDataLayerListeners}`,
68
+ OrgsCommonDataLayerListener.dataLayerCache,
69
+ );
70
+ }
71
+
72
+ if (OrgsCommonDataLayerListener.dataLayerCache[orgShortName]) {
73
+ const dataLayerListener = OrgsCommonDataLayerListener.dataLayerCache[orgShortName];
74
+ return { dataLayerListener };
75
+ }
76
+
77
+ const callback = (event: object) => {
78
+ Logger.logDebug(`[spiffy-ai] dataLayer event:`, event);
79
+ if (
80
+ // @ts-expect-error: event is not typed
81
+ event?.event !== GoogleAnalyticsEvents.ADD_TO_CART_v1 &&
82
+ // @ts-expect-error: event is not typed
83
+ event?.event !== GoogleAnalyticsEvents.ADD_TO_CART_v2
84
+ ) {
85
+ Logger.logDebug(`[spiffy-ai] dataLayer [pass-through] event. event_not_captured=`, event);
86
+ return;
87
+ }
88
+
89
+ // @ts-expect-error: event is not typed
90
+ const items = event?.ecommerce?.items || event?.items;
91
+ const itemIdList = items?.map((item: any) => item?.item_id).filter((id: any) => id);
92
+ const itemCategoryList = items
93
+ ?.map((item: any) => item?.item_category)
94
+ .filter((category: any) => category);
95
+ const eventProps = {
96
+ 'ecommerce.item_id_list': itemIdList,
97
+ 'ecommerce.item_category_list': itemCategoryList,
98
+ display_location: ChatElementDisplayLocation.UNSPECIFIED,
99
+ };
100
+ AmplitudeAdapter.trackEvent({
101
+ eventName: SpiffyMetricsEventName.AddToCartClicked,
102
+ eventProps,
103
+ alsoSendToGoogleAnalytics: true,
104
+ });
105
+ };
106
+
107
+ const dataLayerListener = new DataLayerEventsListener(
108
+ callback,
109
+ [GoogleAnalyticsEvents.ADD_TO_CART_v1, GoogleAnalyticsEvents.ADD_TO_CART_v2],
110
+ orgAnalyticsConfig.googleAnalytics,
111
+ );
112
+
113
+ OrgsCommonDataLayerListener.dataLayerCache[orgShortName] = dataLayerListener;
114
+
115
+ return { dataLayerListener };
116
+ }
117
+ }
118
+
119
+ export { OrgsCommonDataLayerListener };
@@ -0,0 +1,51 @@
1
+ import { ContextSourceEnum } from "@spiffy-ai/commerce-api-client";
2
+ import { LocalStorageService } from "./localStorageService";
3
+ import { useEnviveConfig } from "src/contexts/enviveConfigContext";
4
+
5
+ class EnvironmentService {
6
+ static getApiEndpoint() {
7
+ const { baseUrl } = useEnviveConfig();
8
+ return baseUrl || "https://commerce-api.dev.spiffy.ai";
9
+ }
10
+
11
+ static getContextSource(): ContextSourceEnum {
12
+ // detect if we're in a storybook context. this is set up in preview.ts
13
+ if (window.IS_STORYBOOK) {
14
+ return ContextSourceEnum.Test;
15
+ }
16
+
17
+ const { contextSource } = useEnviveConfig();
18
+ if (contextSource) {
19
+ return contextSource as ContextSourceEnum;
20
+ }
21
+
22
+ const spiffyOnFeatureFlagSet = LocalStorageService.getSpiffyOnFeatureFlag();
23
+ if (spiffyOnFeatureFlagSet === "true") {
24
+ return ContextSourceEnum.Playground;
25
+ }
26
+
27
+ return ContextSourceEnum.App;
28
+ }
29
+
30
+ static getIdentifyingPrefix(): string {
31
+ return "spiffy";
32
+ }
33
+
34
+ static getEnvironment = () => {
35
+ const { env } = useEnviveConfig();
36
+
37
+ if (!env) {
38
+ return "dev";
39
+ }
40
+
41
+ switch (env.toLowerCase()) {
42
+ case "production":
43
+ case "prod":
44
+ return "prod";
45
+ default:
46
+ return "dev";
47
+ }
48
+ };
49
+ }
50
+
51
+ export { EnvironmentService };
@@ -0,0 +1,130 @@
1
+ import Logger from 'src/application/logging/logger';
2
+ import { StatsigFeatureGate } from '@spiffy-ai/commerce-api-client';
3
+ import { FeatureGates } from 'src/application/models/featureGates';
4
+ import { SessionStorageService } from 'src/application/service/sessionStorageService';
5
+ import { OrgConfigFeatureGate } from 'src/application/models/api/orgConfigResults';
6
+
7
+ const FEATURE_FLAGS_STORAGE_KEY = 'spiffy-feature-flags';
8
+
9
+ class FeatureFlagService {
10
+ constructor(private readonly featureGates: OrgConfigFeatureGate[]) {}
11
+
12
+ private getQueryParamFeatureGateOverrides = (featureGate: FeatureGates): boolean | undefined => {
13
+ const urlObj = new URL(window.location.href);
14
+ const params = new URLSearchParams(urlObj.search);
15
+ const paramsObj = Object.fromEntries(params.entries());
16
+ const value = paramsObj[featureGate];
17
+
18
+ if (value != null) {
19
+ return value === 'true';
20
+ }
21
+
22
+ return undefined;
23
+ };
24
+
25
+ private getWindowFeatureGateOverrides = (featureGate: FeatureGates): boolean | undefined => {
26
+ const value = window._spiffy?.featureOverrides?.[String(featureGate)];
27
+ if (value != null) {
28
+ return value;
29
+ }
30
+
31
+ return undefined;
32
+ };
33
+
34
+ private getStoredFeatureGateOverrides = (featureGate: FeatureGates): boolean | undefined => {
35
+ const featureFlags = SessionStorageService.getItem(FEATURE_FLAGS_STORAGE_KEY);
36
+
37
+ if (featureFlags) {
38
+ try {
39
+ const featureFlagsObj = JSON.parse(featureFlags);
40
+ return featureFlagsObj[featureGate];
41
+ } catch (err) {
42
+ Logger.logError(
43
+ '[spiffy-ai] getStoredFeatureGateOverrides: error parsing feature flags',
44
+ err,
45
+ );
46
+ }
47
+ }
48
+
49
+ return undefined;
50
+ };
51
+
52
+ public persistFeatureGateOverrides() {
53
+ const featureFlags = Object.values(FeatureGates)
54
+ .map((featureGate) => ({
55
+ [featureGate]: this.getFeatureFlagOverride(featureGate),
56
+ }))
57
+ .filter((_, val) => val !== undefined)
58
+ .reduce((acc, curr) => ({ ...acc, ...curr }), {});
59
+ SessionStorageService.setItem(FEATURE_FLAGS_STORAGE_KEY, JSON.stringify(featureFlags));
60
+ }
61
+
62
+ private getFeatureFlagOverride(featureGate: FeatureGates): boolean | undefined {
63
+ const queryOverride = this.getQueryParamFeatureGateOverrides(featureGate);
64
+ if (queryOverride != null) {
65
+ Logger.logDebug(
66
+ `[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} overridden by URL param. New value: ${queryOverride}`,
67
+ );
68
+ return queryOverride;
69
+ }
70
+
71
+ const windowOverride = this.getWindowFeatureGateOverrides(featureGate);
72
+ if (windowOverride != null) {
73
+ Logger.logDebug(
74
+ `[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} overridden by window param. New value: ${windowOverride}`,
75
+ );
76
+ return windowOverride;
77
+ }
78
+
79
+ const storedOverride = this.getStoredFeatureGateOverrides(featureGate);
80
+ if (storedOverride != null) {
81
+ Logger.logDebug(
82
+ `[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} overridden by stored value. New value: ${storedOverride}`,
83
+ );
84
+ return storedOverride;
85
+ }
86
+
87
+ return undefined;
88
+ }
89
+
90
+ public isFeatureGateEnabled(featureGate: FeatureGates): boolean {
91
+ const gateValue = this.featureGates.find((gate) => gate.name === featureGate);
92
+
93
+ const featureFlagOverride = this.getFeatureFlagOverride(featureGate);
94
+ if (featureFlagOverride !== undefined) {
95
+ return featureFlagOverride;
96
+ }
97
+
98
+ if (gateValue == null || gateValue.value == null) {
99
+ Logger.logDebug(
100
+ `[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} value is undefined - returning false`,
101
+ );
102
+
103
+ return false;
104
+ }
105
+
106
+ return gateValue.value;
107
+ }
108
+
109
+ public isClientSessionEnabled(): boolean {
110
+ const gates: Array<StatsigFeatureGate> | undefined = this.featureGates;
111
+ const isEnabled =
112
+ gates == null ||
113
+ gates?.filter(
114
+ (gate) => gate.name === FeatureGates.IsClientSessionEnabled && gate.value === true,
115
+ ).length > 0;
116
+
117
+ return isEnabled;
118
+ }
119
+
120
+ public getFeatureFlags(): Record<string, boolean> {
121
+ return Object.fromEntries(
122
+ Object.values(FeatureGates).map((featureGate: FeatureGates) => [
123
+ featureGate,
124
+ this.isFeatureGateEnabled(featureGate),
125
+ ]),
126
+ );
127
+ }
128
+ }
129
+
130
+ export { FeatureFlagService };
@@ -0,0 +1,111 @@
1
+ import { LocalStorageService } from './localStorageService';
2
+ import Logger from '../logging/logger';
3
+
4
+ interface KustomerState {
5
+ wasWidgetOpen: boolean;
6
+ }
7
+
8
+ class KustomerIntegrationService {
9
+ static KUSTOMER_LOCAL_STORAGE_KEY = 'kustomerState';
10
+
11
+ static KUSTOMER_IFRAME_ID = 'kustomer-ui-sdk-iframe';
12
+
13
+ initialized: boolean;
14
+
15
+ constructor() {
16
+ Logger.logDebug('[spiffy-ai] KustomerIntegrationService created', undefined);
17
+ this.initialized = false;
18
+ }
19
+
20
+ initOnce(): void {
21
+ if (this.initialized) {
22
+ return;
23
+ }
24
+ const This = this;
25
+ LocalStorageService.attachListener({
26
+ storageKey: KustomerIntegrationService.KUSTOMER_LOCAL_STORAGE_KEY,
27
+ listener: (event) => This.onCustomerStateChange(event),
28
+ });
29
+ this.initialized = true;
30
+ }
31
+
32
+ disconnect(): void {
33
+ Logger.logDebug('[spiffy-ai] Disconnecting KustomerIntegrationService');
34
+ const This = this;
35
+ LocalStorageService.detachListener({
36
+ storageKey: KustomerIntegrationService.KUSTOMER_LOCAL_STORAGE_KEY,
37
+ listener: (event) => This.onCustomerStateChange(event),
38
+ });
39
+ const elementRef = this.findKustomerButton();
40
+ if (elementRef == null) {
41
+ Logger.logDebug('[spiffy-ai] Kustomer iFrame element not found');
42
+ return;
43
+ }
44
+ elementRef.style.visibility = 'visible';
45
+ }
46
+
47
+ /**
48
+ * Updates the visibility of the Kustomer chat icon.
49
+ */
50
+ updateVisibility(): boolean {
51
+ const elementRef = this.findKustomerButton();
52
+ if (elementRef == null) {
53
+ Logger.logDebug('[spiffy-ai] Kustomer iFrame element not found');
54
+ return false;
55
+ }
56
+
57
+ let kustomerStateStorageItem = LocalStorageService.getItem(
58
+ KustomerIntegrationService.KUSTOMER_LOCAL_STORAGE_KEY,
59
+ );
60
+ if (kustomerStateStorageItem == null) {
61
+ Logger.logDebug('[spiffy-ai] Kustomer state not found in local storage (defaulting)');
62
+ kustomerStateStorageItem = JSON.stringify({ wasWidgetOpen: false });
63
+ }
64
+
65
+ const kustomerState: KustomerState = JSON.parse(kustomerStateStorageItem);
66
+ const visibility = kustomerState.wasWidgetOpen ? 'visible' : 'hidden';
67
+ elementRef.style.visibility = visibility;
68
+ Logger.logDebug(
69
+ `[spiffy-ai] Kustomer widget was ${kustomerState.wasWidgetOpen ? 'open' : 'closed'}, setting visibility to ${visibility}`,
70
+ );
71
+ return true;
72
+ }
73
+
74
+ /**
75
+ * Queries the document body for the Kustomer SDK iframe. This function is to be run in a
76
+ * MutationObserver.
77
+ * @returns the iframe element if it exists, else undefine.
78
+ */
79
+ findKustomerButton(): HTMLIFrameElement | undefined {
80
+ Logger.logDebug('[spiffy-ai] Finding Kustomer button');
81
+ const parentDocument = window.document;
82
+ const kustomerElement =
83
+ parentDocument.getElementById(KustomerIntegrationService.KUSTOMER_IFRAME_ID) ?? undefined;
84
+
85
+ if (kustomerElement != null && kustomerElement instanceof HTMLIFrameElement) {
86
+ return kustomerElement;
87
+ }
88
+
89
+ Logger.logDebug('[spiffy-ai] Kustomer iFrame element not found');
90
+ return undefined;
91
+ }
92
+
93
+ /**
94
+ * Updates the Kustomer chat icon visibility when the kustomerState localStorage item changes.
95
+ * @param event The event that triggered the event listener.
96
+ */
97
+ onCustomerStateChange(event: StorageEvent): void {
98
+ if (
99
+ event.key === KustomerIntegrationService.KUSTOMER_LOCAL_STORAGE_KEY &&
100
+ event.newValue != null
101
+ ) {
102
+ Logger.logDebug(
103
+ `[spiffy-ai] Storage change key=${event.key}, updating widget visibility`,
104
+ event.newValue,
105
+ );
106
+ this.updateVisibility();
107
+ }
108
+ }
109
+ }
110
+
111
+ export { KustomerIntegrationService };
@@ -0,0 +1,77 @@
1
+ import Logger from '../logging/logger';
2
+
3
+ export enum LocalStorageKeys {
4
+ ChatId = 'v1-spiffy-chat-session-id',
5
+ SpiffyOnOverride = 'spiffy_on',
6
+ EnviveOnOverride = 'envive_on',
7
+ }
8
+
9
+ class LocalStorageService {
10
+ static setItem(key: string, value: string): void {
11
+ localStorage.setItem(key, value);
12
+ window.dispatchEvent(
13
+ new StorageEvent('storage', {
14
+ key,
15
+ newValue: value,
16
+ }),
17
+ );
18
+ }
19
+
20
+ static getItem(key: string): string | null {
21
+ return localStorage.getItem(key);
22
+ }
23
+
24
+ static setSpiffyOnFeatureFlag(value: boolean | null): void {
25
+ if (value === true) {
26
+ localStorage.setItem(LocalStorageKeys.SpiffyOnOverride, 'true');
27
+ } else if (value === false) {
28
+ localStorage.setItem(LocalStorageKeys.SpiffyOnOverride, 'false');
29
+ }
30
+ }
31
+
32
+ // TODO: LocalStorage service is not the proper use case for this method
33
+ // Should be moved to a more appropriate service or utility class (FeatureFlagService for ex)
34
+ // which may use LocalStorageService (or something else) under the hood
35
+ static getSpiffyOnFeatureFlag(): string | null {
36
+ return localStorage.getItem(LocalStorageKeys.SpiffyOnOverride);
37
+ }
38
+
39
+ static getLocalStorage() {
40
+ const ls = window?.localStorage;
41
+ if (!ls) {
42
+ Logger.logError('localStorage is not available', undefined);
43
+ }
44
+ return ls;
45
+ }
46
+
47
+ private static listenersCache: Record<string, (event: StorageEvent) => void> = {};
48
+ private static listenerForKey(
49
+ listener: LocalStorageEventListener,
50
+ ): (event: StorageEvent) => void {
51
+ if (!this.listenersCache[listener.storageKey]) {
52
+ this.listenersCache[listener.storageKey] = (event: StorageEvent) => {
53
+ if (event.key !== listener.storageKey) {
54
+ return;
55
+ }
56
+ Logger.logDebug(`[spiffy-ai] Storage event key=${event.key}, value=`, event.newValue);
57
+ listener.listener(event);
58
+ };
59
+ }
60
+
61
+ return this.listenersCache[listener.storageKey];
62
+ }
63
+
64
+ /**
65
+ * Attach a listener to the window's storage event. Safe to call multiple times.
66
+ * @param listener
67
+ */
68
+ static attachListener(listener: LocalStorageEventListener): void {
69
+ window.addEventListener('storage', this.listenerForKey(listener));
70
+ }
71
+
72
+ static detachListener(listener: LocalStorageEventListener): void {
73
+ window.removeEventListener('storage', this.listenerForKey(listener));
74
+ }
75
+ }
76
+
77
+ export { LocalStorageService };