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