@envive-ai/react-hooks 0.3.10 → 0.3.12
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 +26 -22
- package/dist/application/commerce-api.d.cts +58 -0
- package/dist/application/commerce-api.d.ts +59 -0
- package/dist/application/commerce-api.js +16 -12
- package/dist/application/models/api/widgetText.d.cts +14 -0
- package/dist/application/models/api/widgetText.d.ts +14 -0
- package/dist/application/models/api/widgetTextRequest.d.cts +16 -0
- package/dist/application/models/api/widgetTextRequest.d.ts +16 -0
- package/dist/application/models/chatElementDisplayLocationV3.cjs +4 -1
- package/dist/application/models/chatElementDisplayLocationV3.d.cts +4 -1
- package/dist/application/models/chatElementDisplayLocationV3.d.ts +4 -1
- package/dist/application/models/chatElementDisplayLocationV3.js +4 -1
- package/dist/application/models/guards/api/index.cjs +7 -7
- package/dist/application/models/guards/api/index.js +7 -7
- 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/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/models/index.cjs +29 -29
- package/dist/application/models/index.d.cts +25 -25
- package/dist/application/models/index.d.ts +25 -25
- package/dist/application/models/index.js +29 -29
- package/dist/application/models/validators/validateGraphQLFrontendConfig.cjs +1 -1
- package/dist/application/models/validators/validateGraphQLFrontendConfig.js +1 -1
- package/dist/application/models/validators/validateResponse.cjs +3 -3
- package/dist/application/models/validators/validateResponse.js +3 -3
- package/dist/application/models/validators/validateUserEvent.cjs +2 -2
- package/dist/application/models/validators/validateUserEvent.js +2 -2
- package/dist/application/models/variantInfo/variantInfo.cjs +2 -1
- package/dist/application/models/variantInfo/variantInfo.d.cts +6 -1
- package/dist/application/models/variantInfo/variantInfo.d.ts +6 -1
- package/dist/application/models/variantInfo/variantInfo.js +2 -1
- package/dist/application/utils/analyticsUtils.cjs +1 -1
- package/dist/application/utils/analyticsUtils.js +1 -1
- package/dist/application/utils/nodeSelector.cjs +12 -14
- package/dist/application/utils/nodeSelector.js +12 -14
- package/dist/application/utils/widgetTextFromApiWidgetTextResponse.cjs +3 -1
- package/dist/application/utils/widgetTextFromApiWidgetTextResponse.js +3 -1
- package/dist/application/utils/widgetTextRequestToApiRequest.cjs +4 -1
- package/dist/application/utils/widgetTextRequestToApiRequest.js +4 -1
- package/dist/atoms/app/index.cjs +7 -7
- package/dist/atoms/app/index.d.cts +1 -1
- package/dist/atoms/app/index.d.ts +8 -8
- package/dist/atoms/app/index.js +1 -1
- package/dist/atoms/app/variant.cjs +44 -4
- package/dist/atoms/app/variant.d.cts +8 -8
- package/dist/atoms/app/variant.d.ts +8 -8
- package/dist/atoms/app/variant.js +44 -5
- package/dist/atoms/chat/chatState.d.cts +18 -18
- package/dist/atoms/chat/chatState.d.ts +17 -17
- package/dist/atoms/chat/form.cjs +1 -1
- package/dist/atoms/chat/form.d.cts +2 -2
- package/dist/atoms/chat/form.d.ts +2 -2
- package/dist/atoms/chat/form.js +1 -1
- package/dist/atoms/chat/index.d.cts +3 -3
- package/dist/atoms/chat/index.d.ts +2 -2
- package/dist/atoms/chat/lastMessage.d.cts +2 -2
- package/dist/atoms/chat/lastMessage.d.ts +2 -2
- package/dist/atoms/chat/messageQueue.d.cts +6 -6
- package/dist/atoms/chat/messageQueue.d.ts +6 -6
- 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 +3 -3
- 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.d.cts +19 -0
- package/dist/atoms/envive/enviveConfig.d.ts +19 -0
- 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/customerService.d.ts +6 -6
- package/dist/atoms/org/graphqlConfig.d.cts +4 -4
- package/dist/atoms/org/graphqlConfig.d.ts +4 -4
- package/dist/atoms/org/index.cjs +1 -1
- package/dist/atoms/org/index.js +1 -1
- package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
- package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
- package/dist/atoms/org/orgAnalyticsConfig.d.cts +5 -5
- package/dist/atoms/org/orgAnalyticsConfig.d.ts +5 -5
- package/dist/atoms/search/chatSearch.cjs +1 -1
- package/dist/atoms/search/chatSearch.d.cts +17 -17
- package/dist/atoms/search/chatSearch.d.ts +17 -17
- package/dist/atoms/search/chatSearch.js +1 -1
- package/dist/atoms/search/searchAPI.d.cts +13 -13
- 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/atoms/widget/chatPreviewLoading.d.ts +2 -2
- package/dist/config/locators/components/search/index.d.cts +1 -1
- package/dist/contexts/amplitudeContext/amplitudeContext.cjs +9 -7
- package/dist/contexts/amplitudeContext/amplitudeContext.d.cts +2 -2
- package/dist/contexts/amplitudeContext/amplitudeContext.d.ts +2 -2
- package/dist/contexts/amplitudeContext/amplitudeContext.js +5 -3
- package/dist/contexts/amplitudeContext/index.cjs +1 -0
- package/dist/contexts/amplitudeContext/index.d.cts +2 -2
- package/dist/contexts/amplitudeContext/index.d.ts +2 -2
- package/dist/contexts/amplitudeContext/index.js +2 -2
- package/dist/contexts/cdnContext/cdnContext.cjs +3 -3
- package/dist/contexts/enviveConfigContext/enviveConfigContext.cjs +6 -5
- package/dist/contexts/enviveConfigContext/enviveConfigContext.d.cts +2 -1
- package/dist/contexts/enviveConfigContext/enviveConfigContext.d.ts +2 -1
- package/dist/contexts/enviveConfigContext/enviveConfigContext.js +3 -2
- package/dist/contexts/enviveContext/WindowChatToggleBinder.cjs +4 -3
- package/dist/contexts/enviveContext/WindowChatToggleBinder.js +4 -3
- package/dist/contexts/enviveContext/enviveContext.cjs +23 -16
- package/dist/contexts/enviveContext/enviveContext.d.cts +5 -1
- package/dist/contexts/enviveContext/enviveContext.d.ts +5 -1
- package/dist/contexts/enviveContext/enviveContext.js +23 -16
- package/dist/contexts/enviveContext/types.d.cts +1 -1
- package/dist/contexts/enviveContext/types.d.ts +1 -1
- package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.cjs +23 -2
- package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.d.cts +11 -2
- package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.d.ts +11 -2
- package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.js +23 -2
- package/dist/contexts/featureFlagServiceContext/index.d.cts +2 -2
- package/dist/contexts/featureFlagServiceContext/index.d.ts +2 -2
- package/dist/contexts/graphqlContext/graphqlContext.cjs +7 -7
- package/dist/contexts/graphqlContext/graphqlContext.d.cts +1 -1
- package/dist/contexts/graphqlContext/graphqlContext.d.ts +1 -1
- package/dist/contexts/graphqlContext/graphqlContext.js +3 -3
- package/dist/contexts/graphqlContext/mockV3Config.cjs +10 -4
- package/dist/contexts/graphqlContext/mockV3Config.js +10 -4
- package/dist/contexts/hardcopyContext/hardcopyContext.cjs +60 -6
- package/dist/contexts/hardcopyContext/hardcopyContext.d.cts +8 -3
- package/dist/contexts/hardcopyContext/hardcopyContext.d.ts +8 -3
- package/dist/contexts/hardcopyContext/hardcopyContext.js +58 -4
- package/dist/contexts/newOrgConfigContext/newOrgConfigContext.cjs +3 -3
- package/dist/contexts/pageContext/mapping.cjs +6 -2
- package/dist/contexts/pageContext/mapping.js +6 -2
- package/dist/contexts/pageContext/pageContext.cjs +12 -7
- package/dist/contexts/pageContext/pageContext.js +10 -5
- package/dist/contexts/pageContext/types.d.cts +7 -3
- package/dist/contexts/pageContext/types.d.ts +7 -3
- package/dist/contexts/salesAgentContext/chatAPI.cjs +101 -12
- package/dist/contexts/salesAgentContext/chatAPI.d.cts +8 -4
- package/dist/contexts/salesAgentContext/chatAPI.d.ts +8 -4
- package/dist/contexts/salesAgentContext/chatAPI.js +103 -14
- package/dist/contexts/salesAgentContext/salesAgentContext.cjs +1 -1
- package/dist/contexts/salesAgentContext/salesAgentContext.js +1 -1
- package/dist/contexts/salesAgentContext/salesAgentService.cjs +52 -10
- package/dist/contexts/salesAgentContext/salesAgentService.js +50 -8
- package/dist/contexts/searchContext/searchContext.cjs +4 -4
- package/dist/contexts/searchContext/searchContext.js +1 -1
- package/dist/contexts/systemSettingsContext/systemSettingsContext.cjs +3 -3
- package/dist/contexts/systemSettingsContext/systemSettingsContext.d.cts +2 -2
- package/dist/contexts/types.cjs +1 -1
- package/dist/contexts/types.d.cts +10 -3
- package/dist/contexts/types.d.ts +10 -3
- package/dist/contexts/types.js +1 -1
- package/dist/contexts/typesV3.cjs +2 -1
- package/dist/contexts/typesV3.d.cts +28 -7
- package/dist/contexts/typesV3.d.ts +26 -5
- package/dist/contexts/typesV3.js +2 -1
- package/dist/contexts/userIdentityContext/userIdentityContext.cjs +3 -3
- package/dist/contexts/widgetConfigContext/widgetConfigContext.cjs +1 -1
- package/dist/contexts/widgetConfigContext/widgetConfigContext.js +1 -1
- package/dist/hooks/AppDetails/useAppDetails.cjs +6 -6
- package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.cts +2 -2
- package/dist/hooks/ImageResolver/useImageResolver.cjs +3 -3
- package/dist/hooks/Search/useSearch.cjs +4 -4
- package/dist/hooks/Search/useSearch.d.cts +1 -1
- package/dist/hooks/Search/useSearch.d.ts +1 -1
- package/dist/hooks/Search/useSearch.js +1 -1
- package/dist/services/amplitudeService/amplitudeService.cjs +49 -11
- package/dist/services/amplitudeService/amplitudeService.d.cts +18 -3
- package/dist/services/amplitudeService/amplitudeService.d.ts +18 -3
- package/dist/services/amplitudeService/amplitudeService.js +49 -12
- package/dist/services/amplitudeService/index.cjs +1 -0
- package/dist/services/amplitudeService/index.d.cts +2 -2
- package/dist/services/amplitudeService/index.d.ts +2 -2
- package/dist/services/amplitudeService/index.js +2 -2
- package/dist/types/customerService.d.cts +3 -1
- package/dist/types/customerService.d.ts +1 -1
- package/dist/types/enviveConfig.d.cts +4 -1
- package/dist/types/enviveConfig.d.ts +4 -1
- package/package.json +10 -2
- package/src/application/commerce-api.ts +25 -20
- package/src/application/models/api/widgetText.ts +2 -0
- package/src/application/models/api/widgetTextRequest.ts +2 -0
- package/src/application/models/chatElementDisplayLocationV3.ts +3 -0
- package/src/application/models/variantInfo/variantInfo.ts +5 -0
- package/src/application/utils/nodeSelector.ts +15 -14
- package/src/application/utils/widgetTextFromApiWidgetTextResponse.ts +2 -0
- package/src/application/utils/widgetTextRequestToApiRequest.ts +5 -0
- package/src/atoms/app/variant.ts +56 -2
- package/src/contexts/amplitudeContext/__tests__/amplitudeContext.test.tsx +2 -0
- package/src/contexts/amplitudeContext/amplitudeContext.tsx +5 -1
- package/src/contexts/enviveConfigContext/enviveConfigContext.tsx +3 -0
- package/src/contexts/enviveContext/WindowChatToggleBinder.tsx +5 -1
- package/src/contexts/enviveContext/enviveContext.tsx +10 -3
- package/src/contexts/featureFlagServiceContext/featureFlagServiceContext.tsx +36 -0
- package/src/contexts/graphqlContext/mockV3Config.ts +13 -7
- package/src/contexts/hardcopyContext/hardcopyContext.tsx +67 -4
- package/src/contexts/pageContext/mapping.ts +13 -1
- package/src/contexts/pageContext/pageContext.tsx +9 -4
- package/src/contexts/pageContext/types.ts +7 -1
- package/src/contexts/salesAgentContext/chatAPI.ts +105 -13
- package/src/contexts/salesAgentContext/salesAgentService.ts +66 -4
- package/src/contexts/types.ts +11 -2
- package/src/contexts/typesV3.ts +42 -16
- package/src/services/amplitudeService/__tests__/amplitudeService.test.ts +80 -0
- package/src/services/amplitudeService/amplitudeService.ts +55 -11
- package/src/types/enviveConfig.ts +3 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// This component will interact with the backend API to get the responses from the sales agent.
|
|
2
|
-
|
|
2
|
+
import Logger from 'src/application/logging/logger';
|
|
3
3
|
import { PageVisitCategory, UserEventCategory } from '@spiffy-ai/commerce-api-client';
|
|
4
4
|
import {
|
|
5
5
|
ChatElementDisplayLocationV3,
|
|
@@ -9,13 +9,21 @@ import {
|
|
|
9
9
|
Suggestion,
|
|
10
10
|
UserEvent,
|
|
11
11
|
} from 'src/application/models';
|
|
12
|
-
import { useSetAtom } from 'jotai';
|
|
12
|
+
import { useAtomValue, useSetAtom } from 'jotai';
|
|
13
13
|
import { useCallback } from 'react';
|
|
14
14
|
import { v4 as uuid } from 'uuid';
|
|
15
15
|
import { formSubmitAtom, replyEventCategoryAtom } from 'src/atoms/chat';
|
|
16
16
|
import { queueUserEventAtom } from 'src/atoms/chat/messageQueue';
|
|
17
|
+
import { EnviveMetricsEventName } from 'src/services/amplitudeService/amplitudeService';
|
|
18
|
+
import { analyticsContextAtom } from 'src/atoms/app/variant';
|
|
19
|
+
import { hasParsedVariantInfoAtom } from 'src/atoms/app';
|
|
17
20
|
import { SpiffyMetricsEventName, useAmplitude } from '../amplitudeContext';
|
|
18
21
|
|
|
22
|
+
const TRACKED_USER_EVENTS = [
|
|
23
|
+
UserEventCategory.PageVisit,
|
|
24
|
+
UserEventCategory.PdpVisit,
|
|
25
|
+
UserEventCategory.PlpVisit,
|
|
26
|
+
];
|
|
19
27
|
export interface SalesAgentChatAPI {
|
|
20
28
|
logPageVisit: ({ pageVisitCategory }: { pageVisitCategory: PageVisitCategory }) => void;
|
|
21
29
|
logUserEvent: (event: UserEvent) => void;
|
|
@@ -23,13 +31,23 @@ export interface SalesAgentChatAPI {
|
|
|
23
31
|
suggestion: Suggestion,
|
|
24
32
|
displayLocation: ChatElementDisplayLocationV3,
|
|
25
33
|
) => void;
|
|
26
|
-
onTypedMessageSubmitted: ({
|
|
27
|
-
|
|
34
|
+
onTypedMessageSubmitted: ({
|
|
35
|
+
query,
|
|
36
|
+
userTyped,
|
|
37
|
+
displayLocation,
|
|
38
|
+
}: {
|
|
39
|
+
query: string;
|
|
40
|
+
userTyped: boolean;
|
|
41
|
+
displayLocation: ChatElementDisplayLocationV3;
|
|
42
|
+
}) => void;
|
|
43
|
+
onFormResponseSubmitted: (form: FormSubmittedAttributes) => void;
|
|
28
44
|
}
|
|
29
45
|
|
|
30
46
|
export const useSalesAgentChatAPI = () => {
|
|
31
47
|
// TODO: Each of these functions will trigger both the necessary amplitude events and initiate the
|
|
32
48
|
// necessary actions to trigger the backend API
|
|
49
|
+
const context = useAtomValue(analyticsContextAtom);
|
|
50
|
+
const hasParsedVariantInfo = useAtomValue(hasParsedVariantInfoAtom);
|
|
33
51
|
const queueUserEvent = useSetAtom(queueUserEventAtom);
|
|
34
52
|
const setReplyEventCategory = useSetAtom(replyEventCategoryAtom);
|
|
35
53
|
const setFormSubmit = useSetAtom(formSubmitAtom);
|
|
@@ -37,8 +55,17 @@ export const useSalesAgentChatAPI = () => {
|
|
|
37
55
|
|
|
38
56
|
const logPageVisit = useCallback(
|
|
39
57
|
({ pageVisitCategory }: { pageVisitCategory: PageVisitCategory }) => {
|
|
58
|
+
const eventId = uuid();
|
|
59
|
+
trackEvent({
|
|
60
|
+
eventName: EnviveMetricsEventName.ChatRequest,
|
|
61
|
+
eventProps: {
|
|
62
|
+
...context,
|
|
63
|
+
'chat.request_id': eventId,
|
|
64
|
+
'chat.request_type': 'page_visit',
|
|
65
|
+
},
|
|
66
|
+
});
|
|
40
67
|
const event: UserEvent = {
|
|
41
|
-
eventId
|
|
68
|
+
eventId,
|
|
42
69
|
category: UserEventCategory.PageVisit,
|
|
43
70
|
createdAt: new Date().toISOString(),
|
|
44
71
|
attributes: {
|
|
@@ -48,14 +75,32 @@ export const useSalesAgentChatAPI = () => {
|
|
|
48
75
|
};
|
|
49
76
|
queueUserEvent(event);
|
|
50
77
|
},
|
|
51
|
-
[queueUserEvent],
|
|
78
|
+
[queueUserEvent, context, trackEvent],
|
|
52
79
|
);
|
|
53
80
|
|
|
54
81
|
const logUserEvent = useCallback(
|
|
55
82
|
(event: UserEvent) => {
|
|
83
|
+
if (!hasParsedVariantInfo) {
|
|
84
|
+
Logger.logWarn(
|
|
85
|
+
'[envive-ai] hasParsedVariantInfo is false, not logging user event',
|
|
86
|
+
undefined,
|
|
87
|
+
{ event },
|
|
88
|
+
);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (TRACKED_USER_EVENTS.includes(event.category)) {
|
|
92
|
+
trackEvent({
|
|
93
|
+
eventName: EnviveMetricsEventName.ChatRequest,
|
|
94
|
+
eventProps: {
|
|
95
|
+
...context,
|
|
96
|
+
'chat.request_id': event.eventId,
|
|
97
|
+
'chat.request_type': 'page_visit',
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
56
101
|
queueUserEvent(event);
|
|
57
102
|
},
|
|
58
|
-
[queueUserEvent],
|
|
103
|
+
[context, hasParsedVariantInfo, queueUserEvent, trackEvent],
|
|
59
104
|
);
|
|
60
105
|
const onSuggestionClicked = useCallback(
|
|
61
106
|
(suggestion: Suggestion, displayLocation: ChatElementDisplayLocationV3) => {
|
|
@@ -74,8 +119,24 @@ export const useSalesAgentChatAPI = () => {
|
|
|
74
119
|
},
|
|
75
120
|
},
|
|
76
121
|
});
|
|
122
|
+
const eventId = uuid();
|
|
123
|
+
trackEvent({
|
|
124
|
+
eventName: EnviveMetricsEventName.ChatRequest,
|
|
125
|
+
eventProps: {
|
|
126
|
+
...context,
|
|
127
|
+
'trigger.widget': displayLocation, // This is fairly finegrained, but that may be ok
|
|
128
|
+
'chat.request_id': eventId,
|
|
129
|
+
'chat.request_type': 'suggestion',
|
|
130
|
+
'chat.request_text': suggestion.content,
|
|
131
|
+
'chat.suggestion_id': suggestion.id,
|
|
132
|
+
'chat.suggestion_category': suggestion.category,
|
|
133
|
+
'chat.suggestion_created_at': suggestion.createdAt,
|
|
134
|
+
'chat.suggestion_is_answer': suggestion.isAnswer,
|
|
135
|
+
'chat.user_typed': false,
|
|
136
|
+
},
|
|
137
|
+
});
|
|
77
138
|
const event: UserEvent = {
|
|
78
|
-
eventId
|
|
139
|
+
eventId,
|
|
79
140
|
category: UserEventCategory.SuggestionClicked,
|
|
80
141
|
createdAt: new Date().toISOString(),
|
|
81
142
|
attributes: {
|
|
@@ -85,10 +146,18 @@ export const useSalesAgentChatAPI = () => {
|
|
|
85
146
|
};
|
|
86
147
|
queueUserEvent(event);
|
|
87
148
|
},
|
|
88
|
-
[queueUserEvent, trackEvent],
|
|
149
|
+
[queueUserEvent, trackEvent, context],
|
|
89
150
|
);
|
|
90
151
|
const onTypedMessageSubmitted = useCallback(
|
|
91
|
-
({
|
|
152
|
+
({
|
|
153
|
+
query,
|
|
154
|
+
userTyped,
|
|
155
|
+
displayLocation,
|
|
156
|
+
}: {
|
|
157
|
+
query: string;
|
|
158
|
+
userTyped: boolean;
|
|
159
|
+
displayLocation: ChatElementDisplayLocationV3;
|
|
160
|
+
}) => {
|
|
92
161
|
const eventId = uuid();
|
|
93
162
|
trackEvent({
|
|
94
163
|
eventName: SpiffyMetricsEventName.ChatUserMessageInput,
|
|
@@ -105,6 +174,18 @@ export const useSalesAgentChatAPI = () => {
|
|
|
105
174
|
},
|
|
106
175
|
},
|
|
107
176
|
});
|
|
177
|
+
trackEvent({
|
|
178
|
+
eventName: EnviveMetricsEventName.ChatRequest,
|
|
179
|
+
eventProps: {
|
|
180
|
+
...context,
|
|
181
|
+
'trigger.widget': displayLocation,
|
|
182
|
+
'chat.request_type': 'text',
|
|
183
|
+
'chat.request_text': query,
|
|
184
|
+
'chat.request_id': eventId,
|
|
185
|
+
'chat.request_created_at': new Date().toISOString(),
|
|
186
|
+
'chat.user_typed': userTyped,
|
|
187
|
+
},
|
|
188
|
+
});
|
|
108
189
|
const event: UserEvent = {
|
|
109
190
|
eventId,
|
|
110
191
|
category: UserEventCategory.QueryTyped,
|
|
@@ -116,21 +197,32 @@ export const useSalesAgentChatAPI = () => {
|
|
|
116
197
|
};
|
|
117
198
|
queueUserEvent(event);
|
|
118
199
|
},
|
|
119
|
-
[queueUserEvent, trackEvent],
|
|
200
|
+
[queueUserEvent, trackEvent, context],
|
|
120
201
|
);
|
|
121
202
|
const onFormResponseSubmitted = useCallback(
|
|
122
203
|
(form: FormSubmittedAttributes) => {
|
|
123
204
|
setReplyEventCategory(UserEventCategory.FormSubmitted);
|
|
124
205
|
setFormSubmit(form);
|
|
206
|
+
const eventId = uuid();
|
|
207
|
+
trackEvent({
|
|
208
|
+
eventName: EnviveMetricsEventName.ChatRequest,
|
|
209
|
+
eventProps: {
|
|
210
|
+
...context,
|
|
211
|
+
'chat.request_id': eventId,
|
|
212
|
+
'chat.request_type': 'form',
|
|
213
|
+
'chat.form_response_id': form.formResponseId,
|
|
214
|
+
'chat.form_type': form.formType,
|
|
215
|
+
},
|
|
216
|
+
});
|
|
125
217
|
const event: UserEvent = {
|
|
126
|
-
eventId
|
|
218
|
+
eventId,
|
|
127
219
|
category: UserEventCategory.FormSubmitted,
|
|
128
220
|
createdAt: new Date().toISOString(),
|
|
129
221
|
attributes: form,
|
|
130
222
|
};
|
|
131
223
|
queueUserEvent(event);
|
|
132
224
|
},
|
|
133
|
-
[
|
|
225
|
+
[setReplyEventCategory, setFormSubmit, trackEvent, context, queueUserEvent],
|
|
134
226
|
);
|
|
135
227
|
|
|
136
228
|
return {
|
|
@@ -25,6 +25,8 @@ import { useMessageInterceptor } from 'src/interceptors/useMessageInterceptor';
|
|
|
25
25
|
import { SpiffyMetricsEventName, useAmplitude } from 'src/contexts/amplitudeContext';
|
|
26
26
|
import { useFeatureFlagService } from 'src/contexts/featureFlagServiceContext';
|
|
27
27
|
import { UserEventCategory } from '@spiffy-ai/commerce-api-client';
|
|
28
|
+
import { EnviveMetricsEventName } from 'src/services/amplitudeService/amplitudeService';
|
|
29
|
+
import { analyticsContextAtom } from 'src/atoms/app/variant';
|
|
28
30
|
|
|
29
31
|
import { StatusCodeError } from './statusCodeError';
|
|
30
32
|
|
|
@@ -59,6 +61,41 @@ const inputPropsToTrackingProps = (
|
|
|
59
61
|
return {};
|
|
60
62
|
};
|
|
61
63
|
|
|
64
|
+
const inputPropsToEnviveTrackingProps = (
|
|
65
|
+
payload: NextMessageRequest,
|
|
66
|
+
): Record<string, unknown> | undefined => {
|
|
67
|
+
const [userEvent] = payload.userEvents || [];
|
|
68
|
+
if (userEvent.category === UserEventCategory.SuggestionClicked) {
|
|
69
|
+
return {
|
|
70
|
+
'chat.request_type': 'suggestion',
|
|
71
|
+
'chat.request_id': userEvent.eventId,
|
|
72
|
+
'chat.request_text': userEvent.attributes.content,
|
|
73
|
+
'chat.suggestion_id': userEvent.attributes.suggestionId,
|
|
74
|
+
'chat.user_typed': false,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (userEvent.category === UserEventCategory.QueryTyped) {
|
|
78
|
+
return {
|
|
79
|
+
'chat.request_type': 'text',
|
|
80
|
+
'chat.request_id': userEvent.eventId,
|
|
81
|
+
'chat.request_text': userEvent.attributes.query,
|
|
82
|
+
'chat.user_typed': userEvent.attributes.userTyped,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (
|
|
86
|
+
userEvent.category === UserEventCategory.PageVisit ||
|
|
87
|
+
userEvent.category === UserEventCategory.PdpVisit ||
|
|
88
|
+
userEvent.category === UserEventCategory.PlpVisit
|
|
89
|
+
) {
|
|
90
|
+
return {
|
|
91
|
+
'chat.request_id': userEvent.eventId,
|
|
92
|
+
'chat.request_type': 'page_visit',
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {};
|
|
97
|
+
};
|
|
98
|
+
|
|
62
99
|
export const getQueryParam = (key: string): string | null => {
|
|
63
100
|
const urlObj = new URL(window.location.href);
|
|
64
101
|
return urlObj.searchParams.get(key);
|
|
@@ -137,14 +174,15 @@ const processStreamingResponse = async (
|
|
|
137
174
|
messageInterceptor: { intercept: (response?: Response) => boolean | undefined },
|
|
138
175
|
setMessages: (updater: (prev: Message[][]) => Message[][]) => void,
|
|
139
176
|
setResponseStreaming: (responseStreaming: boolean) => void,
|
|
140
|
-
): Promise<
|
|
177
|
+
): Promise<Record<string, number>> => {
|
|
141
178
|
let lastMessage: Message | undefined;
|
|
142
179
|
setResponseStreaming(true);
|
|
180
|
+
const responseAnalytics: Record<string, number> = {};
|
|
143
181
|
|
|
144
182
|
for await (const response of stream) {
|
|
145
183
|
try {
|
|
146
184
|
if (messageInterceptor.intercept(response)) {
|
|
147
|
-
return;
|
|
185
|
+
return {};
|
|
148
186
|
}
|
|
149
187
|
|
|
150
188
|
if (!response) {
|
|
@@ -155,6 +193,14 @@ const processStreamingResponse = async (
|
|
|
155
193
|
if (!message) {
|
|
156
194
|
throw new Error('Failed to transform API response to client message');
|
|
157
195
|
}
|
|
196
|
+
if (message.type === MessageType.Product) {
|
|
197
|
+
responseAnalytics['chat.product_cards_returned'] =
|
|
198
|
+
(responseAnalytics['chat.product_cards_returned'] || 0) + 1;
|
|
199
|
+
}
|
|
200
|
+
if (message.type === MessageType.Review) {
|
|
201
|
+
responseAnalytics['chat.review_cards_returned'] =
|
|
202
|
+
(responseAnalytics['chat.review_cards_returned'] || 0) + 1;
|
|
203
|
+
}
|
|
158
204
|
|
|
159
205
|
// No support for ChatSearch messages at the current time.
|
|
160
206
|
// Perhaps we add support back in the future
|
|
@@ -173,6 +219,7 @@ const processStreamingResponse = async (
|
|
|
173
219
|
}
|
|
174
220
|
setResponseStreaming(false);
|
|
175
221
|
}
|
|
222
|
+
return responseAnalytics;
|
|
176
223
|
};
|
|
177
224
|
|
|
178
225
|
export const useSalesAgentService: () => SalesAgentService = () => {
|
|
@@ -181,6 +228,7 @@ export const useSalesAgentService: () => SalesAgentService = () => {
|
|
|
181
228
|
const setSuggestions = useSetAtom(suggestionsAtom);
|
|
182
229
|
const setPendingResponse = useSetAtom(pendingResponseAtom);
|
|
183
230
|
const setResponseStreaming = useSetAtom(responseStreamingAtom);
|
|
231
|
+
const analyticsContext = useAtomValue(analyticsContextAtom);
|
|
184
232
|
const messageInterceptor = useMessageInterceptor();
|
|
185
233
|
const { trackEvent } = useAmplitude();
|
|
186
234
|
|
|
@@ -220,12 +268,13 @@ export const useSalesAgentService: () => SalesAgentService = () => {
|
|
|
220
268
|
const startTime = Date.now();
|
|
221
269
|
let successfulResponse: boolean | undefined;
|
|
222
270
|
setPendingResponse(true);
|
|
271
|
+
setSuggestions([]);
|
|
223
272
|
const stream = CommerceApiClient.getNextResponseStreaming(payload);
|
|
224
|
-
|
|
273
|
+
let responseAnalytics: Record<string, unknown> | undefined;
|
|
225
274
|
try {
|
|
226
275
|
setRequestFailure(false);
|
|
227
276
|
|
|
228
|
-
await processStreamingResponse(
|
|
277
|
+
responseAnalytics = await processStreamingResponse(
|
|
229
278
|
stream,
|
|
230
279
|
messageInterceptor,
|
|
231
280
|
setMessages,
|
|
@@ -274,14 +323,27 @@ export const useSalesAgentService: () => SalesAgentService = () => {
|
|
|
274
323
|
...inputPropsToTrackingProps(payload),
|
|
275
324
|
},
|
|
276
325
|
});
|
|
326
|
+
trackEvent({
|
|
327
|
+
eventName: EnviveMetricsEventName.ChatResponse,
|
|
328
|
+
eventProps: {
|
|
329
|
+
...analyticsContext,
|
|
330
|
+
'chat.response_time_ms': responseTime.toString(),
|
|
331
|
+
...inputPropsToEnviveTrackingProps(payload),
|
|
332
|
+
...responseAnalytics,
|
|
333
|
+
},
|
|
334
|
+
});
|
|
277
335
|
setPendingResponse(false);
|
|
278
336
|
setResponseStreaming(false);
|
|
279
337
|
// logPerfMetric(PerfMetricsEvents.FirstResponseCompleted);
|
|
280
338
|
}
|
|
281
339
|
},
|
|
282
340
|
[
|
|
341
|
+
analyticsContext,
|
|
342
|
+
trackEvent,
|
|
343
|
+
setResponseStreaming,
|
|
283
344
|
// logPerfMetric,
|
|
284
345
|
setRequestFailure,
|
|
346
|
+
setSuggestions,
|
|
285
347
|
messageInterceptor,
|
|
286
348
|
setMessages,
|
|
287
349
|
setPendingResponse,
|
package/src/contexts/types.ts
CHANGED
|
@@ -13,7 +13,8 @@ import { ChatState } from 'src/types/custservice-types';
|
|
|
13
13
|
import { SuggestionBarLocationForMetrics } from 'src/types/suggestionBarV2-types';
|
|
14
14
|
import { TestProps } from 'src/types/test-types';
|
|
15
15
|
import { OrgConfigFeatureGate } from 'src/application/models/api/orgConfigResults';
|
|
16
|
-
import { WidgetConfigV3 } from './typesV3';
|
|
16
|
+
import { WidgetConfigV3, WidgetTypeV3 } from './typesV3';
|
|
17
|
+
import type { HardcopyResponse } from './hardcopyContext/hardcopyContext';
|
|
17
18
|
|
|
18
19
|
type ShowFloatingButtonOptions =
|
|
19
20
|
| 'always'
|
|
@@ -863,6 +864,7 @@ type PageVariantBase = {
|
|
|
863
864
|
variantId: string;
|
|
864
865
|
widgetMounting: WidgetMounting[];
|
|
865
866
|
variantTests: PageVariantTest[];
|
|
867
|
+
floatingButtonOverride?: ShowFloatingButtonOptions;
|
|
866
868
|
};
|
|
867
869
|
|
|
868
870
|
type PLPPageVariant = PageVariantBase & {
|
|
@@ -892,13 +894,18 @@ type SearchPageVariant = PageVariantBase & {
|
|
|
892
894
|
variantType: 'search';
|
|
893
895
|
};
|
|
894
896
|
|
|
897
|
+
type FullPageSalesAgentVariant = PageVariantBase & {
|
|
898
|
+
variantType: 'full_page';
|
|
899
|
+
};
|
|
900
|
+
|
|
895
901
|
export type PageVariantConfig =
|
|
896
902
|
| PLPPageVariant
|
|
897
903
|
| PDPPageVariant
|
|
898
904
|
| VisitPageVariant
|
|
899
905
|
| OtherPageVariant
|
|
900
906
|
| HomePageVariant
|
|
901
|
-
| SearchPageVariant
|
|
907
|
+
| SearchPageVariant
|
|
908
|
+
| FullPageSalesAgentVariant;
|
|
902
909
|
|
|
903
910
|
export type OrgPageConfig = {
|
|
904
911
|
// pageVariants is a list of page variants that we support.
|
|
@@ -928,8 +935,10 @@ export interface EnviveConfig {
|
|
|
928
935
|
variantUrlOverride?: string;
|
|
929
936
|
variantInfoOverride?: any;
|
|
930
937
|
show?: boolean;
|
|
938
|
+
enviveOn?: boolean;
|
|
931
939
|
publicKey?: string;
|
|
932
940
|
featureGates?: OrgConfigFeatureGate[];
|
|
941
|
+
hardcopyOverride?: Partial<Record<WidgetTypeV3, HardcopyResponse>>;
|
|
933
942
|
}
|
|
934
943
|
|
|
935
944
|
export type {
|
package/src/contexts/typesV3.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FloatingButtonLocation } from '@envive-ai/react-toolkit-v3/FloatingButton';
|
|
2
2
|
import { ImageGalleryImage, ImageGalleryLayout } from '@envive-ai/react-toolkit-v3/ImageGallery';
|
|
3
3
|
import { PromptButtonVariant } from '@envive-ai/react-toolkit-v3/PromptButton';
|
|
4
|
-
import {
|
|
5
|
-
import { Theme } from '@envive-ai/react-toolkit-v3/Tokens';
|
|
4
|
+
import { AnimationSpeed, PromptCarouselRows } from '@envive-ai/react-toolkit-v3/PromptCarousel';
|
|
6
5
|
import { DynamicLayout, WidgetKind } from '@envive-ai/react-toolkit-v3/SocialProof';
|
|
6
|
+
import { Theme } from '@envive-ai/react-toolkit-v3/Tokens';
|
|
7
7
|
import { SparkleIconColor } from '@envive-ai/react-toolkit-v3/WelcomeMessage';
|
|
8
|
-
import {
|
|
8
|
+
import { WidgetWrapperVariant } from '@envive-ai/react-toolkit-v3/WidgetWrapper';
|
|
9
9
|
import { ColorNames } from '../application/models/colorsConfigV3';
|
|
10
10
|
import { CustomerServiceType } from '../types/customerService';
|
|
11
11
|
import type { SearchConfig } from './types';
|
|
@@ -184,6 +184,23 @@ type FloatingButtonConfig = {
|
|
|
184
184
|
style: Style;
|
|
185
185
|
};
|
|
186
186
|
|
|
187
|
+
export type ReferrerPopupTrigger = {
|
|
188
|
+
type: 'referrer';
|
|
189
|
+
referrers: string[];
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
export type AutomaticPopupTrigger = {
|
|
193
|
+
type: 'automatic';
|
|
194
|
+
};
|
|
195
|
+
export type PopupTrigger = ReferrerPopupTrigger | AutomaticPopupTrigger;
|
|
196
|
+
export type AutoPopupTrigger = {
|
|
197
|
+
delay: number;
|
|
198
|
+
trigger: PopupTrigger;
|
|
199
|
+
};
|
|
200
|
+
export interface AutoPopupConfig {
|
|
201
|
+
triggers: AutoPopupTrigger[];
|
|
202
|
+
}
|
|
203
|
+
|
|
187
204
|
type FloatingChatConfig = {
|
|
188
205
|
headerBackgroundColor?: string;
|
|
189
206
|
headerMode: Mode;
|
|
@@ -196,6 +213,7 @@ type FloatingChatConfig = {
|
|
|
196
213
|
welcomeMessageTitle: string;
|
|
197
214
|
welcomeMessageText: string;
|
|
198
215
|
chatFooterTextFieldPlaceholderText: string;
|
|
216
|
+
autoPopupConfig?: AutoPopupConfig;
|
|
199
217
|
};
|
|
200
218
|
|
|
201
219
|
type CustomerServiceIntegration = {
|
|
@@ -246,6 +264,7 @@ export enum WidgetTypeV3 {
|
|
|
246
264
|
FloatingChatV3 = 'FloatingChatV3',
|
|
247
265
|
FloatingButtonV3 = 'FloatingButtonV3',
|
|
248
266
|
ProductCardV3 = 'ProductCardV3',
|
|
267
|
+
FullPageSalesAgentV3 = 'FullPageSalesAgentV3',
|
|
249
268
|
}
|
|
250
269
|
|
|
251
270
|
interface BaseWidgetConfig<T extends WidgetTypeV3> {
|
|
@@ -324,6 +343,11 @@ interface ProductCardWidgetV3Config extends BaseWidgetConfig<WidgetTypeV3.Produc
|
|
|
324
343
|
imageSrc?: string;
|
|
325
344
|
}
|
|
326
345
|
|
|
346
|
+
interface FullPageSalesAgentWidgetV3Config extends BaseWidgetConfig<WidgetTypeV3.FullPageSalesAgentV3> {
|
|
347
|
+
headerContainer?: string;
|
|
348
|
+
autoHeight?: boolean;
|
|
349
|
+
}
|
|
350
|
+
|
|
327
351
|
type WidgetConfigV3 =
|
|
328
352
|
| PromptCarouselWidgetV3Config
|
|
329
353
|
| SocialProofWidgetV3Config
|
|
@@ -334,24 +358,26 @@ type WidgetConfigV3 =
|
|
|
334
358
|
| ChatPreviewWidgetV3Config
|
|
335
359
|
| PromptButtonCarouselWithImageWidgetV3Config
|
|
336
360
|
| FloatingChatWidgetV3Config
|
|
337
|
-
| ProductCardWidgetV3Config
|
|
361
|
+
| ProductCardWidgetV3Config
|
|
362
|
+
| FullPageSalesAgentWidgetV3Config;
|
|
338
363
|
|
|
339
364
|
export type {
|
|
340
|
-
OrgUIConfigV3,
|
|
341
|
-
WidgetConfigV3,
|
|
342
|
-
LookAndFeelConfig,
|
|
343
|
-
SocialProofWidgetV3Config,
|
|
344
|
-
PromptCarouselWidgetV3Config,
|
|
345
365
|
ChatPreviewComparisonWidgetV3Config,
|
|
346
366
|
ChatPreviewLoadingWidgetV3Config,
|
|
347
367
|
ChatPreviewWidgetV3Config,
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
368
|
+
CustomerServiceIntegration,
|
|
369
|
+
FloatingButtonConfig,
|
|
370
|
+
FloatingChatConfig,
|
|
351
371
|
FloatingChatWidgetV3Config,
|
|
372
|
+
FullPageSalesAgentWidgetV3Config,
|
|
373
|
+
LookAndFeelConfig,
|
|
374
|
+
OrgUIConfigV3,
|
|
352
375
|
ProductCardWidgetV3Config,
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
376
|
+
PromptButtonCarouselWithImageWidgetV3Config,
|
|
377
|
+
PromptCarouselWidgetV3Config,
|
|
378
|
+
SocialProofWidgetV3Config,
|
|
356
379
|
SPASettings,
|
|
380
|
+
TitledPromptCarouselWidgetV3Config,
|
|
381
|
+
TypingAnimationWidgetV3Config,
|
|
382
|
+
WidgetConfigV3,
|
|
357
383
|
};
|
|
@@ -66,6 +66,23 @@ describe('AmplitudeService', () => {
|
|
|
66
66
|
mockAdd.mockClear();
|
|
67
67
|
mockDigest.mockResolvedValue(new Uint8Array(32).fill(0));
|
|
68
68
|
mockDispatch.mockClear();
|
|
69
|
+
|
|
70
|
+
// Mock window.location for tests that need it
|
|
71
|
+
Object.defineProperty(global, 'window', {
|
|
72
|
+
value: {
|
|
73
|
+
location: {
|
|
74
|
+
href: 'https://test.example.com',
|
|
75
|
+
},
|
|
76
|
+
localStorage: {
|
|
77
|
+
getItem: vi.fn(),
|
|
78
|
+
},
|
|
79
|
+
performance: {
|
|
80
|
+
now: vi.fn(() => Date.now()),
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
writable: true,
|
|
84
|
+
configurable: true,
|
|
85
|
+
});
|
|
69
86
|
});
|
|
70
87
|
|
|
71
88
|
const createService = (overrides?: Partial<AmplitudeServiceConfig>) => {
|
|
@@ -76,6 +93,7 @@ describe('AmplitudeService', () => {
|
|
|
76
93
|
env: 'test',
|
|
77
94
|
orgId: 'test-org-id',
|
|
78
95
|
show: true,
|
|
96
|
+
enviveOn: true,
|
|
79
97
|
contextSource: 'app',
|
|
80
98
|
orgShortName: 'test-org',
|
|
81
99
|
featureFlagService,
|
|
@@ -108,6 +126,7 @@ describe('AmplitudeService', () => {
|
|
|
108
126
|
env: 'test',
|
|
109
127
|
orgId: 'test-org-id',
|
|
110
128
|
show: true,
|
|
129
|
+
enviveOn: true,
|
|
111
130
|
getLocalStorageItem: mockGetLocalStorageItem,
|
|
112
131
|
contextSource: 'app',
|
|
113
132
|
orgShortName: 'test-org',
|
|
@@ -125,6 +144,7 @@ describe('AmplitudeService', () => {
|
|
|
125
144
|
env: 'test',
|
|
126
145
|
orgId: 'test-org-id',
|
|
127
146
|
show: true,
|
|
147
|
+
enviveOn: true,
|
|
128
148
|
getLocalStorageItem: mockGetLocalStorageItem,
|
|
129
149
|
contextSource: 'app',
|
|
130
150
|
orgShortName: 'test-org',
|
|
@@ -142,6 +162,7 @@ describe('AmplitudeService', () => {
|
|
|
142
162
|
env: 'test',
|
|
143
163
|
orgId: 'test-org-id',
|
|
144
164
|
show: true,
|
|
165
|
+
enviveOn: true,
|
|
145
166
|
getLocalStorageItem: mockGetLocalStorageItem,
|
|
146
167
|
contextSource: 'app',
|
|
147
168
|
orgShortName: 'test-org',
|
|
@@ -209,6 +230,7 @@ describe('AmplitudeService', () => {
|
|
|
209
230
|
eventProps: { message: 'test', count: 5 },
|
|
210
231
|
});
|
|
211
232
|
|
|
233
|
+
expect(mockTrack).toHaveBeenCalled();
|
|
212
234
|
const callArgs = mockTrack.mock.calls[0];
|
|
213
235
|
const eventProps = callArgs[1];
|
|
214
236
|
|
|
@@ -238,6 +260,7 @@ describe('AmplitudeService', () => {
|
|
|
238
260
|
eventGroups: { group1: 'value1', group2: 'value2' },
|
|
239
261
|
});
|
|
240
262
|
|
|
263
|
+
expect(mockTrack).toHaveBeenCalled();
|
|
241
264
|
const callArgs = mockTrack.mock.calls[0];
|
|
242
265
|
expect(callArgs[2]).toHaveProperty('group1', 'value1');
|
|
243
266
|
expect(callArgs[2]).toHaveProperty('group2', 'value2');
|
|
@@ -251,6 +274,7 @@ describe('AmplitudeService', () => {
|
|
|
251
274
|
env: 'test',
|
|
252
275
|
orgId: 'test-org-id',
|
|
253
276
|
show: true,
|
|
277
|
+
enviveOn: true,
|
|
254
278
|
getLocalStorageItem: mockGetLocalStorageItem,
|
|
255
279
|
contextSource: 'app',
|
|
256
280
|
orgShortName: 'test-org',
|
|
@@ -304,6 +328,15 @@ describe('AmplitudeService', () => {
|
|
|
304
328
|
const dataLayer: any[] = [];
|
|
305
329
|
Object.defineProperty(global, 'window', {
|
|
306
330
|
value: {
|
|
331
|
+
location: {
|
|
332
|
+
href: 'https://test.example.com',
|
|
333
|
+
},
|
|
334
|
+
localStorage: {
|
|
335
|
+
getItem: vi.fn(),
|
|
336
|
+
},
|
|
337
|
+
performance: {
|
|
338
|
+
now: vi.fn(() => Date.now()),
|
|
339
|
+
},
|
|
307
340
|
dataLayer,
|
|
308
341
|
},
|
|
309
342
|
writable: true,
|
|
@@ -391,6 +424,7 @@ describe('AmplitudeService', () => {
|
|
|
391
424
|
env: 'test',
|
|
392
425
|
orgId: 'test-org-id',
|
|
393
426
|
show: true,
|
|
427
|
+
enviveOn: true,
|
|
394
428
|
getLocalStorageItem: null,
|
|
395
429
|
contextSource: 'app',
|
|
396
430
|
orgShortName: 'test-org',
|
|
@@ -408,7 +442,13 @@ describe('AmplitudeService', () => {
|
|
|
408
442
|
};
|
|
409
443
|
Object.defineProperty(global, 'window', {
|
|
410
444
|
value: {
|
|
445
|
+
location: {
|
|
446
|
+
href: 'https://test.example.com',
|
|
447
|
+
},
|
|
411
448
|
localStorage: mockLocalStorage,
|
|
449
|
+
performance: {
|
|
450
|
+
now: vi.fn(() => Date.now()),
|
|
451
|
+
},
|
|
412
452
|
},
|
|
413
453
|
writable: true,
|
|
414
454
|
configurable: true,
|
|
@@ -418,7 +458,9 @@ describe('AmplitudeService', () => {
|
|
|
418
458
|
eventName: SpiffyMetricsEventName.ChatUserMessageInput,
|
|
419
459
|
});
|
|
420
460
|
|
|
461
|
+
// Check that getItem was called with ChatId (may be called with other keys too)
|
|
421
462
|
expect(mockLocalStorage.getItem).toHaveBeenCalledWith(LocalStorageKeys.ChatId);
|
|
463
|
+
expect(mockTrack).toHaveBeenCalled();
|
|
422
464
|
const callArgs = mockTrack.mock.calls[0];
|
|
423
465
|
expect(callArgs[1]).toHaveProperty('chat_id', 'window-chat-id');
|
|
424
466
|
});
|
|
@@ -448,6 +490,7 @@ describe('AmplitudeService', () => {
|
|
|
448
490
|
eventName: SpiffyMetricsEventName.ChatUserMessageInput,
|
|
449
491
|
});
|
|
450
492
|
|
|
493
|
+
expect(mockTrack).toHaveBeenCalled();
|
|
451
494
|
const callArgs = mockTrack.mock.calls[0];
|
|
452
495
|
const eventProps = callArgs[1];
|
|
453
496
|
expect(eventProps).toHaveProperty('test', 'value');
|
|
@@ -456,6 +499,23 @@ describe('AmplitudeService', () => {
|
|
|
456
499
|
|
|
457
500
|
describe('Event enrichment', () => {
|
|
458
501
|
it('should enrich Page Viewed events', async () => {
|
|
502
|
+
// Ensure window.location is properly mocked
|
|
503
|
+
Object.defineProperty(global, 'window', {
|
|
504
|
+
value: {
|
|
505
|
+
location: {
|
|
506
|
+
href: 'https://test.example.com',
|
|
507
|
+
},
|
|
508
|
+
localStorage: {
|
|
509
|
+
getItem: vi.fn(),
|
|
510
|
+
},
|
|
511
|
+
performance: {
|
|
512
|
+
now: vi.fn(() => Date.now()),
|
|
513
|
+
},
|
|
514
|
+
},
|
|
515
|
+
writable: true,
|
|
516
|
+
configurable: true,
|
|
517
|
+
});
|
|
518
|
+
|
|
459
519
|
createService({
|
|
460
520
|
show: true,
|
|
461
521
|
});
|
|
@@ -487,6 +547,23 @@ describe('AmplitudeService', () => {
|
|
|
487
547
|
});
|
|
488
548
|
|
|
489
549
|
it('should enrich Bundle Loaded events', async () => {
|
|
550
|
+
// Ensure window.location is properly mocked
|
|
551
|
+
Object.defineProperty(global, 'window', {
|
|
552
|
+
value: {
|
|
553
|
+
location: {
|
|
554
|
+
href: 'https://test.example.com',
|
|
555
|
+
},
|
|
556
|
+
localStorage: {
|
|
557
|
+
getItem: vi.fn(),
|
|
558
|
+
},
|
|
559
|
+
performance: {
|
|
560
|
+
now: vi.fn(() => Date.now()),
|
|
561
|
+
},
|
|
562
|
+
},
|
|
563
|
+
writable: true,
|
|
564
|
+
configurable: true,
|
|
565
|
+
});
|
|
566
|
+
|
|
490
567
|
createService();
|
|
491
568
|
|
|
492
569
|
const enrichmentCall = mockAdd.mock.calls[0];
|
|
@@ -541,6 +618,9 @@ describe('AmplitudeService', () => {
|
|
|
541
618
|
it('should track multiple events with correct userId', async () => {
|
|
542
619
|
const service = createService();
|
|
543
620
|
|
|
621
|
+
// Ensure the service is ready
|
|
622
|
+
expect(service.isReady).toBe(true);
|
|
623
|
+
|
|
544
624
|
await service.trackEvent({
|
|
545
625
|
eventName: SpiffyMetricsEventName.ChatUserMessageInput,
|
|
546
626
|
eventProps: { event1: true },
|