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