@envive-ai/react-hooks 0.3.10 → 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 (206) hide show
  1. package/dist/application/commerce-api.cjs +15 -15
  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 +4 -4
  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 +2 -2
  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.d.cts +3 -3
  58. package/dist/atoms/chat/index.d.ts +2 -2
  59. package/dist/atoms/chat/lastMessage.d.cts +2 -2
  60. package/dist/atoms/chat/lastMessage.d.ts +2 -2
  61. package/dist/atoms/chat/messageQueue.d.cts +6 -6
  62. package/dist/atoms/chat/messageQueue.d.ts +6 -6
  63. package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
  64. package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
  65. package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
  66. package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
  67. package/dist/atoms/chat/replies.d.ts +3 -3
  68. package/dist/atoms/chat/suggestions.d.cts +2 -2
  69. package/dist/atoms/chat/suggestions.d.ts +2 -2
  70. package/dist/atoms/envive/enviveConfig.d.cts +19 -0
  71. package/dist/atoms/envive/enviveConfig.d.ts +19 -0
  72. package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
  73. package/dist/atoms/globalSearch/globalSearch.d.ts +5 -5
  74. package/dist/atoms/org/customerService.d.cts +6 -6
  75. package/dist/atoms/org/customerService.d.ts +6 -6
  76. package/dist/atoms/org/graphqlConfig.d.cts +4 -4
  77. package/dist/atoms/org/graphqlConfig.d.ts +4 -4
  78. package/dist/atoms/org/index.cjs +1 -1
  79. package/dist/atoms/org/index.js +1 -1
  80. package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
  81. package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
  82. package/dist/atoms/org/orgAnalyticsConfig.d.cts +5 -5
  83. package/dist/atoms/org/orgAnalyticsConfig.d.ts +5 -5
  84. package/dist/atoms/search/chatSearch.cjs +1 -1
  85. package/dist/atoms/search/chatSearch.d.cts +17 -17
  86. package/dist/atoms/search/chatSearch.d.ts +17 -17
  87. package/dist/atoms/search/chatSearch.js +1 -1
  88. package/dist/atoms/search/searchAPI.d.cts +13 -13
  89. package/dist/atoms/search/searchAPI.d.ts +13 -13
  90. package/dist/atoms/search/types.d.ts +1 -1
  91. package/dist/atoms/search/utils.d.cts +1 -1
  92. package/dist/atoms/search/utils.d.ts +1 -1
  93. package/dist/atoms/widget/chatPreviewLoading.d.cts +2 -2
  94. package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
  95. package/dist/contexts/amplitudeContext/amplitudeContext.cjs +10 -7
  96. package/dist/contexts/amplitudeContext/amplitudeContext.d.cts +2 -2
  97. package/dist/contexts/amplitudeContext/amplitudeContext.d.ts +2 -2
  98. package/dist/contexts/amplitudeContext/amplitudeContext.js +6 -3
  99. package/dist/contexts/amplitudeContext/index.cjs +1 -0
  100. package/dist/contexts/amplitudeContext/index.d.cts +2 -2
  101. package/dist/contexts/amplitudeContext/index.d.ts +2 -2
  102. package/dist/contexts/amplitudeContext/index.js +2 -2
  103. package/dist/contexts/cdnContext/cdnContext.cjs +3 -3
  104. package/dist/contexts/enviveConfigContext/enviveConfigContext.cjs +6 -5
  105. package/dist/contexts/enviveConfigContext/enviveConfigContext.d.cts +2 -1
  106. package/dist/contexts/enviveConfigContext/enviveConfigContext.d.ts +2 -1
  107. package/dist/contexts/enviveConfigContext/enviveConfigContext.js +3 -2
  108. package/dist/contexts/enviveContext/WindowChatToggleBinder.cjs +4 -3
  109. package/dist/contexts/enviveContext/WindowChatToggleBinder.js +4 -3
  110. package/dist/contexts/enviveContext/enviveContext.cjs +14 -10
  111. package/dist/contexts/enviveContext/enviveContext.d.cts +2 -1
  112. package/dist/contexts/enviveContext/enviveContext.d.ts +2 -1
  113. package/dist/contexts/enviveContext/enviveContext.js +14 -10
  114. package/dist/contexts/enviveContext/types.d.ts +1 -1
  115. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.cjs +23 -2
  116. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.d.cts +11 -2
  117. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.d.ts +11 -2
  118. package/dist/contexts/featureFlagServiceContext/featureFlagServiceContext.js +23 -2
  119. package/dist/contexts/featureFlagServiceContext/index.d.cts +2 -2
  120. package/dist/contexts/featureFlagServiceContext/index.d.ts +2 -2
  121. package/dist/contexts/graphqlContext/graphqlContext.cjs +7 -7
  122. package/dist/contexts/graphqlContext/graphqlContext.d.cts +1 -1
  123. package/dist/contexts/graphqlContext/graphqlContext.d.ts +1 -1
  124. package/dist/contexts/graphqlContext/graphqlContext.js +3 -3
  125. package/dist/contexts/graphqlContext/mockV3Config.cjs +10 -4
  126. package/dist/contexts/graphqlContext/mockV3Config.js +10 -4
  127. package/dist/contexts/hardcopyContext/hardcopyContext.cjs +50 -5
  128. package/dist/contexts/hardcopyContext/hardcopyContext.d.cts +4 -1
  129. package/dist/contexts/hardcopyContext/hardcopyContext.d.ts +4 -1
  130. package/dist/contexts/hardcopyContext/hardcopyContext.js +48 -3
  131. package/dist/contexts/newOrgConfigContext/newOrgConfigContext.cjs +3 -3
  132. package/dist/contexts/pageContext/mapping.cjs +6 -2
  133. package/dist/contexts/pageContext/mapping.js +6 -2
  134. package/dist/contexts/pageContext/pageContext.cjs +4 -3
  135. package/dist/contexts/pageContext/pageContext.js +2 -1
  136. package/dist/contexts/pageContext/types.d.cts +7 -3
  137. package/dist/contexts/pageContext/types.d.ts +7 -3
  138. package/dist/contexts/salesAgentContext/chatAPI.cjs +102 -12
  139. package/dist/contexts/salesAgentContext/chatAPI.d.cts +8 -4
  140. package/dist/contexts/salesAgentContext/chatAPI.d.ts +8 -4
  141. package/dist/contexts/salesAgentContext/chatAPI.js +104 -14
  142. package/dist/contexts/salesAgentContext/salesAgentContext.cjs +1 -1
  143. package/dist/contexts/salesAgentContext/salesAgentContext.js +1 -1
  144. package/dist/contexts/salesAgentContext/salesAgentService.cjs +52 -10
  145. package/dist/contexts/salesAgentContext/salesAgentService.js +50 -8
  146. package/dist/contexts/searchContext/searchContext.cjs +4 -4
  147. package/dist/contexts/searchContext/searchContext.js +1 -1
  148. package/dist/contexts/systemSettingsContext/systemSettingsContext.cjs +3 -3
  149. package/dist/contexts/systemSettingsContext/systemSettingsContext.d.cts +2 -2
  150. package/dist/contexts/systemSettingsContext/systemSettingsContext.d.ts +2 -2
  151. package/dist/contexts/types.cjs +1 -1
  152. package/dist/contexts/types.d.cts +7 -2
  153. package/dist/contexts/types.d.ts +7 -2
  154. package/dist/contexts/types.js +1 -1
  155. package/dist/contexts/typesV3.cjs +2 -1
  156. package/dist/contexts/typesV3.d.cts +12 -7
  157. package/dist/contexts/typesV3.d.ts +10 -5
  158. package/dist/contexts/typesV3.js +2 -1
  159. package/dist/contexts/userIdentityContext/userIdentityContext.cjs +3 -3
  160. package/dist/contexts/widgetConfigContext/widgetConfigContext.cjs +1 -1
  161. package/dist/contexts/widgetConfigContext/widgetConfigContext.js +1 -1
  162. package/dist/hooks/AppDetails/useAppDetails.cjs +6 -6
  163. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.ts +2 -2
  164. package/dist/hooks/ImageResolver/useImageResolver.cjs +3 -3
  165. package/dist/hooks/Search/useSearch.cjs +4 -4
  166. package/dist/hooks/Search/useSearch.d.cts +1 -1
  167. package/dist/hooks/Search/useSearch.d.ts +1 -1
  168. package/dist/hooks/Search/useSearch.js +1 -1
  169. package/dist/hooks/Search/useSearchInput.cjs +1 -1
  170. package/dist/hooks/Search/useSearchInput.js +1 -1
  171. package/dist/hooks/utils.d.cts +1 -1
  172. package/dist/services/amplitudeService/amplitudeService.cjs +49 -11
  173. package/dist/services/amplitudeService/amplitudeService.d.cts +18 -3
  174. package/dist/services/amplitudeService/amplitudeService.d.ts +18 -3
  175. package/dist/services/amplitudeService/amplitudeService.js +49 -12
  176. package/dist/services/amplitudeService/index.cjs +1 -0
  177. package/dist/services/amplitudeService/index.d.cts +2 -2
  178. package/dist/services/amplitudeService/index.d.ts +2 -2
  179. package/dist/services/amplitudeService/index.js +2 -2
  180. package/dist/types/customerService.d.cts +3 -1
  181. package/dist/types/customerService.d.ts +1 -1
  182. package/package.json +10 -2
  183. package/src/application/models/api/widgetText.ts +2 -0
  184. package/src/application/models/api/widgetTextRequest.ts +1 -0
  185. package/src/application/models/chatElementDisplayLocationV3.ts +1 -0
  186. package/src/application/models/variantInfo/variantInfo.ts +5 -0
  187. package/src/application/utils/widgetTextFromApiWidgetTextResponse.ts +2 -0
  188. package/src/application/utils/widgetTextRequestToApiRequest.ts +4 -0
  189. package/src/atoms/app/variant.ts +56 -2
  190. package/src/contexts/amplitudeContext/__tests__/amplitudeContext.test.tsx +2 -0
  191. package/src/contexts/amplitudeContext/amplitudeContext.tsx +6 -1
  192. package/src/contexts/enviveConfigContext/enviveConfigContext.tsx +3 -0
  193. package/src/contexts/enviveContext/WindowChatToggleBinder.tsx +5 -1
  194. package/src/contexts/enviveContext/enviveContext.tsx +5 -1
  195. package/src/contexts/featureFlagServiceContext/featureFlagServiceContext.tsx +36 -0
  196. package/src/contexts/graphqlContext/mockV3Config.ts +13 -7
  197. package/src/contexts/hardcopyContext/hardcopyContext.tsx +48 -3
  198. package/src/contexts/pageContext/mapping.ts +13 -1
  199. package/src/contexts/pageContext/pageContext.tsx +1 -0
  200. package/src/contexts/pageContext/types.ts +7 -1
  201. package/src/contexts/salesAgentContext/chatAPI.ts +106 -13
  202. package/src/contexts/salesAgentContext/salesAgentService.ts +66 -4
  203. package/src/contexts/types.ts +8 -1
  204. package/src/contexts/typesV3.ts +24 -16
  205. package/src/services/amplitudeService/__tests__/amplitudeService.test.ts +80 -0
  206. package/src/services/amplitudeService/amplitudeService.ts +55 -11
