@envive-ai/react-hooks 0.3.9 → 0.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/dist/application/commerce-api.cjs +14 -14
  2. package/dist/application/commerce-api.d.cts +58 -0
  3. package/dist/application/commerce-api.d.ts +59 -0
  4. package/dist/application/commerce-api.js +3 -3
  5. package/dist/application/models/api/widgetText.d.cts +14 -0
  6. package/dist/application/models/api/widgetText.d.ts +14 -0
  7. package/dist/application/models/api/widgetTextRequest.d.cts +15 -0
  8. package/dist/application/models/api/widgetTextRequest.d.ts +15 -0
  9. package/dist/application/models/chatElementDisplayLocationV3.cjs +2 -1
  10. package/dist/application/models/chatElementDisplayLocationV3.d.cts +2 -1
  11. package/dist/application/models/chatElementDisplayLocationV3.d.ts +2 -1
  12. package/dist/application/models/chatElementDisplayLocationV3.js +2 -1
  13. package/dist/application/models/guards/api/index.cjs +4 -4
  14. package/dist/application/models/guards/api/index.js +4 -4
  15. package/dist/application/models/guards/api/isApiFormResponse.cjs +1 -1
  16. package/dist/application/models/guards/api/isApiFormResponse.js +1 -1
  17. package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.cjs +1 -1
  18. package/dist/application/models/guards/api/isApiFormSubmittedResponseAttributes.js +1 -1
  19. package/dist/application/models/guards/api/isApiOrderResponseAttributes.cjs +1 -1
  20. package/dist/application/models/guards/api/isApiOrderResponseAttributes.js +1 -1
  21. package/dist/application/models/guards/api/isApiProductResponseAttributes.cjs +1 -1
  22. package/dist/application/models/guards/api/isApiProductResponseAttributes.js +1 -1
  23. package/dist/application/models/guards/api/isApiResponse.cjs +1 -1
  24. package/dist/application/models/guards/api/isApiResponse.js +1 -1
  25. package/dist/application/models/index.cjs +12 -12
  26. package/dist/application/models/index.d.cts +25 -25
  27. package/dist/application/models/index.d.ts +25 -25
  28. package/dist/application/models/index.js +12 -12
  29. package/dist/application/models/validators/validateGraphQLFrontendConfig.cjs +1 -1
  30. package/dist/application/models/validators/validateGraphQLFrontendConfig.js +1 -1
  31. package/dist/application/models/validators/validateUserEvent.cjs +2 -2
  32. package/dist/application/models/validators/validateUserEvent.js +2 -2
  33. package/dist/application/models/variantInfo/variantInfo.cjs +2 -1
  34. package/dist/application/models/variantInfo/variantInfo.d.cts +6 -1
  35. package/dist/application/models/variantInfo/variantInfo.d.ts +6 -1
  36. package/dist/application/models/variantInfo/variantInfo.js +2 -1
  37. package/dist/application/utils/analyticsUtils.cjs +1 -1
  38. package/dist/application/utils/analyticsUtils.js +1 -1
  39. package/dist/application/utils/widgetTextFromApiWidgetTextResponse.cjs +3 -1
  40. package/dist/application/utils/widgetTextFromApiWidgetTextResponse.js +3 -1
  41. package/dist/application/utils/widgetTextRequestToApiRequest.cjs +3 -1
  42. package/dist/application/utils/widgetTextRequestToApiRequest.js +3 -1
  43. package/dist/atoms/app/index.cjs +7 -7
  44. package/dist/atoms/app/index.d.cts +8 -8
  45. package/dist/atoms/app/index.d.ts +8 -8
  46. package/dist/atoms/app/index.js +1 -1
  47. package/dist/atoms/app/variant.cjs +44 -4
  48. package/dist/atoms/app/variant.d.cts +8 -8
  49. package/dist/atoms/app/variant.d.ts +8 -8
  50. package/dist/atoms/app/variant.js +44 -5
  51. package/dist/atoms/chat/chatState.d.cts +17 -17
  52. package/dist/atoms/chat/chatState.d.ts +18 -18
  53. package/dist/atoms/chat/form.cjs +1 -1
  54. package/dist/atoms/chat/form.d.cts +2 -2
  55. package/dist/atoms/chat/form.d.ts +2 -2
  56. package/dist/atoms/chat/form.js +1 -1
  57. package/dist/atoms/chat/index.cjs +1 -1
  58. package/dist/atoms/chat/index.d.cts +2 -2
  59. package/dist/atoms/chat/index.d.ts +2 -2
  60. package/dist/atoms/chat/index.js +1 -1
  61. package/dist/atoms/chat/lastMessage.d.cts +2 -2
  62. package/dist/atoms/chat/lastMessage.d.ts +2 -2
  63. package/dist/atoms/chat/messageQueue.d.cts +6 -6
  64. package/dist/atoms/chat/messageQueue.d.ts +6 -6
  65. package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
  66. package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
  67. package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
  68. package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
  69. package/dist/atoms/chat/replies.d.cts +3 -3
  70. package/dist/atoms/chat/replies.d.ts +3 -3
  71. package/dist/atoms/chat/suggestions.d.cts +2 -2
  72. package/dist/atoms/chat/suggestions.d.ts +2 -2
  73. package/dist/atoms/envive/enviveConfig.d.cts +19 -0
  74. package/dist/atoms/envive/enviveConfig.d.ts +19 -0
  75. package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
  76. package/dist/atoms/globalSearch/globalSearch.d.ts +5 -5
  77. package/dist/atoms/org/customerService.d.cts +6 -6
  78. package/dist/atoms/org/customerService.d.ts +6 -6
  79. package/dist/atoms/org/graphqlConfig.d.cts +4 -4
  80. package/dist/atoms/org/graphqlConfig.d.ts +4 -4
  81. package/dist/atoms/org/index.cjs +1 -1
  82. package/dist/atoms/org/index.js +1 -1
  83. package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
  84. package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
  85. package/dist/atoms/org/orgAnalyticsConfig.d.cts +5 -5
  86. package/dist/atoms/org/orgAnalyticsConfig.d.ts +5 -5
  87. package/dist/atoms/search/chatSearch.cjs +2 -2
  88. package/dist/atoms/search/chatSearch.d.cts +17 -17
  89. package/dist/atoms/search/chatSearch.d.ts +17 -17
  90. package/dist/atoms/search/chatSearch.js +2 -2
  91. package/dist/atoms/search/searchAPI.cjs +1 -1
  92. package/dist/atoms/search/searchAPI.d.cts +13 -13
  93. package/dist/atoms/search/searchAPI.d.ts +13 -13
  94. package/dist/atoms/search/searchAPI.js +1 -1
  95. package/dist/atoms/widget/chatPreviewLoading.d.cts +2 -2
  96. package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
  97. package/dist/contexts/amplitudeContext/amplitudeContext.cjs +10 -7
  98. package/dist/contexts/amplitudeContext/amplitudeContext.d.cts +2 -2
  99. package/dist/contexts/amplitudeContext/amplitudeContext.d.ts +2 -2
  100. package/dist/contexts/amplitudeContext/amplitudeContext.js +6 -3
  101. package/dist/contexts/amplitudeContext/index.cjs +1 -0
  102. package/dist/contexts/amplitudeContext/index.d.cts +2 -2
  103. package/dist/contexts/amplitudeContext/index.d.ts +2 -2
  104. package/dist/contexts/amplitudeContext/index.js +2 -2
  105. package/dist/contexts/cdnContext/cdnContext.cjs +3 -3
  106. package/dist/contexts/enviveConfigContext/enviveConfigContext.cjs +6 -5
  107. package/dist/contexts/enviveConfigContext/enviveConfigContext.d.cts +2 -1
  108. package/dist/contexts/enviveConfigContext/enviveConfigContext.d.ts +2 -1
  109. package/dist/contexts/enviveConfigContext/enviveConfigContext.js +3 -2
  110. package/dist/contexts/enviveContext/WindowChatToggleBinder.cjs +4 -3
  111. package/dist/contexts/enviveContext/WindowChatToggleBinder.js +4 -3
  112. package/dist/contexts/enviveContext/enviveContext.cjs +15 -11
  113. package/dist/contexts/enviveContext/enviveContext.d.cts +2 -1
  114. package/dist/contexts/enviveContext/enviveContext.d.ts +2 -1
  115. package/dist/contexts/enviveContext/enviveContext.js +15 -11
  116. package/dist/contexts/enviveContext/types.d.cts +1 -1
  117. package/dist/contexts/enviveContext/types.d.ts +1 -1
  118. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.cjs +23 -2
  119. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.d.cts +11 -2
  120. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.d.ts +11 -2
  121. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.js +23 -2
  122. package/dist/contexts/featureFlagServiceContext/index.d.cts +2 -2
  123. package/dist/contexts/featureFlagServiceContext/index.d.ts +2 -2
  124. package/dist/contexts/graphqlContext/graphqlContext.cjs +7 -7
  125. package/dist/contexts/graphqlContext/graphqlContext.d.cts +1 -1
  126. package/dist/contexts/graphqlContext/graphqlContext.d.ts +1 -1
  127. package/dist/contexts/graphqlContext/graphqlContext.js +3 -3
  128. package/dist/contexts/graphqlContext/mockV3Config.cjs +10 -4
  129. package/dist/contexts/graphqlContext/mockV3Config.js +10 -4
  130. package/dist/contexts/hardcopyContext/hardcopyContext.cjs +50 -5
  131. package/dist/contexts/hardcopyContext/hardcopyContext.d.cts +4 -1
  132. package/dist/contexts/hardcopyContext/hardcopyContext.d.ts +4 -1
  133. package/dist/contexts/hardcopyContext/hardcopyContext.js +48 -3
  134. package/dist/contexts/newOrgConfigContext/newOrgConfigContext.cjs +4 -4
  135. package/dist/contexts/newOrgConfigContext/newOrgConfigContext.js +1 -1
  136. package/dist/contexts/pageContext/mapping.cjs +6 -2
  137. package/dist/contexts/pageContext/mapping.js +6 -2
  138. package/dist/contexts/pageContext/pageContext.cjs +4 -3
  139. package/dist/contexts/pageContext/pageContext.js +2 -1
  140. package/dist/contexts/pageContext/types.d.cts +7 -3
  141. package/dist/contexts/pageContext/types.d.ts +7 -3
  142. package/dist/contexts/salesAgentContext/chatAPI.cjs +103 -13
  143. package/dist/contexts/salesAgentContext/chatAPI.d.cts +8 -4
  144. package/dist/contexts/salesAgentContext/chatAPI.d.ts +8 -4
  145. package/dist/contexts/salesAgentContext/chatAPI.js +105 -15
  146. package/dist/contexts/salesAgentContext/salesAgentContext.cjs +1 -1
  147. package/dist/contexts/salesAgentContext/salesAgentContext.js +1 -1
  148. package/dist/contexts/salesAgentContext/salesAgentService.cjs +53 -11
  149. package/dist/contexts/salesAgentContext/salesAgentService.js +51 -9
  150. package/dist/contexts/searchContext/searchContext.cjs +4 -4
  151. package/dist/contexts/searchContext/searchContext.js +1 -1
  152. package/dist/contexts/systemSettingsContext/systemSettingsContext.cjs +3 -3
  153. package/dist/contexts/systemSettingsContext/systemSettingsContext.d.cts +2 -2
  154. package/dist/contexts/systemSettingsContext/systemSettingsContext.d.ts +2 -2
  155. package/dist/contexts/types.cjs +1 -1
  156. package/dist/contexts/types.d.cts +7 -2
  157. package/dist/contexts/types.d.ts +7 -2
  158. package/dist/contexts/types.js +1 -1
  159. package/dist/contexts/typesV3.cjs +2 -1
  160. package/dist/contexts/typesV3.d.cts +12 -7
  161. package/dist/contexts/typesV3.d.ts +10 -5
  162. package/dist/contexts/typesV3.js +2 -1
  163. package/dist/contexts/userIdentityContext/userIdentityContext.cjs +3 -3
  164. package/dist/contexts/widgetConfigContext/widgetConfigContext.cjs +1 -1
  165. package/dist/contexts/widgetConfigContext/widgetConfigContext.js +1 -1
  166. package/dist/hooks/AppDetails/useAppDetails.cjs +6 -6
  167. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.cts +2 -2
  168. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.ts +2 -2
  169. package/dist/hooks/ImageResolver/useImageResolver.cjs +3 -3
  170. package/dist/hooks/Search/useSearch.cjs +6 -6
  171. package/dist/hooks/Search/useSearch.d.cts +1 -1
  172. package/dist/hooks/Search/useSearch.d.ts +1 -1
  173. package/dist/hooks/Search/useSearch.js +3 -3
  174. package/dist/hooks/Search/useSearchInput.cjs +2 -2
  175. package/dist/hooks/Search/useSearchInput.js +2 -2
  176. package/dist/services/amplitudeService/amplitudeService.cjs +49 -11
  177. package/dist/services/amplitudeService/amplitudeService.d.cts +18 -3
  178. package/dist/services/amplitudeService/amplitudeService.d.ts +18 -3
  179. package/dist/services/amplitudeService/amplitudeService.js +49 -12
  180. package/dist/services/amplitudeService/index.cjs +1 -0
  181. package/dist/services/amplitudeService/index.d.cts +2 -2
  182. package/dist/services/amplitudeService/index.d.ts +2 -2
  183. package/dist/services/amplitudeService/index.js +2 -2
  184. package/dist/types/customerService.d.cts +3 -1
  185. package/dist/types/customerService.d.ts +1 -1
  186. package/package.json +10 -2
  187. package/src/application/models/api/widgetText.ts +2 -0
  188. package/src/application/models/api/widgetTextRequest.ts +1 -0
  189. package/src/application/models/chatElementDisplayLocationV3.ts +1 -0
  190. package/src/application/models/variantInfo/variantInfo.ts +5 -0
  191. package/src/application/utils/widgetTextFromApiWidgetTextResponse.ts +2 -0
  192. package/src/application/utils/widgetTextRequestToApiRequest.ts +4 -0
  193. package/src/atoms/app/variant.ts +56 -2
  194. package/src/contexts/amplitudeContext/__tests__/amplitudeContext.test.tsx +2 -0
  195. package/src/contexts/amplitudeContext/amplitudeContext.tsx +6 -1
  196. package/src/contexts/enviveConfigContext/enviveConfigContext.tsx +3 -0
  197. package/src/contexts/enviveContext/WindowChatToggleBinder.tsx +5 -1
  198. package/src/contexts/enviveContext/enviveContext.tsx +5 -1
  199. package/src/contexts/featureFlagServiceContext/featureFlagServiceContext.tsx +36 -0
  200. package/src/contexts/graphqlContext/mockV3Config.ts +13 -7
  201. package/src/contexts/hardcopyContext/hardcopyContext.tsx +48 -3
  202. package/src/contexts/pageContext/mapping.ts +13 -1
  203. package/src/contexts/pageContext/pageContext.tsx +1 -0
  204. package/src/contexts/pageContext/types.ts +7 -1
  205. package/src/contexts/salesAgentContext/chatAPI.ts +106 -13
  206. package/src/contexts/salesAgentContext/salesAgentService.ts +66 -4
  207. package/src/contexts/types.ts +8 -1
  208. package/src/contexts/typesV3.ts +24 -16
  209. package/src/services/amplitudeService/__tests__/amplitudeService.test.ts +80 -0
  210. package/src/services/amplitudeService/amplitudeService.ts +55 -11
