@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.
- package/LICENSE +2 -0
- package/README.md +2 -0
- package/dist/GridInsertionService-CEYo9pGj.js +22 -0
- package/dist/GridInsertionService-CS_bnPh0.cjs +28 -0
- package/dist/bandolier-Ble8jEa8.js +1221 -0
- package/dist/bandolier-Bm2xAt_j.cjs +1221 -0
- package/dist/carpe-Da7b-LCW.cjs +599 -0
- package/dist/carpe-W13mhRRP.js +597 -0
- package/dist/cdnService-CZ-aXcY6.cjs +23 -0
- package/dist/cdnService-zQfKk3Eb.js +18 -0
- package/dist/chatElementDisplayLocation-CX8fuNao.d.cts +239 -0
- package/dist/chatElementDisplayLocation-CwptS9tx.d.ts +239 -0
- package/dist/chunk-CUT6urMc.cjs +30 -0
- package/dist/contexts/index.cjs +13 -0
- package/dist/contexts/index.d.cts +65 -0
- package/dist/contexts/index.d.ts +66 -0
- package/dist/contexts/index.js +7 -0
- package/dist/contexts-BRjfVq_k.js +5064 -0
- package/dist/contexts-BYArqZtK.cjs +5164 -0
- package/dist/coterie-3y0D9ko4.cjs +229 -0
- package/dist/coterie-DOWcJAYv.js +229 -0
- package/dist/custservice-types-CFIFwZ-r.js +10 -0
- package/dist/custservice-types-CkfxZiHY.cjs +16 -0
- package/dist/default-C2fEZKXk.js +175 -0
- package/dist/default-CBUq6Q6G.cjs +4 -0
- package/dist/default-CGIFZK6m.js +4 -0
- package/dist/default-D_KPZdPJ.cjs +198 -0
- package/dist/divIds-Bss-btao.js +49 -0
- package/dist/divIds-DnZNd7rA.cjs +223 -0
- package/dist/dreamlandBaby-DCIsuU9R.cjs +338 -0
- package/dist/dreamlandBaby-DvSaZGrz.js +338 -0
- package/dist/entrypoints-D_JUvkgy.cjs +18 -0
- package/dist/entrypoints-YLQsbBRD.js +6 -0
- package/dist/enviveConfigContext-CUGLpPGU.js +34 -0
- package/dist/enviveConfigContext-Dfr2VH6u.cjs +48 -0
- package/dist/fiveCbd-B1SESMCO.js +605 -0
- package/dist/fiveCbd-CkOlVby_.cjs +605 -0
- package/dist/forLoveAndLemons-CfYPMnKS.cjs +660 -0
- package/dist/forLoveAndLemons-DmwYZIk0.js +658 -0
- package/dist/greenpan-Bsl3ir59.cjs +389 -0
- package/dist/greenpan-BtOi45lf.js +389 -0
- package/dist/grooveLife-6_dtYsRk.js +334 -0
- package/dist/grooveLife-Cmm1PSCL.cjs +334 -0
- package/dist/homegrownCannabis-C-kw-74X.js +400 -0
- package/dist/homegrownCannabis-CO0uY_mp.cjs +400 -0
- package/dist/hooks/index.cjs +16 -0
- package/dist/hooks/index.d.cts +357 -0
- package/dist/hooks/index.d.ts +357 -0
- package/dist/hooks/index.js +7 -0
- package/dist/jackArcher-CLVmwwpI.js +719 -0
- package/dist/jackArcher-DdYTIzAV.cjs +719 -0
- package/dist/jordanCraig-Am-Oor-O.js +1778 -0
- package/dist/jordanCraig-_u3-w4Hp.cjs +1778 -0
- package/dist/kindredBravely-CWovIDSc.cjs +482 -0
- package/dist/kindredBravely-eWp-ud_E.js +482 -0
- package/dist/kutFromTheKloth-BMV4BuGQ.js +361 -0
- package/dist/kutFromTheKloth-Q589bAOC.cjs +361 -0
- package/dist/larryAndSerges-BMUlTgI-.js +252 -0
- package/dist/larryAndSerges-CEau764j.cjs +252 -0
- package/dist/leapsAndRebounds-DGMzPO7T.js +352 -0
- package/dist/leapsAndRebounds-DHAtRTJD.cjs +352 -0
- package/dist/logger-Dln20ans.cjs +25 -0
- package/dist/logger-pdEEY8T2.js +19 -0
- package/dist/longevityrx-CZW8Hxzi.cjs +312 -0
- package/dist/longevityrx-jH2JLhNH.js +312 -0
- package/dist/lookOptic-BGXP5P_V.js +274 -0
- package/dist/lookOptic-CA6RwLbG.cjs +274 -0
- package/dist/mantraBrand-Cm9_PBCT.js +742 -0
- package/dist/mantraBrand-DByNqpnL.cjs +742 -0
- package/dist/medterra-B0wxj_PV.js +575 -0
- package/dist/medterra-DnPN2ksU.cjs +575 -0
- package/dist/modells-Bmz8Ag5M.js +476 -0
- package/dist/modells-CoYgkLSp.cjs +476 -0
- package/dist/models-DHdb7QWn.js +51 -0
- package/dist/models-ixxUsGL_.cjs +69 -0
- package/dist/pressedFloral-DSKs_oVG.js +653 -0
- package/dist/pressedFloral-DjBiSoUl.cjs +653 -0
- package/dist/skinPerfection-B_3xzVNS.cjs +326 -0
- package/dist/skinPerfection-IDrBuAPt.js +326 -0
- package/dist/snapSupplements-BJk5T5ba.js +277 -0
- package/dist/snapSupplements-BStTsdOZ.cjs +277 -0
- package/dist/socialProofClasses-Bhv2Vulz.js +9 -0
- package/dist/socialProofClasses-CrQBWdSA.cjs +39 -0
- package/dist/spanx-BYg0LE7R.js +653 -0
- package/dist/spanx-LwU1zSzq.cjs +655 -0
- package/dist/spanxStaging-CfSmuKYB.js +837 -0
- package/dist/spanxStaging-OZLV9qix.cjs +840 -0
- package/dist/suggestionBarV2-types-BllzwsBD.js +34 -0
- package/dist/suggestionBarV2-types-CaovchMP.cjs +46 -0
- package/dist/supergoop-BqPXDnKk.cjs +327 -0
- package/dist/supergoop-CIlrHND_.js +325 -0
- package/dist/types-C4T5UOIW.cjs +230 -0
- package/dist/types-CYNvLeSA.js +176 -0
- package/dist/uniqueVintage-B30mOqbH.cjs +1205 -0
- package/dist/uniqueVintage-CFueJOhO.js +1203 -0
- package/dist/venaCbd-DHGZy49P.cjs +357 -0
- package/dist/venaCbd-T0CqVD4k.js +357 -0
- package/dist/westonJonBoucher-BdMzs_Yg.cjs +414 -0
- package/dist/westonJonBoucher-b4TCQ4ev.js +414 -0
- package/dist/wineEnthusiast-BLGlOjgr.cjs +932 -0
- package/dist/wineEnthusiast-BqR0i_54.js +932 -0
- package/dist/wolfMattress-CyyO-LoC.js +362 -0
- package/dist/wolfMattress-DNGZOivg.cjs +362 -0
- package/dist/wolfTactical-3Mm2fvVF.js +341 -0
- package/dist/wolfTactical-BmXYlFjr.cjs +341 -0
- package/package.json +66 -0
- package/src/adapters/amplitude/amplitudeAdapter.ts +454 -0
- package/src/adapters/amplitude/index.ts +2 -0
- package/src/adapters/amplitude/stubAmplitudeAdapter.ts +34 -0
- package/src/adapters/spiffy/commerce/api.ts +596 -0
- package/src/adapters/spiffy/commerce/exceptions/sessionExceptions.ts +6 -0
- package/src/adapters/spiffy/commerce/exceptions/unsupportedProductExceptions.ts +6 -0
- package/src/adapters/spiffy/commerce/graphql.ts +184 -0
- package/src/application/config/generalStaticConfig.ts +37 -0
- package/src/application/logging/logger.ts +29 -0
- package/src/application/models/api/context.ts +4 -0
- package/src/application/models/api/generationParams.ts +4 -0
- package/src/application/models/api/nextMessageRequest.ts +11 -0
- package/src/application/models/api/orgAnalyticsConfig.ts +19 -0
- package/src/application/models/api/orgConfigResults.ts +40 -0
- package/src/application/models/api/organizationConfig.ts +12 -0
- package/src/application/models/api/response.ts +132 -0
- package/src/application/models/api/responseGenerics.ts +67 -0
- package/src/application/models/api/search.ts +26 -0
- package/src/application/models/api/suggestion.ts +4 -0
- package/src/application/models/api/supportedEventRequest.ts +8 -0
- package/src/application/models/api/userEvent.ts +101 -0
- package/src/application/models/cachedValue.ts +8 -0
- package/src/application/models/chatElementDisplayLocation.ts +22 -0
- package/src/application/models/clientDetails.ts +18 -0
- package/src/application/models/colorsConfig.ts +28 -0
- package/src/application/models/conversationalSearchIds.ts +5 -0
- package/src/application/models/dataLayer.ts +45 -0
- package/src/application/models/domMutationContinuation.ts +7 -0
- package/src/application/models/domObservationStrategy.ts +9 -0
- package/src/application/models/events.ts +5 -0
- package/src/application/models/featureGates.ts +23 -0
- package/src/application/models/frontendConfig.ts +14 -0
- package/src/application/models/googleAnalyticsEvents.ts +8 -0
- package/src/application/models/graphql/index.ts +2 -0
- package/src/application/models/graphql/queries/getMerchantColorsQuery.ts +37 -0
- package/src/application/models/graphql/queries/getMerchantFrontendConfigQuery.ts +103 -0
- package/src/application/models/graphql/queries/getMerchantOrgIdQuery.ts +11 -0
- package/src/application/models/guards/api/index.ts +12 -0
- package/src/application/models/guards/api/isApiFormResponse.ts +90 -0
- package/src/application/models/guards/api/isApiFormSubmittedResponseAttributes.ts +37 -0
- package/src/application/models/guards/api/isApiOrderResponseAttributes.ts +155 -0
- package/src/application/models/guards/api/isApiOrgConfigResults.ts +277 -0
- package/src/application/models/guards/api/isApiOrganizationConfig.ts +207 -0
- package/src/application/models/guards/api/isApiPDPEventAttributes.ts +21 -0
- package/src/application/models/guards/api/isApiPLPEventAttributes.ts +41 -0
- package/src/application/models/guards/api/isApiPageResponseAttributes.ts +21 -0
- package/src/application/models/guards/api/isApiProductResponseAttributes.ts +85 -0
- package/src/application/models/guards/api/isApiProductSearchAttributes.ts +23 -0
- package/src/application/models/guards/api/isApiProductSearchFilterAttributes.ts +15 -0
- package/src/application/models/guards/api/isApiQueryTypedEventAttributes.ts +4 -0
- package/src/application/models/guards/api/isApiResponse.ts +39 -0
- package/src/application/models/guards/api/isApiReviewResponseAttributes.ts +30 -0
- package/src/application/models/guards/api/isApiReviewRichInformation.ts +37 -0
- package/src/application/models/guards/api/isApiSearchEventAttributes.ts +28 -0
- package/src/application/models/guards/api/isApiSuggestion.ts +36 -0
- package/src/application/models/guards/api/isApiSuggestionClickedEventAttributes.ts +9 -0
- package/src/application/models/guards/api/isApiTextResponseAttributes.ts +9 -0
- package/src/application/models/guards/api/isApiUserEvent.ts +25 -0
- package/src/application/models/guards/graphQL/isGraphQLColorsConfig.ts +50 -0
- package/src/application/models/guards/isBaseEcommerceEvent.ts +17 -0
- package/src/application/models/guards/isGA4EcommerceEvent.ts +17 -0
- package/src/application/models/guards/isLegacyUAEcommerceEvent.ts +17 -0
- package/src/application/models/guards/isMobilePLPChatPlacementParameter.ts +11 -0
- package/src/application/models/guards/isSpanxTakeAQuizCtaParameter.ts +4 -0
- package/src/application/models/guards/isVariantInfo.ts +37 -0
- package/src/application/models/guards/utils.ts +43 -0
- package/src/application/models/index.ts +20 -0
- package/src/application/models/localStorageEventListener.ts +4 -0
- package/src/application/models/message.ts +146 -0
- package/src/application/models/mobilePLPChatPlacementParameter.ts +3 -0
- package/src/application/models/orgsEnum.ts +36 -0
- package/src/application/models/productExperiment.ts +5 -0
- package/src/application/models/spanxTakeAQuizCtaParameter.ts +4 -0
- package/src/application/models/spiffyWidgets.ts +16 -0
- package/src/application/models/supportedOrgs.ts +137 -0
- package/src/application/models/utilityTypes/camelCase.ts +87 -0
- package/src/application/models/utilityTypes/camelCasedPropertiesDeep.ts +80 -0
- package/src/application/models/utilityTypes/delimiterCase.ts +121 -0
- package/src/application/models/utilityTypes/delimiterCasedPropertiesDeep.ts +98 -0
- package/src/application/models/utilityTypes/index.ts +1 -0
- package/src/application/models/utilityTypes/internal.ts +93 -0
- package/src/application/models/utilityTypes/primitive.ts +8 -0
- package/src/application/models/utilityTypes/snakeCasedPropertiesDeep.ts +49 -0
- package/src/application/models/utilityTypes/splitWords.ts +76 -0
- package/src/application/models/utilityTypes/trim.ts +28 -0
- package/src/application/models/utilityTypes/unknownArray.ts +25 -0
- package/src/application/models/utils/snakeToCamelTransformer.ts +90 -0
- package/src/application/models/utils/stringToFulfillmentDisplayStatusEnumValue.ts +68 -0
- package/src/application/models/validators/validateGraphQLColorsConfig.ts +29 -0
- package/src/application/models/validators/validateGraphQLFrontendConfig.ts +594 -0
- package/src/application/models/validators/validateGraphQLOrgId.ts +7 -0
- package/src/application/models/validators/validateMobilePLPChatPlacementParameter.ts +14 -0
- package/src/application/models/validators/validateOrgConfigResults.ts +47 -0
- package/src/application/models/validators/validateOrganizationConfig.ts +37 -0
- package/src/application/models/validators/validateResponse.ts +187 -0
- package/src/application/models/validators/validateSuggestion.ts +16 -0
- package/src/application/models/validators/validateUserEvent.ts +110 -0
- package/src/application/models/variantInfo/index.ts +1 -0
- package/src/application/models/variantInfo/pageVisitInfo.ts +6 -0
- package/src/application/models/variantInfo/plpInfo.ts +3 -0
- package/src/application/models/variantInfo/productInfo.ts +5 -0
- package/src/application/models/variantInfo/variantInfo.ts +23 -0
- package/src/application/service/cachingService.ts +84 -0
- package/src/application/service/cdnService.ts +18 -0
- package/src/application/service/customerService/index.ts +8 -0
- package/src/application/service/customerService/providers/UnsupportedCustomerService.ts +15 -0
- package/src/application/service/customerService/types.ts +31 -0
- package/src/application/service/domMutationObserver.ts +320 -0
- package/src/application/service/domMutations/GridInsertionService.ts +123 -0
- package/src/application/service/domMutations/dataLayer/dataLayerEventsListener.ts +99 -0
- package/src/application/service/domMutations/domInsertionService.ts +90 -0
- package/src/application/service/domMutations/domMutationListener.ts +15 -0
- package/src/application/service/domMutations/domMutationListenerState.ts +52 -0
- package/src/application/service/domMutations/floatingChat/embeddedChatsPlacementsListener.ts +41 -0
- package/src/application/service/domMutations/gladly/gladlyListener.ts +61 -0
- package/src/application/service/domMutations/spiffy/orgs/common/kustomerVisibilityListener.ts +41 -0
- package/src/application/service/domMutations/spiffy/orgs/common/orgsCommonDataLayerListener.ts +119 -0
- package/src/application/service/environmentService.ts +51 -0
- package/src/application/service/featureFlagService.ts +130 -0
- package/src/application/service/kustomerIntegrationService.ts +111 -0
- package/src/application/service/localStorageService.ts +77 -0
- package/src/application/service/pageVariantService.ts +779 -0
- package/src/application/service/searchService.ts +140 -0
- package/src/application/service/sessionStorageService.ts +27 -0
- package/src/application/service/shopifyUrlService.ts +63 -0
- package/src/application/service/userIdentityService.ts +114 -0
- package/src/application/service/windowChatToggleService.ts +71 -0
- package/src/application/service/windowDataLayerService.ts +181 -0
- package/src/application/service/windowFrontendConfigService.ts +104 -0
- package/src/application/utils/__tests__/divideArrays.test.ts +14 -0
- package/src/application/utils/analyticsUtils.ts +110 -0
- package/src/application/utils/coreContextToApiContext.ts +11 -0
- package/src/application/utils/coreUserEventToApiUserEvent.ts +106 -0
- package/src/application/utils/divideArray.ts +7 -0
- package/src/application/utils/domObserver.ts +96 -0
- package/src/application/utils/elementObserver.ts +246 -0
- package/src/application/utils/imageFilter.ts +12 -0
- package/src/application/utils/index.ts +3 -0
- package/src/application/utils/merchantUtils.ts +16 -0
- package/src/application/utils/messageFromFormSubmittedEvent.ts +31 -0
- package/src/application/utils/messageFromQueryEvent.ts +38 -0
- package/src/application/utils/messageFromResponse.ts +133 -0
- package/src/application/utils/messageFromSuggestionEvent.ts +32 -0
- package/src/application/utils/mouseEventTypes.ts +1 -0
- package/src/application/utils/mutationHelper.ts +51 -0
- package/src/application/utils/nextMessageRequestToApiRequest.ts +31 -0
- package/src/application/utils/nodeSelector.ts +133 -0
- package/src/application/utils/overrides.ts +196 -0
- package/src/application/utils/stringUtils.ts +55 -0
- package/src/application/utils/supportedEventRequestToApiRequest.ts +12 -0
- package/src/application/utils/urlsParser.ts +53 -0
- package/src/application/utils/validation.ts +5 -0
- package/src/atoms/app/index.ts +57 -0
- package/src/atoms/app/variant.ts +261 -0
- package/src/atoms/atomStore.ts +34 -0
- package/src/atoms/chat/chatState.ts +44 -0
- package/src/atoms/chat/form.ts +19 -0
- package/src/atoms/chat/index.ts +38 -0
- package/src/atoms/chat/lastMessage.ts +11 -0
- package/src/atoms/chat/messageQueue.ts +65 -0
- package/src/atoms/chat/performanceMetrics.ts +84 -0
- package/src/atoms/chat/renderedWidgetRefs.ts +28 -0
- package/src/atoms/chat/replies.ts +51 -0
- package/src/atoms/chat/suggestions.ts +36 -0
- package/src/atoms/globalSearch.ts +12 -0
- package/src/atoms/index.ts +5 -0
- package/src/atoms/org/customerService.ts +13 -0
- package/src/atoms/org/graphqlConfig.ts +27 -0
- package/src/atoms/org/index.ts +7 -0
- package/src/atoms/org/merchantCss.ts +44 -0
- package/src/atoms/org/org.ts +256 -0
- package/src/atoms/org/orgAnalyticsConfig.ts +28 -0
- package/src/atoms/org/orgPageConfig.ts +38 -0
- package/src/atoms/org/orgUIConfig.ts +122 -0
- package/src/atoms/search/chatSearch.ts +293 -0
- package/src/atoms/search/index.ts +2 -0
- package/src/atoms/search/productFilters.ts +207 -0
- package/src/atoms/search/productSorter.ts +23 -0
- package/src/atoms/search/searchAPI.ts +194 -0
- package/src/atoms/search/types.ts +55 -0
- package/src/atoms/search/utils.ts +18 -0
- package/src/config/divIds.ts +27 -0
- package/src/config/locators/components/chat/entrypoints.ts +13 -0
- package/src/config/locators/components/chat/index.ts +23 -0
- package/src/config/locators/components/chat/preview.ts +13 -0
- package/src/config/locators/components/chat/variants/index.ts +16 -0
- package/src/config/locators/components/common/buttons.ts +6 -0
- package/src/config/locators/components/common/cards.ts +18 -0
- package/src/config/locators/components/common/links.ts +1 -0
- package/src/config/locators/components/common/tables.ts +2 -0
- package/src/config/locators/components/floating-button.ts +2 -0
- package/src/config/locators/components/index.ts +3 -0
- package/src/config/locators/components/report-issue.ts +21 -0
- package/src/config/locators/components/search/index.ts +5 -0
- package/src/config/locators/components/shadow-dom.ts +1 -0
- package/src/config/locators/embedded.ts +21 -0
- package/src/config/locators/index.ts +3 -0
- package/src/config/socialProofClasses.ts +17 -0
- package/src/contexts/chatContext.tsx +451 -0
- package/src/contexts/enviveConfigContext.tsx +70 -0
- package/src/contexts/index.ts +4 -0
- package/src/contexts/systemSettingsContext.tsx +61 -0
- package/src/contexts/types.ts +1059 -0
- package/src/enabled-features.ts +83 -0
- package/src/events/event-types.ts +11 -0
- package/src/events/index.ts +52 -0
- package/src/events/registerAnalyticsListeners.ts +49 -0
- package/src/extension.ts +63 -0
- package/src/hooks/index.ts +22 -0
- package/src/hooks/useBlockBackButton.ts +29 -0
- package/src/hooks/useChatToggle.ts +66 -0
- package/src/hooks/useCustomerSupportHandoff.ts +39 -0
- package/src/hooks/useDebounce.ts +17 -0
- package/src/hooks/useDynamicVariants.ts +210 -0
- package/src/hooks/useElementObserver.ts +245 -0
- package/src/hooks/useFileUpload.ts +61 -0
- package/src/hooks/useGrabAndScroll.ts +133 -0
- package/src/hooks/useHideElements.ts +82 -0
- package/src/hooks/useHorizontalScrollAnimation.ts +115 -0
- package/src/hooks/useImageResolver.ts +51 -0
- package/src/hooks/useIntersection.ts +28 -0
- package/src/hooks/useIsSmallScreen.ts +23 -0
- package/src/hooks/useMessageFilter.ts +49 -0
- package/src/hooks/useMessageScrollObserver.ts +47 -0
- package/src/hooks/useReducedMotionWithOverride.ts +15 -0
- package/src/hooks/useSearch.tsx +433 -0
- package/src/hooks/useSnapCalculator.ts +38 -0
- package/src/hooks/useSnapControl.ts +155 -0
- package/src/hooks/useSystemSettingsContext.ts +12 -0
- package/src/hooks/useTrackComponentVisibleEvent.ts +52 -0
- package/src/hooks/useUpdateAnalyticsProps.ts +56 -0
- package/src/hooks/utils.ts +153 -0
- package/src/index.ts +31 -0
- package/src/initialize.ts +163 -0
- package/src/interceptors/types.ts +6 -0
- package/src/interceptors/useFormEscalation.ts +40 -0
- package/src/interceptors/useMessageInterceptor.ts +32 -0
- package/src/main.ts +85 -0
- package/src/main.tsx +123 -0
- package/src/merchants/bandolier/bandolier.ts +1389 -0
- package/src/merchants/carpe/carpe.ts +656 -0
- package/src/merchants/coterie/coterie.ts +280 -0
- package/src/merchants/default.ts +193 -0
- package/src/merchants/dreamlandBaby/dreamlandBaby.ts +375 -0
- package/src/merchants/fiveCbd/fiveCbd.ts +697 -0
- package/src/merchants/forLoveAndLemons/forLoveAndLemons.ts +721 -0
- package/src/merchants/greenpan/greenpan.ts +440 -0
- package/src/merchants/grooveLife/grooveLife.ts +386 -0
- package/src/merchants/homegrownCannabis/homegrownCannabis.ts +468 -0
- package/src/merchants/init-merchant.sh +53 -0
- package/src/merchants/jackArcher/jackArcher.ts +974 -0
- package/src/merchants/jordanCraig/jordanCraig.ts +1927 -0
- package/src/merchants/kindredBravely/kindredBravely.ts +529 -0
- package/src/merchants/kutFromTheKloth/kutFromTheKloth.ts +418 -0
- package/src/merchants/larryAndSerges/larryAndSerges.ts +314 -0
- package/src/merchants/leapsAndRebounds/leapsAndRebounds.ts +424 -0
- package/src/merchants/longevityrx/longevityrx.ts +368 -0
- package/src/merchants/lookOptic/lookOptic.ts +323 -0
- package/src/merchants/mantraBrand/mantraBrand.ts +838 -0
- package/src/merchants/medterra/medterra.ts +670 -0
- package/src/merchants/modells/modells.ts +546 -0
- package/src/merchants/pressedFloral/pressedFloral.ts +734 -0
- package/src/merchants/skinPerfection/skinPerfection.ts +379 -0
- package/src/merchants/snapSupplements/snapSupplements.ts +325 -0
- package/src/merchants/spanx/spanx.ts +810 -0
- package/src/merchants/spanx/spanxStaging.ts +942 -0
- package/src/merchants/supergoop/supergoop.ts +376 -0
- package/src/merchants/uniqueVintage/uniqueVintage.ts +1314 -0
- package/src/merchants/uniqueVintage/views/useUniqueVintageChatSearch.ts +147 -0
- package/src/merchants/venaCbd/venaCbd.ts +410 -0
- package/src/merchants/westonJonBoucher/westonJonBoucher.ts +473 -0
- package/src/merchants/wineEnthusiast/wineEnthusiast.ts +990 -0
- package/src/merchants/wolfMattress/wolfMattress.ts +411 -0
- package/src/merchants/wolfTactical/wolfTactical.ts +389 -0
- package/src/types/custservice-types.ts +28 -0
- package/src/types/search-filter-types.ts +111 -0
- package/src/types/suggestionBarV2-types.ts +4 -0
- package/src/types/test-types.ts +3 -0
- 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,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
|
+
};
|