@@ -25,7 +25,11 @@ export const WindowChatToggleBinder = () => {
25
25
  toggleChatRef.current = (triggerId?: string) => hook.toggle(triggerLocation, triggerId);
26
26
  isOpenRef.current = hook.isOpen;
27
27
  openChatWithPromptRef.current = (prompt: string, triggerId?: string) => {
28
- onTypedMessageSubmitted({ query: prompt, userTyped: false });
28
+ onTypedMessageSubmitted({
29
+ query: prompt,
30
+ userTyped: false,
31
+ displayLocation: ChatElementDisplayLocationV3.WINDOW_API_CALL,
32
+ });
29
33
  hook.openChat(triggerLocation, triggerId);
30
34
  };
31
35
  }, [hook, onTypedMessageSubmitted, triggerLocation]);
@@ -45,6 +45,7 @@ interface EnviveProviderProps extends AgentWrapperProps {
45
45
  variantUrlOverride?: string;
46
46
  variantInfoOverride?: any;
47
47
  show?: boolean;
48
+ enviveOn?: boolean;
48
49
  publicKey?: string;
49
50
  featureGates?: OrgConfigFeatureGate[]; // New prop for feature gates
50
51
  featureFlagService?: FeatureFlagService;
@@ -67,6 +68,7 @@ const SearchAgentWrapper: React.FC<AgentWrapperProps> = ({ children, enabledAgen
67
68
 
68
69
  interface SalesAgentWrapperProps extends AgentWrapperProps {
69
70
  previewMode?: boolean;
71
+ showDebugBar: boolean;
70
72
  mockSalesAgentData?: any;
71
73
  }
72
74
 
@@ -74,13 +76,14 @@ const SalesAgentWrapper: React.FC<SalesAgentWrapperProps> = ({
74
76
  children,
75
77
  enabledAgents,
76
78
  previewMode,
79
+ showDebugBar,
77
80
  mockSalesAgentData,
78
81
  }) => {
79
82
  if (!enabledAgents.includes(EnviveAgent.SalesAgent)) {
80
83
  return children;
81
84
  }
82
85
  return (
83
- <SystemSettingsContextProvider>
86
+ <SystemSettingsContextProvider showDebugBar={showDebugBar}>
84
87
  <SalesAgentProvider
85
88
  previewMode={previewMode}
86
89
  mockData={mockSalesAgentData}
@@ -187,6 +190,7 @@ export const EnviveProvider: React.FC<EnviveProviderProps> = ({
187
190
  <WindowChatToggleBinder />
188
191
  <SalesAgentWrapper
189
192
  enabledAgents={enabledAgents}
193
+ showDebugBar={config.enviveOn || false}
190
194
  previewMode={previewMode}
191
195
  mockSalesAgentData={mockSalesAgentData}
192
196
  >
@@ -5,6 +5,14 @@ import Logger from 'src/application/logging/logger';
5
5
 
6
6
  const FEATURE_FLAGS_STORAGE_KEY = 'spiffy-feature-flags';
7
7
 
8
+ export interface FullFlagValue {
9
+ resolved: boolean;
10
+ initial: boolean | undefined;
11
+ query_param_override: boolean | undefined;
12
+ window_param_override: boolean | undefined;
13
+ stored_override: boolean | undefined;
14
+ }
15
+
8
16
  // This is the class that was previously implicitly used or defined elsewhere
9
17
  export class FeatureFlagService {
10
18
  private featureGates: OrgConfigFeatureGate[];
@@ -124,6 +132,34 @@ export class FeatureFlagService {
124
132
  );
125
133
  };
126
134
 
135
+ getFullFlagValue = (featureGate: FeatureGates): FullFlagValue => {
136
+ const gateValue = this.featureGates.find(gate => gate.name === featureGate);
137
+ return {
138
+ resolved: this.isFeatureGateEnabled(featureGate),
139
+ initial: gateValue?.value,
140
+ query_param_override: FeatureFlagService.getQueryParamFeatureGateOverrides(featureGate),
141
+ window_param_override: FeatureFlagService.getWindowFeatureGateOverrides(featureGate),
142
+ stored_override: FeatureFlagService.getStoredFeatureGateOverrides(featureGate),
143
+ };
144
+ };
145
+
146
+ getFullFlagValues = (): Record<string, FullFlagValue> => {
147
+ const featureGates = Object.values(FeatureGates).map((featureGate: FeatureGates) => [
148
+ featureGate,
149
+ this.getFullFlagValue(featureGate),
150
+ ]);
151
+
152
+ return featureGates.length > 0
153
+ ? featureGates.reduce<Record<string, FullFlagValue>>((acc, entry) => {
154
+ const [name, value] = entry as [FeatureGates, FullFlagValue];
155
+ if (name && value != null) {
156
+ return { ...acc, [`feature_gate.${name}`]: value };
157
+ }
158
+ return acc;
159
+ }, {})
160
+ : {};
161
+ };
162
+
127
163
  static persistFeatureGateOverrides(): void {
128
164
  if (typeof window === 'undefined' || typeof window.localStorage === 'undefined') {
129
165
  return;
@@ -1,17 +1,17 @@
1
- import { FrontendConfigV3 } from 'src/application/models/frontendConfigV3';
2
- import { ColorMappingV3, ColorNames, colorVar } from 'src/application/models/colorsConfigV3';
3
- import { CamelCasedPropertiesDeep } from 'src/application/models';
1
+ import { ChatHeaderVariant } from '@envive-ai/react-toolkit-v3/ChatHeader';
4
2
  import { ImageGalleryLayout } from '@envive-ai/react-toolkit-v3/ImageGallery';
5
3
  import { PromptButtonVariant } from '@envive-ai/react-toolkit-v3/PromptButton';
6
4
  import { AnimationSpeed, PromptCarouselRows } from '@envive-ai/react-toolkit-v3/PromptCarousel';
7
- import { WidgetWrapperVariant } from '@envive-ai/react-toolkit-v3/WidgetWrapper';
8
- import { Theme } from '@envive-ai/react-toolkit-v3/Tokens';
9
- import { ChatHeaderVariant } from '@envive-ai/react-toolkit-v3/ChatHeader';
10
5
  import { WidgetKind } from '@envive-ai/react-toolkit-v3/SocialProof';
6
+ import { Theme } from '@envive-ai/react-toolkit-v3/Tokens';
11
7
  import { SparkleIconColor } from '@envive-ai/react-toolkit-v3/WelcomeMessage';
8
+ import { WidgetWrapperVariant } from '@envive-ai/react-toolkit-v3/WidgetWrapper';
9
+ import { CamelCasedPropertiesDeep } from 'src/application/models';
10
+ import { ColorMappingV3, ColorNames, colorVar } from 'src/application/models/colorsConfigV3';
11
+ import { FrontendConfigV3 } from 'src/application/models/frontendConfigV3';
12
12
 
13
- import { CustomerServiceType } from 'src/types/customerService';
14
13
  import { FloatingButtonLocation } from '@envive-ai/react-toolkit-v3/FloatingButton';
14
+ import { CustomerServiceType } from 'src/types/customerService';
15
15
  import { ConfigVersionEnum, WidgetTypeV3 } from '../typesV3';
16
16
 
17
17
  const mockImages = [
@@ -262,5 +262,11 @@ export const mockV3FrontendConfig: FrontendConfigV3 = {
262
262
  imageSrc:
263
263
  'https://www.bandolierstyle.com/cdn/shop/files/Lily17_Black_Gold_Chrome_MOD_Dec25_6.jpg?v=1765844272',
264
264
  },
265
+ 'full-page-sales-agent-widget': {
266
+ widgetConfigId: 'full-page-sales-agent-widget',
267
+ contentId: 'full-page-sales-agent-widget',
268
+ type: WidgetTypeV3.FullPageSalesAgentV3,
269
+ autoHeight: true,
270
+ },
265
271
  },
266
272
  };
@@ -1,16 +1,18 @@
1
1
  import { ReactNode, createContext, useCallback, useContext, useMemo, useState } from 'react';
2
2
  import Logger from 'src/application/logging/logger';
3
-
3
+ import { v4 as uuid } from 'uuid';
4
4
  import CommerceApiClient from 'src/application/commerce-api';
5
- import { WidgetText } from 'src/application/models/api/widgetText';
5
+ import { WidgetString, WidgetText } from 'src/application/models/api/widgetText';
6
6
  import { WidgetTextRequest } from 'src/application/models/api/widgetTextRequest';
7
7
 
8
8
  import { useAtomValue } from 'jotai';
9
9
  import { appDetailsAtom } from 'src/atoms/app';
10
+ import { EnviveMetricsEventName } from 'src/services/amplitudeService/amplitudeService';
10
11
  import { toCamelCase } from 'src/application/models/utils/snakeToCamelTransformer';
11
12
  import { UserEvent } from 'src/application/models';
12
13
  import { WidgetTypeV3 } from '../typesV3';
13
14
  import { useFeatureFlagService } from '../featureFlagServiceContext/featureFlagServiceContext';
15
+ import { useAmplitude } from '../amplitudeContext';
14
16
 
15
17
  interface HardcopyRequest {
16
18
  widgetType: WidgetTypeV3;
@@ -18,7 +20,9 @@ interface HardcopyRequest {
18
20
  }
19
21
 
20
22
  export type HardcopyResponse = {
23
+ responseId: string;
21
24
  language: string;
25
+ rawValues?: Record<string, WidgetString | WidgetString[]>;
22
26
  values: Record<string, string | string[]>;
23
27
  };
24
28
 
@@ -29,7 +33,9 @@ interface HardcopyContextType {
29
33
 
30
34
  const convertToHardcopyResponse = (response: WidgetText): HardcopyResponse => {
31
35
  return {
36
+ responseId: response.responseId,
32
37
  language: response.language,
38
+ rawValues: response.values,
33
39
  values: Object.fromEntries(
34
40
  Object.entries(response.values).map(([key, value]) => [
35
41
  // Transform the key from snake_case to camelCase
@@ -45,6 +51,7 @@ const convertToHardcopyResponse = (response: WidgetText): HardcopyResponse => {
45
51
  // values and their names should be.
46
52
  const MOCK_HARDCOPY_RESPONSE: Partial<Record<WidgetTypeV3, HardcopyResponse>> = {
47
53
  [WidgetTypeV3.PromptCarouselV3]: {
54
+ responseId: uuid(),
48
55
  language: 'en',
49
56
  values: {
50
57
  promptButtonTexts: [
@@ -57,6 +64,7 @@ const MOCK_HARDCOPY_RESPONSE: Partial<Record<WidgetTypeV3, HardcopyResponse>> =
57
64
  },
58
65
  },
59
66
  [WidgetTypeV3.TitledPromptCarouselV3]: {
67
+ responseId: 'mock-response-id',
60
68
  language: 'en',
61
69
  values: {
62
70
  titleLabel: 'Need some help?',
@@ -70,6 +78,7 @@ const MOCK_HARDCOPY_RESPONSE: Partial<Record<WidgetTypeV3, HardcopyResponse>> =
70
78
  },
71
79
  },
72
80
  [WidgetTypeV3.SocialProofV3]: {
81
+ responseId: 'mock-response-id',
73
82
  language: 'en',
74
83
  values: {
75
84
  titleLabel: 'Shopping Assistant',
@@ -88,6 +97,7 @@ const MOCK_HARDCOPY_RESPONSE: Partial<Record<WidgetTypeV3, HardcopyResponse>> =
88
97
  },
89
98
  },
90
99
  [WidgetTypeV3.TypingAnimationV3]: {
100
+ responseId: 'mock-response-id',
91
101
  language: 'en',
92
102
  values: {
93
103
  titleLabel: 'Shopping Assistant',
@@ -108,6 +118,7 @@ const MOCK_HARDCOPY_RESPONSE: Partial<Record<WidgetTypeV3, HardcopyResponse>> =
108
118
  },
109
119
  },
110
120
  [WidgetTypeV3.ChatPreviewComparisonV3]: {
121
+ responseId: 'mock-response-id',
111
122
  language: 'en',
112
123
  values: {
113
124
  titleLabel: 'Shopping Assistant',
@@ -116,6 +127,7 @@ const MOCK_HARDCOPY_RESPONSE: Partial<Record<WidgetTypeV3, HardcopyResponse>> =
116
127
  },
117
128
  },
118
129
  [WidgetTypeV3.ChatPreviewLoadingV3]: {
130
+ responseId: 'mock-response-id',
119
131
  language: 'en',
120
132
  values: {
121
133
  titleLabel: 'Shopping Assistant',
@@ -123,6 +135,7 @@ const MOCK_HARDCOPY_RESPONSE: Partial<Record<WidgetTypeV3, HardcopyResponse>> =
123
135
  },
124
136
  },
125
137
  [WidgetTypeV3.ChatPreviewV3]: {
138
+ responseId: 'mock-response-id',
126
139
  language: 'en',
127
140
  values: {
128
141
  titleLabel: 'Shopping Assistant',
@@ -130,6 +143,7 @@ const MOCK_HARDCOPY_RESPONSE: Partial<Record<WidgetTypeV3, HardcopyResponse>> =
130
143
  },
131
144
  },
132
145
  [WidgetTypeV3.PromptButtonCarouselWithImageV3]: {
146
+ responseId: 'mock-response-id',
133
147
  language: 'en',
134
148
  values: {
135
149
  titleLabel: 'Need some help?',
@@ -138,6 +152,7 @@ const MOCK_HARDCOPY_RESPONSE: Partial<Record<WidgetTypeV3, HardcopyResponse>> =
138
152
  },
139
153
  },
140
154
  [WidgetTypeV3.ProductCardV3]: {
155
+ responseId: 'mock-response-id',
141
156
  language: 'en',
142
157
  values: {
143
158
  headline: 'Discover Your Perfect Style',
@@ -157,6 +172,18 @@ const MOCK_HARDCOPY_RESPONSE: Partial<Record<WidgetTypeV3, HardcopyResponse>> =
157
172
  },
158
173
  },
159
174
  [WidgetTypeV3.FloatingChatV3]: {
175
+ responseId: 'mock-response-id',
176
+ language: 'en',
177
+ values: {
178
+ welcomeMessageTitle: 'Welcome to Envive AI',
179
+ welcomeMessageText:
180
+ 'Your personal shopper trained on the collective knowledge of thousands of real experts!',
181
+ chatFooterTextFieldPlaceholderText: 'Ask me anything...',
182
+ disclaimerText: 'This is a disclaimer...',
183
+ },
184
+ },
185
+ [WidgetTypeV3.FullPageSalesAgentV3]: {
186
+ responseId: 'mock-response-id',
160
187
  language: 'en',
161
188
  values: {
162
189
  welcomeMessageTitle: 'Welcome to Envive AI',
@@ -174,22 +201,40 @@ export const HardcopyProvider: React.FC<{ children: ReactNode }> = ({ children }
174
201
  const languages = useMemo(() => navigator.languages, []);
175
202
  const [isLoading, setIsLoading] = useState(false);
176
203
  const context = useAtomValue(appDetailsAtom);
204
+ const { trackEvent } = useAmplitude();
177
205
 
178
206
  const { featureFlagService } = useFeatureFlagService();
179
207
  const getHardcopyFromBackend = useCallback(
180
208
  async (request: HardcopyRequest): Promise<HardcopyResponse> => {
181
209
  const widgetTextRequest: WidgetTextRequest = {
210
+ requestId: uuid(),
182
211
  widgetType: request.widgetType,
183
212
  context,
184
213
  featureFlags: featureFlagService?.getFeatureFlags() || {},
185
214
  language: languages[0] || 'en',
186
215
  url: window.location.href,
187
216
  };
217
+ trackEvent({
218
+ eventName: EnviveMetricsEventName.WidgetTextRequest,
219
+ eventProps: {
220
+ widget_type: request.widgetType,
221
+ request_id: widgetTextRequest.requestId,
222
+ },
223
+ });
188
224
  try {
189
225
  const response = await CommerceApiClient.getHardcopy(widgetTextRequest);
190
226
  if (response) {
191
227
  const convertedResponse = convertToHardcopyResponse(response);
192
228
  Logger.logInfo('hardcopyContext | converted response', convertedResponse);
229
+ trackEvent({
230
+ eventName: EnviveMetricsEventName.WidgetTextResponse,
231
+ eventProps: {
232
+ widget_type: request.widgetType,
233
+ response_id: response.responseId,
234
+ widget_text: response.values,
235
+ request_id: widgetTextRequest.requestId,
236
+ },
237
+ });
193
238
  return convertedResponse;
194
239
  }
195
240
  } catch (error) {
@@ -202,7 +247,7 @@ export const HardcopyProvider: React.FC<{ children: ReactNode }> = ({ children }
202
247
  }
203
248
  throw new Error(`No hardcopy response found for widget type: ${request.widgetType}`);
204
249
  },
205
- [context, featureFlagService, languages],
250
+ [context, featureFlagService, languages, trackEvent],
206
251
  );
207
252
 
208
253
  const getHardcopy = useCallback(
@@ -15,7 +15,13 @@ import { isApiSearchAttributes } from 'src/application/models/guards/api/isApiSe
15
15
  import { isApiSuggestionClickedAttributes } from 'src/application/models/guards/api/isApiSuggestionClickedEventAttributes';
16
16
  import { isApiFormSubmittedResponseAttributes } from 'src/application/models/guards/api/isApiFormSubmittedResponseAttributes';
17
17
 
18
- import { HomeVariantInfo, OtherVariantInfo, PageVariantInfo, VisitPageVariantInfo } from './types';
18
+ import {
19
+ FullPageSalesAgentVariantInfo,
20
+ HomeVariantInfo,
21
+ OtherVariantInfo,
22
+ PageVariantInfo,
23
+ VisitPageVariantInfo,
24
+ } from './types';
19
25
 
20
26
  export const mapUrlResolverResponseToVariantInfo = (
21
27
  url: string,
@@ -66,6 +72,12 @@ export const mapUrlResolverResponseToVariantInfo = (
66
72
  } as OtherVariantInfo;
67
73
  }
68
74
 
75
+ if (response.variant_type === VariantTypeEnum.FullPageSalesAgent) {
76
+ return {
77
+ variantType: VariantTypeEnum.FullPageSalesAgent,
78
+ url,
79
+ } as FullPageSalesAgentVariantInfo;
80
+ }
69
81
  throw new Error('Invalid variant type');
70
82
  };
71
83
 
@@ -70,6 +70,7 @@ export const PageProvider: React.FC<{
70
70
  const newVariantInfo = mapUrlResolverResponseToVariantInfo(url, response);
71
71
  const newUserEvent = mapApiUserEventToUserEvent(response.user_event ?? undefined);
72
72
  setVariantInfo(newVariantInfo);
73
+ console.log('=== newUserEvent ===', newUserEvent);
73
74
  setUserEvent(newUserEvent);
74
75
  },
75
76
  [setVariantInfo, setUserEvent],
@@ -31,12 +31,18 @@ export type OtherVariantInfo = {
31
31
  url: string;
32
32
  };
33
33
 
34
+ export type FullPageSalesAgentVariantInfo = {
35
+ variantType: VariantTypeEnum.FullPageSalesAgent;
36
+ url: string;
37
+ };
38
+
34
39
  export type PageVariantInfo =
35
40
  | PDPPageVariantInfo
36
41
  | PLPPageVariantInfo
37
42
  | VisitPageVariantInfo
38
43
  | HomeVariantInfo
39
- | OtherVariantInfo;
44
+ | OtherVariantInfo
45
+ | FullPageSalesAgentVariantInfo;
40
46
 
41
47
  export interface PageDetails {
42
48
  pageUrl: string | undefined;
@@ -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: ({ query, userTyped }: { query: string; userTyped: boolean }) => void;
27
- onFormResponseSubmitted: (formResponse: FormSubmittedAttributes) => void;
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,18 @@ export const useSalesAgentChatAPI = () => {
37
55
 
38
56
  const logPageVisit = useCallback(
39
57
  ({ pageVisitCategory }: { pageVisitCategory: PageVisitCategory }) => {
58
+ const eventId = uuid();
59
+ console.log('=== logPageVisit ===', eventId);
60
+ trackEvent({
61
+ eventName: EnviveMetricsEventName.ChatRequest,
62
+ eventProps: {
63
+ ...context,
64
+ 'chat.request_id': eventId,
65
+ 'chat.request_type': 'page_visit',
66
+ },
67
+ });
40
68
  const event: UserEvent = {
41
- eventId: uuid(),
69
+ eventId,
42
70
  category: UserEventCategory.PageVisit,
43
71
  createdAt: new Date().toISOString(),
44
72
  attributes: {
@@ -48,14 +76,32 @@ export const useSalesAgentChatAPI = () => {
48
76
  };
49
77
  queueUserEvent(event);
50
78
  },
51
- [queueUserEvent],
79
+ [queueUserEvent, context, trackEvent],
52
80
  );
53
81
 
54
82
  const logUserEvent = useCallback(
55
83
  (event: UserEvent) => {
84
+ if (!hasParsedVariantInfo) {
85
+ Logger.logWarn(
86
+ '[envive-ai] hasParsedVariantInfo is false, not logging user event',
87
+ undefined,
88
+ { event },
89
+ );
90
+ return;
91
+ }
92
+ if (TRACKED_USER_EVENTS.includes(event.category)) {
93
+ trackEvent({
94
+ eventName: EnviveMetricsEventName.ChatRequest,
95
+ eventProps: {
96
+ ...context,
97
+ 'chat.request_id': event.eventId,
98
+ 'chat.request_type': 'page_visit',
99
+ },
100
+ });
101
+ }
56
102
  queueUserEvent(event);
57
103
  },
58
- [queueUserEvent],
104
+ [context, hasParsedVariantInfo, queueUserEvent, trackEvent],
59
105
  );
60
106
  const onSuggestionClicked = useCallback(
61
107
  (suggestion: Suggestion, displayLocation: ChatElementDisplayLocationV3) => {
@@ -74,8 +120,24 @@ export const useSalesAgentChatAPI = () => {
74
120
  },
75
121
  },
76
122
  });
123
+ const eventId = uuid();
124
+ trackEvent({
125
+ eventName: EnviveMetricsEventName.ChatRequest,
126
+ eventProps: {
127
+ ...context,
128
+ 'trigger.widget': displayLocation, // This is fairly finegrained, but that may be ok
129
+ 'chat.request_id': eventId,
130
+ 'chat.request_type': 'suggestion',
131
+ 'chat.request_text': suggestion.content,
132
+ 'chat.suggestion_id': suggestion.id,
133
+ 'chat.suggestion_category': suggestion.category,
134
+ 'chat.suggestion_created_at': suggestion.createdAt,
135
+ 'chat.suggestion_is_answer': suggestion.isAnswer,
136
+ 'chat.user_typed': false,
137
+ },
138
+ });
77
139
  const event: UserEvent = {
78
- eventId: uuid(),
140
+ eventId,
79
141
  category: UserEventCategory.SuggestionClicked,
80
142
  createdAt: new Date().toISOString(),
81
143
  attributes: {
@@ -85,10 +147,18 @@ export const useSalesAgentChatAPI = () => {
85
147
  };
86
148
  queueUserEvent(event);
87
149
  },
88
- [queueUserEvent, trackEvent],
150
+ [queueUserEvent, trackEvent, context],
89
151
  );
90
152
  const onTypedMessageSubmitted = useCallback(
91
- ({ query, userTyped }: { query: string; userTyped: boolean }) => {
153
+ ({
154
+ query,
155
+ userTyped,
156
+ displayLocation,
157
+ }: {
158
+ query: string;
159
+ userTyped: boolean;
160
+ displayLocation: ChatElementDisplayLocationV3;
161
+ }) => {
92
162
  const eventId = uuid();
93
163
  trackEvent({
94
164
  eventName: SpiffyMetricsEventName.ChatUserMessageInput,
@@ -105,6 +175,18 @@ export const useSalesAgentChatAPI = () => {
105
175
  },
106
176
  },
107
177
  });
178
+ trackEvent({
179
+ eventName: EnviveMetricsEventName.ChatRequest,
180
+ eventProps: {
181
+ ...context,
182
+ 'trigger.widget': displayLocation,
183
+ 'chat.request_type': 'text',
184
+ 'chat.request_text': query,
185
+ 'chat.request_id': eventId,
186
+ 'chat.request_created_at': new Date().toISOString(),
187
+ 'chat.user_typed': userTyped,
188
+ },
189
+ });
108
190
  const event: UserEvent = {
109
191
  eventId,
110
192
  category: UserEventCategory.QueryTyped,
@@ -116,21 +198,32 @@ export const useSalesAgentChatAPI = () => {
116
198
  };
117
199
  queueUserEvent(event);
118
200
  },
119
- [queueUserEvent, trackEvent],
201
+ [queueUserEvent, trackEvent, context],
120
202
  );
121
203
  const onFormResponseSubmitted = useCallback(
122
204
  (form: FormSubmittedAttributes) => {
123
205
  setReplyEventCategory(UserEventCategory.FormSubmitted);
124
206
  setFormSubmit(form);
207
+ const eventId = uuid();
208
+ trackEvent({
209
+ eventName: EnviveMetricsEventName.ChatRequest,
210
+ eventProps: {
211
+ ...context,
212
+ 'chat.request_id': eventId,
213
+ 'chat.request_type': 'form',
214
+ 'chat.form_response_id': form.formResponseId,
215
+ 'chat.form_type': form.formType,
216
+ },
217
+ });
125
218
  const event: UserEvent = {
126
- eventId: uuid(),
219
+ eventId,
127
220
  category: UserEventCategory.FormSubmitted,
128
221
  createdAt: new Date().toISOString(),
129
222
  attributes: form,
130
223
  };
131
224
  queueUserEvent(event);
132
225
  },
133
- [queueUserEvent, setReplyEventCategory, setFormSubmit],
226
+ [setReplyEventCategory, setFormSubmit, trackEvent, context, queueUserEvent],
134
227
  );
135
228
 
136
229
  return {