@@ -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<void> => {
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,
@@ -863,6 +863,7 @@ type PageVariantBase = {
863
863
  variantId: string;
864
864
  widgetMounting: WidgetMounting[];
865
865
  variantTests: PageVariantTest[];
866
+ floatingButtonOverride?: ShowFloatingButtonOptions;
866
867
  };
867
868
 
868
869
  type PLPPageVariant = PageVariantBase & {
@@ -892,13 +893,18 @@ type SearchPageVariant = PageVariantBase & {
892
893
  variantType: 'search';
893
894
  };
894
895
 
896
+ type FullPageSalesAgentVariant = PageVariantBase & {
897
+ variantType: 'full_page';
898
+ };
899
+
895
900
  export type PageVariantConfig =
896
901
  | PLPPageVariant
897
902
  | PDPPageVariant
898
903
  | VisitPageVariant
899
904
  | OtherPageVariant
900
905
  | HomePageVariant
901
- | SearchPageVariant;
906
+ | SearchPageVariant
907
+ | FullPageSalesAgentVariant;
902
908
 
903
909
  export type OrgPageConfig = {
904
910
  // pageVariants is a list of page variants that we support.
@@ -928,6 +934,7 @@ export interface EnviveConfig {
928
934
  variantUrlOverride?: string;
929
935
  variantInfoOverride?: any;
930
936
  show?: boolean;
937
+ enviveOn?: boolean;
931
938
  publicKey?: string;
932
939
  featureGates?: OrgConfigFeatureGate[];
933
940
  }
@@ -1,11 +1,11 @@
1
- import { AnimationSpeed, PromptCarouselRows } from '@envive-ai/react-toolkit-v3/PromptCarousel';
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 { WidgetWrapperVariant } from '@envive-ai/react-toolkit-v3/WidgetWrapper';
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 { FloatingButtonLocation } from '@envive-ai/react-toolkit-v3/FloatingButton';
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';
@@ -246,6 +246,7 @@ export enum WidgetTypeV3 {
246
246
  FloatingChatV3 = 'FloatingChatV3',
247
247
  FloatingButtonV3 = 'FloatingButtonV3',
248
248
  ProductCardV3 = 'ProductCardV3',
249
+ FullPageSalesAgentV3 = 'FullPageSalesAgentV3',
249
250
  }
250
251
 
251
252
  interface BaseWidgetConfig<T extends WidgetTypeV3> {
@@ -324,6 +325,11 @@ interface ProductCardWidgetV3Config extends BaseWidgetConfig<WidgetTypeV3.Produc
324
325
  imageSrc?: string;
325
326
  }
326
327
 
328
+ interface FullPageSalesAgentWidgetV3Config extends BaseWidgetConfig<WidgetTypeV3.FullPageSalesAgentV3> {
329
+ headerContainer?: string;
330
+ autoHeight?: boolean;
331
+ }
332
+
327
333
  type WidgetConfigV3 =
328
334
  | PromptCarouselWidgetV3Config
329
335
  | SocialProofWidgetV3Config
@@ -334,24 +340,26 @@ type WidgetConfigV3 =
334
340
  | ChatPreviewWidgetV3Config
335
341
  | PromptButtonCarouselWithImageWidgetV3Config
336
342
  | FloatingChatWidgetV3Config
337
- | ProductCardWidgetV3Config;
343
+ | ProductCardWidgetV3Config
344
+ | FullPageSalesAgentWidgetV3Config;
338
345
 
339
346
  export type {
340
- OrgUIConfigV3,
341
- WidgetConfigV3,
342
- LookAndFeelConfig,
343
- SocialProofWidgetV3Config,
344
- PromptCarouselWidgetV3Config,
345
347
  ChatPreviewComparisonWidgetV3Config,
346
348
  ChatPreviewLoadingWidgetV3Config,
347
349
  ChatPreviewWidgetV3Config,
348
- TitledPromptCarouselWidgetV3Config,
349
- TypingAnimationWidgetV3Config,
350
- PromptButtonCarouselWithImageWidgetV3Config,
350
+ CustomerServiceIntegration,
351
+ FloatingButtonConfig,
352
+ FloatingChatConfig,
351
353
  FloatingChatWidgetV3Config,
354
+ FullPageSalesAgentWidgetV3Config,
355
+ LookAndFeelConfig,
356
+ OrgUIConfigV3,
352
357
  ProductCardWidgetV3Config,
353
- FloatingChatConfig,
354
- FloatingButtonConfig,
355
- CustomerServiceIntegration,
358
+ PromptButtonCarouselWithImageWidgetV3Config,
359
+ PromptCarouselWidgetV3Config,
360
+ SocialProofWidgetV3Config,
356
361
  SPASettings,
362
+ TitledPromptCarouselWidgetV3Config,
363
+ TypingAnimationWidgetV3Config,
364
+ WidgetConfigV3,
357
365
  };
@@ -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 },
@@ -46,8 +46,20 @@ export enum SpiffyMetricsEventName {
46
46
  SearchSortClicked = 'Search Sort Clicked',
47
47
  }
48
48
 
49
+ export enum EnviveMetricsEventName {
50
+ WidgetRendered = 'Widget Rendered',
51
+ WidgetInteraction = 'Widget Interaction',
52
+ ChatRequest = 'Chat Request',
53
+ ChatResponse = 'Chat Response',
54
+ EnviveInitialized = 'Envive Initialized',
55
+ PageViewed = 'Page Viewed', // Will this be useful?
56
+ WidgetTextRequest = 'Widget Text Request',
57
+ WidgetTextResponse = 'Widget Text Response',
58
+ WidgetTextClicked = 'Widget Text Clicked',
59
+ }
60
+
49
61
  export interface TrackEventParams {
50
- eventName: SpiffyMetricsEventName;
62
+ eventName: SpiffyMetricsEventName | EnviveMetricsEventName;
51
63
  eventProps?: Record<string, unknown>;
52
64
  eventGroups?: Record<string, unknown>;
53
65
  alsoSendToGoogleAnalytics?: boolean;
@@ -64,6 +76,7 @@ export interface AmplitudeServiceConfig {
64
76
  featureFlagService: FeatureFlagService;
65
77
  orgGaConfig?: unknown;
66
78
  show: boolean;
79
+ enviveOn: boolean;
67
80
  enabledFeatures?: Record<string, boolean>;
68
81
  getLocalStorageItem: null | ((key: string) => string | null);
69
82
  }
@@ -101,7 +114,9 @@ export class AmplitudeService {
101
114
  return null;
102
115
  }
103
116
 
104
- private getDefaultTrackingProps(): Record<string, unknown> {
117
+ private getDefaultTrackingProps(
118
+ eventName: SpiffyMetricsEventName | EnviveMetricsEventName,
119
+ ): Record<string, unknown> {
105
120
  const featureGates = Object.entries(this.config.featureFlagService.getFeatureFlags());
106
121
  const gatesProps =
107
122
  featureGates.length > 0
@@ -114,16 +129,32 @@ export class AmplitudeService {
114
129
  : {};
115
130
  const experimentProps = {}; // No direct equivalent for experiments in EnviveConfig yet
116
131
 
117
- const orgLevelAmplitudeTrackingProps = {
118
- ...gatesProps,
119
- ...experimentProps,
132
+ const environmentProps = {
133
+ 'environment.execution_context': 'bundle',
134
+ 'environment.page_url': window.location.href,
135
+ 'environment.envive_user_id': this.config.userId,
136
+ 'environment.execution_environment': this.config.env || 'unknown',
137
+ 'environment.context_source': this.config.contextSource,
138
+ 'environment.sales_agent_enabled': this.config.enabledFeatures?.salesAgent ?? false,
139
+ 'environment.search_enabled': this.config.enabledFeatures?.searchAgent ?? false,
140
+ 'environment.envive_on_query_param': this.config.enviveOn,
141
+ 'environment.window_show': this.config.show,
142
+ 'environment.envive_enabled': this.config.enabledFeatures?.envive,
120
143
  };
121
144
 
145
+ const orgLevelAmplitudeTrackingProps = AmplitudeService.isEnviveEvent(eventName)
146
+ ? {
147
+ ...this.config.featureFlagService.getFullFlagValues(),
148
+ ...experimentProps,
149
+ ...environmentProps,
150
+ }
151
+ : {
152
+ ...gatesProps,
153
+ ...experimentProps,
154
+ };
122
155
  return {
123
156
  ...orgLevelAmplitudeTrackingProps,
124
157
  ...this.supplementalDefaultProps,
125
- // TODO: org_id is not directly available in EnviveConfig. Need to find a new source or derive it.
126
- // org_id: orgConfig?.org?.org?.id,
127
158
  app_id: 'commerce-chat-react-component',
128
159
  chat_id: this.getLocalStorageItem(LocalStorageKeys.ChatId),
129
160
  env: this.config.env || 'unknown',
@@ -143,7 +174,7 @@ export class AmplitudeService {
143
174
 
144
175
  // eslint-disable-next-line class-methods-use-this
145
176
  private eventPropsToPrefixedEventProps(
146
- eventName: SpiffyMetricsEventName,
177
+ eventName: SpiffyMetricsEventName | EnviveMetricsEventName,
147
178
  eventProps: Record<string, unknown>,
148
179
  ): Record<string, unknown> {
149
180
  const prefix = eventName.toLowerCase().replace(/\s+/g, '_');
@@ -200,7 +231,9 @@ export class AmplitudeService {
200
231
  ...event,
201
232
  event_properties: {
202
233
  ...event.event_properties,
203
- ...this.getDefaultTrackingProps(),
234
+ ...this.getDefaultTrackingProps(
235
+ event.event_type as SpiffyMetricsEventName | EnviveMetricsEventName,
236
+ ),
204
237
  ...globalProperties,
205
238
  ...enabledFeaturesProperties,
206
239
  ...timingProperties,
@@ -342,6 +375,17 @@ export class AmplitudeService {
342
375
  return eventProps ?? {};
343
376
  }
344
377
 
378
+ static isEnviveEvent(eventName: SpiffyMetricsEventName | EnviveMetricsEventName): boolean {
379
+ return Object.values(EnviveMetricsEventName).includes(eventName as EnviveMetricsEventName);
380
+ }
381
+
382
+ static decorateEventName(eventName: SpiffyMetricsEventName | EnviveMetricsEventName): string {
383
+ if (AmplitudeService.isEnviveEvent(eventName)) {
384
+ return `[Envive] ${eventName}`;
385
+ }
386
+ return `[Spiffy] ${eventName}`;
387
+ }
388
+
345
389
  async trackEvent({
346
390
  eventName,
347
391
  eventProps,
@@ -350,7 +394,7 @@ export class AmplitudeService {
350
394
  }: TrackEventParams): Promise<void> {
351
395
  Logger.logDebug('Submitting event', eventName);
352
396
  try {
353
- const decoratedEventName = `[Spiffy] ${eventName}`;
397
+ const decoratedEventName = AmplitudeService.decorateEventName(eventName);
354
398
 
355
399
  if (!this.amplitudeClient) {
356
400
  Logger.logWarn('amplitude client undefined', undefined, {
@@ -382,7 +426,7 @@ export class AmplitudeService {
382
426
  this.amplitudeClient.track(
383
427
  decoratedEventName,
384
428
  {
385
- ...this.getDefaultTrackingProps(),
429
+ ...this.getDefaultTrackingProps(eventName),
386
430
  ...mappedEventProps,
387
431
  ...(mappedEventProps
388
432
  ? this.eventPropsToPrefixedEventProps(eventName, mappedEventProps)