@envive-ai/react-hooks 0.3.11 → 0.3.13

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 +21 -41
  2. package/dist/application/commerce-api.d.cts +2 -4
  3. package/dist/application/commerce-api.d.ts +2 -4
  4. package/dist/application/commerce-api.js +21 -41
  5. package/dist/application/models/api/widgetTextRequest.d.cts +2 -1
  6. package/dist/application/models/api/widgetTextRequest.d.ts +2 -1
  7. package/dist/application/models/chatElementDisplayLocationV3.cjs +3 -1
  8. package/dist/application/models/chatElementDisplayLocationV3.d.cts +3 -1
  9. package/dist/application/models/chatElementDisplayLocationV3.d.ts +3 -1
  10. package/dist/application/models/chatElementDisplayLocationV3.js +3 -1
  11. package/dist/application/models/guards/api/index.cjs +6 -6
  12. package/dist/application/models/guards/api/index.js +6 -6
  13. package/dist/application/models/index.cjs +18 -18
  14. package/dist/application/models/index.js +18 -18
  15. package/dist/application/models/validators/validateResponse.cjs +3 -3
  16. package/dist/application/models/validators/validateResponse.js +3 -3
  17. package/dist/application/models/variantInfo/variantInfo.cjs +1 -1
  18. package/dist/application/models/variantInfo/variantInfo.d.cts +1 -1
  19. package/dist/application/models/variantInfo/variantInfo.d.ts +1 -1
  20. package/dist/application/models/variantInfo/variantInfo.js +1 -1
  21. package/dist/application/utils/analyticsUtils.cjs +5 -5
  22. package/dist/application/utils/analyticsUtils.d.cts +2 -2
  23. package/dist/application/utils/analyticsUtils.d.ts +2 -2
  24. package/dist/application/utils/analyticsUtils.js +3 -3
  25. package/dist/application/utils/nodeSelector.cjs +12 -14
  26. package/dist/application/utils/nodeSelector.js +12 -14
  27. package/dist/application/utils/widgetTextRequestToApiRequest.cjs +2 -1
  28. package/dist/application/utils/widgetTextRequestToApiRequest.js +2 -1
  29. package/dist/atoms/app/index.d.cts +7 -7
  30. package/dist/atoms/app/index.d.ts +7 -7
  31. package/dist/atoms/chat/chatState.cjs +5 -5
  32. package/dist/atoms/chat/chatState.d.cts +19 -19
  33. package/dist/atoms/chat/chatState.d.ts +19 -19
  34. package/dist/atoms/chat/chatState.js +3 -3
  35. package/dist/atoms/chat/form.d.cts +2 -2
  36. package/dist/atoms/chat/form.d.ts +2 -2
  37. package/dist/atoms/chat/index.d.ts +2 -2
  38. package/dist/atoms/chat/lastMessage.d.cts +2 -2
  39. package/dist/atoms/chat/lastMessage.d.ts +2 -2
  40. package/dist/atoms/chat/messageQueue.d.cts +6 -6
  41. package/dist/atoms/chat/messageQueue.d.ts +6 -6
  42. package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
  43. package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
  44. package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
  45. package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
  46. package/dist/atoms/chat/replies.cjs +4 -4
  47. package/dist/atoms/chat/replies.d.cts +3 -3
  48. package/dist/atoms/chat/replies.d.ts +3 -3
  49. package/dist/atoms/chat/replies.js +3 -3
  50. package/dist/atoms/chat/suggestions.d.cts +2 -2
  51. package/dist/atoms/chat/suggestions.d.ts +2 -2
  52. package/dist/atoms/envive/enviveConfig.d.cts +13 -13
  53. package/dist/atoms/envive/enviveConfig.d.ts +13 -13
  54. package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
  55. package/dist/atoms/globalSearch/globalSearch.d.ts +5 -5
  56. package/dist/atoms/org/customerService.d.cts +6 -6
  57. package/dist/atoms/org/customerService.d.ts +6 -6
  58. package/dist/atoms/org/graphqlConfig.d.cts +4 -4
  59. package/dist/atoms/org/graphqlConfig.d.ts +4 -4
  60. package/dist/atoms/org/index.cjs +1 -1
  61. package/dist/atoms/org/index.js +1 -1
  62. package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
  63. package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
  64. package/dist/atoms/org/orgAnalyticsConfig.d.cts +5 -5
  65. package/dist/atoms/org/orgAnalyticsConfig.d.ts +5 -5
  66. package/dist/atoms/search/chatSearch.d.cts +17 -17
  67. package/dist/atoms/search/searchAPI.d.cts +13 -13
  68. package/dist/atoms/search/searchAPI.d.ts +13 -13
  69. package/dist/atoms/search/utils.d.cts +1 -1
  70. package/dist/atoms/search/utils.d.ts +1 -1
  71. package/dist/atoms/widget/chatPreviewLoading.d.cts +2 -2
  72. package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
  73. package/dist/contexts/amplitudeContext/amplitudeContext.cjs +5 -5
  74. package/dist/contexts/amplitudeContext/amplitudeContext.d.cts +3 -2
  75. package/dist/contexts/amplitudeContext/amplitudeContext.d.ts +3 -2
  76. package/dist/contexts/amplitudeContext/amplitudeContext.js +5 -5
  77. package/dist/contexts/amplitudeContext/index.cjs +3 -3
  78. package/dist/contexts/amplitudeContext/index.d.cts +1 -1
  79. package/dist/contexts/amplitudeContext/index.d.ts +1 -1
  80. package/dist/contexts/amplitudeContext/index.js +1 -1
  81. package/dist/contexts/cdnContext/cdnContext.cjs +1 -1
  82. package/dist/contexts/cdnContext/cdnContext.js +1 -1
  83. package/dist/contexts/enviveConfigContext/enviveConfigContext.cjs +1 -1
  84. package/dist/contexts/enviveConfigContext/enviveConfigContext.js +1 -1
  85. package/dist/contexts/enviveContext/enviveContext.cjs +17 -14
  86. package/dist/contexts/enviveContext/enviveContext.d.cts +4 -1
  87. package/dist/contexts/enviveContext/enviveContext.d.ts +4 -1
  88. package/dist/contexts/enviveContext/enviveContext.js +17 -14
  89. package/dist/contexts/graphqlContext/graphqlContext.cjs +2 -2
  90. package/dist/contexts/graphqlContext/graphqlContext.js +2 -2
  91. package/dist/contexts/graphqlContext/mockV3Config.cjs +3 -2
  92. package/dist/contexts/graphqlContext/mockV3Config.js +3 -2
  93. package/dist/contexts/hardcopyContext/hardcopyContext.cjs +18 -8
  94. package/dist/contexts/hardcopyContext/hardcopyContext.d.cts +6 -4
  95. package/dist/contexts/hardcopyContext/hardcopyContext.d.ts +6 -4
  96. package/dist/contexts/hardcopyContext/hardcopyContext.js +16 -6
  97. package/dist/contexts/newOrgConfigContext/newOrgConfigContext.cjs +1 -1
  98. package/dist/contexts/newOrgConfigContext/newOrgConfigContext.js +1 -1
  99. package/dist/contexts/pageContext/pageContext.cjs +11 -7
  100. package/dist/contexts/pageContext/pageContext.js +11 -7
  101. package/dist/contexts/pageContext/types.d.cts +1 -1
  102. package/dist/contexts/salesAgentContext/chatAPI.cjs +11 -11
  103. package/dist/contexts/salesAgentContext/chatAPI.js +4 -4
  104. package/dist/contexts/salesAgentContext/salesAgentContext.cjs +1 -1
  105. package/dist/contexts/salesAgentContext/salesAgentContext.js +1 -1
  106. package/dist/contexts/salesAgentContext/salesAgentService.cjs +9 -8
  107. package/dist/contexts/salesAgentContext/salesAgentService.js +7 -6
  108. package/dist/contexts/searchContext/searchContext.cjs +2 -2
  109. package/dist/contexts/searchContext/searchContext.js +2 -2
  110. package/dist/contexts/systemSettingsContext/systemSettingsContext.cjs +1 -1
  111. package/dist/contexts/systemSettingsContext/systemSettingsContext.d.cts +2 -2
  112. package/dist/contexts/systemSettingsContext/systemSettingsContext.d.ts +2 -2
  113. package/dist/contexts/systemSettingsContext/systemSettingsContext.js +1 -1
  114. package/dist/contexts/types.cjs +1 -1
  115. package/dist/contexts/types.d.cts +4 -2
  116. package/dist/contexts/types.d.ts +4 -2
  117. package/dist/contexts/types.js +1 -1
  118. package/dist/contexts/typesV3.cjs +1 -1
  119. package/dist/contexts/typesV3.d.cts +27 -2
  120. package/dist/contexts/typesV3.d.ts +27 -2
  121. package/dist/contexts/typesV3.js +1 -1
  122. package/dist/contexts/userIdentityContext/userIdentityContext.cjs +2 -34
  123. package/dist/contexts/userIdentityContext/userIdentityContext.d.cts +1 -2
  124. package/dist/contexts/userIdentityContext/userIdentityContext.d.ts +1 -2
  125. package/dist/contexts/userIdentityContext/userIdentityContext.js +2 -33
  126. package/dist/hooks/AmplitudeOperations/useAmplitudeOperations.cjs +1 -1
  127. package/dist/hooks/AmplitudeOperations/useAmplitudeOperations.d.cts +2 -2
  128. package/dist/hooks/AmplitudeOperations/useAmplitudeOperations.d.ts +2 -2
  129. package/dist/hooks/AmplitudeOperations/useAmplitudeOperations.js +1 -1
  130. package/dist/hooks/ChatToggle/useChatToggle.cjs +6 -5
  131. package/dist/hooks/ChatToggle/useChatToggle.js +4 -3
  132. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.cts +2 -2
  133. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.ts +2 -2
  134. package/dist/hooks/Search/useSearch.cjs +9 -8
  135. package/dist/hooks/Search/useSearch.js +4 -3
  136. package/dist/hooks/Search/useSearchInput.cjs +7 -7
  137. package/dist/hooks/Search/useSearchInput.js +4 -4
  138. package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.cjs +6 -5
  139. package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.d.cts +2 -2
  140. package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.d.ts +2 -2
  141. package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.js +3 -2
  142. package/dist/hooks/UpdateAnalyticsProps/useUpdateAnalyticsProps.cjs +4 -3
  143. package/dist/hooks/UpdateAnalyticsProps/useUpdateAnalyticsProps.js +3 -2
  144. package/dist/hooks/utils.d.ts +1 -1
  145. package/dist/services/amplitudeService/amplitudeService.cjs +17 -57
  146. package/dist/services/amplitudeService/amplitudeService.d.cts +4 -47
  147. package/dist/services/amplitudeService/amplitudeService.d.ts +4 -47
  148. package/dist/services/amplitudeService/amplitudeService.js +14 -52
  149. package/dist/services/amplitudeService/eventNames.cjs +59 -0
  150. package/dist/services/amplitudeService/eventNames.d.cts +54 -0
  151. package/dist/services/amplitudeService/eventNames.d.ts +54 -0
  152. package/dist/services/amplitudeService/eventNames.js +57 -0
  153. package/dist/services/amplitudeService/index.cjs +3 -2
  154. package/dist/services/amplitudeService/index.d.cts +2 -1
  155. package/dist/services/amplitudeService/index.d.ts +2 -1
  156. package/dist/services/amplitudeService/index.js +2 -1
  157. package/dist/services/ga4ProjectionService/ga4EventSchema.cjs +108 -0
  158. package/dist/services/ga4ProjectionService/ga4EventSchema.js +108 -0
  159. package/dist/services/ga4ProjectionService/ga4ProjectionService.cjs +71 -0
  160. package/dist/services/ga4ProjectionService/ga4ProjectionService.js +71 -0
  161. package/dist/types/customerService.cjs +2 -1
  162. package/dist/types/customerService.d.cts +2 -1
  163. package/dist/types/customerService.d.ts +2 -1
  164. package/dist/types/customerService.js +2 -1
  165. package/dist/types/enviveConfig.d.cts +4 -1
  166. package/dist/types/enviveConfig.d.ts +4 -1
  167. package/package.json +2 -7
  168. package/src/application/commerce-api.ts +25 -49
  169. package/src/application/models/api/widgetTextRequest.ts +1 -0
  170. package/src/application/models/chatElementDisplayLocationV3.ts +2 -0
  171. package/src/application/models/variantInfo/variantInfo.ts +1 -1
  172. package/src/application/utils/analyticsUtils.ts +1 -1
  173. package/src/application/utils/nodeSelector.ts +15 -14
  174. package/src/application/utils/widgetTextRequestToApiRequest.ts +1 -0
  175. package/src/atoms/chat/chatState.ts +1 -1
  176. package/src/atoms/chat/replies.ts +1 -1
  177. package/src/contexts/amplitudeContext/amplitudeContext.tsx +0 -1
  178. package/src/contexts/enviveContext/enviveContext.tsx +5 -2
  179. package/src/contexts/graphqlContext/mockV3Config.ts +3 -0
  180. package/src/contexts/hardcopyContext/hardcopyContext.tsx +20 -2
  181. package/src/contexts/pageContext/pageContext.tsx +9 -5
  182. package/src/contexts/salesAgentContext/chatAPI.ts +0 -1
  183. package/src/contexts/salesAgentContext/salesAgentService.ts +5 -2
  184. package/src/contexts/types.ts +3 -1
  185. package/src/contexts/typesV3.ts +28 -0
  186. package/src/contexts/userIdentityContext/__tests__/userIdentityContext.test.tsx +1 -66
  187. package/src/contexts/userIdentityContext/userIdentityContext.tsx +0 -47
  188. package/src/hooks/AmplitudeOperations/useAmplitudeOperations.ts +2 -4
  189. package/src/hooks/ChatToggle/useChatToggle.ts +2 -4
  190. package/src/hooks/Search/useSearch.tsx +2 -4
  191. package/src/hooks/Search/useSearchInput.ts +1 -1
  192. package/src/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.ts +2 -4
  193. package/src/hooks/UpdateAnalyticsProps/useUpdateAnalyticsProps.ts +2 -4
  194. package/src/services/amplitudeService/amplitudeService.ts +14 -50
  195. package/src/services/amplitudeService/eventNames.ts +52 -0
  196. package/src/services/ga4ProjectionService/__tests__/ga4ProjectionService.test.ts +334 -0
  197. package/src/services/ga4ProjectionService/ga4EventSchema.ts +143 -0
  198. package/src/services/ga4ProjectionService/ga4ProjectionService.ts +137 -0
  199. package/src/types/customerService.ts +1 -0
  200. package/src/types/enviveConfig.ts +3 -0
  201. package/dist/hooks/IdentifyUser/index.cjs +0 -3
  202. package/dist/hooks/IdentifyUser/index.d.cts +0 -2
  203. package/dist/hooks/IdentifyUser/index.d.ts +0 -2
  204. package/dist/hooks/IdentifyUser/index.js +0 -3
  205. package/dist/hooks/IdentifyUser/useIdentifyUser.cjs +0 -35
  206. package/dist/hooks/IdentifyUser/useIdentifyUser.d.cts +0 -10
  207. package/dist/hooks/IdentifyUser/useIdentifyUser.d.ts +0 -10
  208. package/dist/hooks/IdentifyUser/useIdentifyUser.js +0 -34
  209. package/src/hooks/IdentifyUser/index.ts +0 -1
  210. package/src/hooks/IdentifyUser/useIdentifyUser.ts +0 -29
@@ -1,4 +1,3 @@
1
- import Logger from 'src/application/logging/logger';
2
1
  import {
3
2
  Configuration,
4
3
  ContextEnvEnum,
@@ -16,13 +15,8 @@ import {
16
15
  V1OrgConfigGetRequest,
17
16
  V1OrgConfigGetSourceEnum,
18
17
  } from '@spiffy-ai/commerce-api-client';
19
- import { validateSuggestion } from 'src/application/models/validators/validateSuggestion';
20
- import { validateUserEvent } from 'src/application/models/validators/validateUserEvent';
21
- import {
22
- messageFromQueryEvent,
23
- messageFromResponse,
24
- messageFromSuggestionEvent,
25
- } from 'src/application/utils';
18
+ import type { Context } from '@spiffy-ai/commerce-api-client/dist/models/Context';
19
+ import Logger from 'src/application/logging/logger';
26
20
  import {
27
21
  Message,
28
22
  NextMessageRequest,
@@ -31,19 +25,25 @@ import {
31
25
  SupportedEventRequest,
32
26
  UserEvent,
33
27
  } from 'src/application/models';
34
- import { messageRequestToCommerceMessageRequest } from 'src/application/utils/nextMessageRequestToApiRequest';
35
- import { validateResponse } from 'src/application/models/validators/validateResponse';
36
- import { coreSupportedEventRequestToApiRequest } from 'src/application/utils/supportedEventRequestToApiRequest';
37
- import { SessionRestartRequired } from 'src/types/exceptions/sessionExceptions';
38
- import { UnsupportedProductException } from 'src/types/exceptions/unsupportedProductExceptions';
28
+ import { OrgConfig } from 'src/application/models/api/orgConfigResults';
39
29
  import { ClientDetails } from 'src/application/models/clientDetails';
40
- import { getAtomStore } from 'src/atoms/atomStore/atomStore';
41
30
  import { ProductExperiment } from 'src/application/models/productExperiment';
42
31
  import { validateOrgConfigResults } from 'src/application/models/validators/validateOrgConfigResults';
43
- import { OrgConfig } from 'src/application/models/api/orgConfigResults';
44
- import { SupportedEvent } from 'src/atoms/app/variant';
32
+ import { validateResponse } from 'src/application/models/validators/validateResponse';
33
+ import { validateSuggestion } from 'src/application/models/validators/validateSuggestion';
34
+ import { validateUserEvent } from 'src/application/models/validators/validateUserEvent';
35
+ import {
36
+ getQueryParam,
37
+ messageFromQueryEvent,
38
+ messageFromResponse,
39
+ messageFromSuggestionEvent,
40
+ } from 'src/application/utils';
45
41
  import { messageFromFormSubmittedEvent } from 'src/application/utils/messageFromFormSubmittedEvent';
46
- import type { Context } from '@spiffy-ai/commerce-api-client/dist/models/Context';
42
+ import { messageRequestToCommerceMessageRequest } from 'src/application/utils/nextMessageRequestToApiRequest';
43
+ import { coreSupportedEventRequestToApiRequest } from 'src/application/utils/supportedEventRequestToApiRequest';
44
+ import { chatIdAtom, userIdAtom } from 'src/atoms/app'; // Import userIdAtom and chatIdAtom
45
+ import { SupportedEvent } from 'src/atoms/app/variant';
46
+ import { getAtomStore } from 'src/atoms/atomStore/atomStore';
47
47
  import {
48
48
  baseUrlAtom,
49
49
  contextSourceAtom,
@@ -53,12 +53,13 @@ import {
53
53
  orgShortNameAtom,
54
54
  reactAppNameAtom, // Import envAtom
55
55
  } from 'src/atoms/envive/enviveConfig';
56
- import { chatIdAtom, userIdAtom } from 'src/atoms/app'; // Import userIdAtom and chatIdAtom
57
56
  import { featureFlagServiceAtom } from 'src/atoms/org/graphqlConfig'; // Import new orgIdAtom and featureFlagServiceAtom
58
- import { coreWidgetTextRequestToApiRequest } from './utils/widgetTextRequestToApiRequest';
57
+ import { SessionRestartRequired } from 'src/types/exceptions/sessionExceptions';
58
+ import { UnsupportedProductException } from 'src/types/exceptions/unsupportedProductExceptions';
59
+ import { WidgetText } from './models/api/widgetText';
59
60
  import { WidgetTextRequest } from './models/api/widgetTextRequest';
60
61
  import { apiWidgetTextResponseToCoreWidgetText } from './utils/widgetTextFromApiWidgetTextResponse';
61
- import { WidgetText } from './models/api/widgetText';
62
+ import { coreWidgetTextRequestToApiRequest } from './utils/widgetTextRequestToApiRequest';
62
63
 
63
64
  async function errorResponseBody(error: ResponseError) {
64
65
  try {
@@ -157,11 +158,15 @@ class CommerceApiClient {
157
158
  env: (env as ContextEnvEnum) ?? ContextEnvEnum.Dev, // Cast env to ContextEnvEnum
158
159
  };
159
160
 
161
+ const overrideConfigVersion =
162
+ getQueryParam('spiffy_config_version') || getQueryParam('envive_config_version') || undefined;
163
+
160
164
  const featureGates = featureFlagService?.featureFlagService?.getFeatureFlags() || {};
161
165
  const urlResolvingRequest = {
162
166
  url,
163
167
  context,
164
168
  feature_gates: featureGates,
169
+ override_config_version: overrideConfigVersion,
165
170
  };
166
171
 
167
172
  const rawResponse = await CommerceApiClient.getInstance().inferenceApi.v1UrlResolvingPostRaw({
@@ -470,35 +475,6 @@ class CommerceApiClient {
470
475
  }
471
476
  };
472
477
 
473
- static identifyUser = async (
474
- spiffyUserId: string,
475
- merchantUserId: string,
476
- uaDetails: ClientDetails,
477
- ): Promise<void> => {
478
- try {
479
- await CommerceApiClient.getInstance().defaultApi.v1AnalyticsIdentifyPost({
480
- AnalyticsIdentifyRequest: {
481
- user_id: spiffyUserId,
482
- os_name: uaDetails.os,
483
- os_version: uaDetails.osVersion,
484
- platform: uaDetails.os,
485
- device_id: uaDetails.deviceModel,
486
- device_brand: uaDetails.deviceBrand,
487
- device_manufacturer: uaDetails.deviceManufacturer,
488
- device_model: uaDetails.deviceModel,
489
- user_properties: {
490
- cdp_user_id: merchantUserId,
491
- browser: uaDetails.browser,
492
- browser_version: uaDetails.browserVersion,
493
- user_agent: uaDetails.userAgent,
494
- },
495
- },
496
- });
497
- } catch (err) {
498
- Logger.logError('Failed to identify user', err);
499
- }
500
- };
501
-
502
478
  private static mapContextSourceToV1OrgConfigGetSource = (
503
479
  source: ContextSourceEnum | undefined,
504
480
  ): V1OrgConfigGetSourceEnum | undefined => {
@@ -7,5 +7,6 @@ export type WidgetTextRequest = {
7
7
  context: Context;
8
8
  featureFlags: Record<string, boolean>;
9
9
  language: string;
10
+ overrideConfigVersion?: string;
10
11
  url: string;
11
12
  };
@@ -20,4 +20,6 @@ export enum ChatElementDisplayLocationV3 {
20
20
  PRODUCT_CARD_PROMPT_BUTTON = 'product_card_prompt_button',
21
21
  PRODUCT_CARD_TEXT_FIELD = 'product_card_text_field',
22
22
  WINDOW_API_CALL = 'window_api_call',
23
+ REFERRER_BASED_PROMPT = 'referrer_based_prompt',
24
+ AUTOMATIC_PROMPT = 'automatic_popup',
23
25
  }
@@ -1,7 +1,7 @@
1
+ import { ShowFloatingButtonOptions } from 'src/contexts/types';
1
2
  import { PLPInfo } from './plpInfo';
2
3
  import { PageVisitInfo } from './pageVisitInfo';
3
4
  import { ProductInfo } from './productInfo';
4
- import { ShowFloatingButtonOptions } from 'src/contexts/types';
5
5
 
6
6
  export enum VariantTypeEnum {
7
7
  Pdp = 'pdp',
@@ -5,7 +5,7 @@ import {
5
5
  isGA4EcommerceEvent,
6
6
  isLegacyUAEcommerceEvent,
7
7
  } from 'src/application/models';
8
- import { SpiffyMetricsEventName } from 'src/contexts/amplitudeContext/amplitudeContext';
8
+ import { SpiffyMetricsEventName } from 'src/services/amplitudeService/amplitudeService';
9
9
 
10
10
  declare global {
11
11
  interface Window {
@@ -32,7 +32,11 @@ class QuerySelector extends NodeSelector {
32
32
 
33
33
  class IDSelector extends NodeSelector {
34
34
  parse(): Node | null {
35
- return this.getRoot().getElementById(this.getPattern()) as Node;
35
+ const root = this.getRoot();
36
+ if (typeof root?.getElementById !== 'function') {
37
+ return null;
38
+ }
39
+ return root.getElementById(this.getPattern()) as Node;
36
40
  }
37
41
  }
38
42
 
@@ -50,19 +54,19 @@ class XpathSelector extends NodeSelector {
50
54
 
51
55
  class ChainSelector extends NodeSelector {
52
56
  parse(): Node | null {
53
- let selectorIndex = 0;
54
57
  const selectors = this.getPattern().split('@');
55
- const lastIndex = selectors.length - 1;
58
+ let currentRoot: Node | null = null;
56
59
 
57
- const parseChain = (pattern: string, prevNode?: Node | null): Node | null => {
58
- const selector = SelectorFactory.parse(pattern);
60
+ for (let i = 0; i < selectors.length; i += 1) {
61
+ const selector = SelectorFactory.parse(selectors[i].trim());
59
62
 
60
- if (prevNode) {
61
- selector.setRoot(prevNode as Document);
63
+ if (currentRoot) {
64
+ selector.setRoot(currentRoot as Document);
62
65
  }
63
66
 
64
67
  const currentNode = selector.parse();
65
- if (selectorIndex === lastIndex) {
68
+
69
+ if (i === selectors.length - 1) {
66
70
  return currentNode;
67
71
  }
68
72
 
@@ -75,13 +79,10 @@ class ChainSelector extends NodeSelector {
75
79
  node = (currentNode as HTMLIFrameElement).contentWindow?.document;
76
80
  }
77
81
 
78
- const nextIndex = selectorIndex + 1;
79
- const result = parseChain(selectors[nextIndex].trim(), node);
80
- selectorIndex = nextIndex; // Update the outer scope variable to reflect the advancement
81
- return result;
82
- };
82
+ currentRoot = node ?? null;
83
+ }
83
84
 
84
- return parseChain(selectors[selectorIndex].trim());
85
+ return null;
85
86
  }
86
87
  }
87
88
 
@@ -47,5 +47,6 @@ export const coreWidgetTextRequestToApiRequest = (
47
47
  feature_flags: coreWidgetTextRequest.featureFlags,
48
48
  language: coreWidgetTextRequest.language,
49
49
  url: coreWidgetTextRequest.url,
50
+ org_base_config_version: coreWidgetTextRequest.overrideConfigVersion,
50
51
  widget_type: coreWidgetTypeToApiWidgetType(coreWidgetTextRequest.widgetType),
51
52
  });
@@ -1,6 +1,6 @@
1
1
  import { UserEventCategory } from '@spiffy-ai/commerce-api-client/dist/models/UserEventCategory';
2
2
  import { atom } from 'jotai';
3
- import { SpiffyMetricsEventName } from 'src/contexts/amplitudeContext/amplitudeContext';
3
+ import { SpiffyMetricsEventName } from 'src/services/amplitudeService/amplitudeService';
4
4
  import {
5
5
  ChatElementDisplayLocationV3,
6
6
  FormSubmittedAttributes,
@@ -7,7 +7,7 @@ import {
7
7
  userQueryAtom,
8
8
  } from 'src/atoms/chat';
9
9
  import { UserEventCategory } from '@spiffy-ai/commerce-api-client';
10
- import { SpiffyMetricsEventName } from 'src/contexts/amplitudeContext/amplitudeContext';
10
+ import { SpiffyMetricsEventName } from 'src/services/amplitudeService/amplitudeService';
11
11
  import { amplitudeTrackEventAtom } from 'src/atoms/amplitude/amplitudeTrackEventAtom';
12
12
  import { queueUserEventAtom } from './messageQueue';
13
13
 
@@ -104,7 +104,6 @@ export const AmplitudeProvider: React.FC<{
104
104
  const value = useMemo(
105
105
  () => ({
106
106
  trackEvent: async (params: TrackEventParams): Promise<void> => {
107
- console.log('=== trackEvent ===', params);
108
107
  if (service) {
109
108
  await service.trackEvent(params);
110
109
  }
@@ -17,7 +17,8 @@ import { EnviveAgent } from './types';
17
17
  import { SearchProvider } from '../searchContext';
18
18
  import { SalesAgentProvider } from '../salesAgentContext/salesAgentContext';
19
19
  import { SystemSettingsContextProvider } from '../systemSettingsContext';
20
- import { HardcopyProvider } from '../hardcopyContext';
20
+ import { HardcopyProvider, HardcopyResponse } from '../hardcopyContext';
21
+ import { WidgetTypeV3 } from '../typesV3';
21
22
  import { WidgetConfigProvider } from '../widgetConfigContext';
22
23
  import { PageProvider } from '../pageContext';
23
24
  import { UiConfigProvider } from '../uiConfigContext';
@@ -57,6 +58,7 @@ interface EnviveProviderProps extends AgentWrapperProps {
57
58
  previewMode?: boolean;
58
59
  overrideConfig?: GraphQlConfigValues;
59
60
  mockSalesAgentData?: any;
61
+ hardcopyOverride?: Partial<Record<WidgetTypeV3, HardcopyResponse>>;
60
62
  }
61
63
 
62
64
  const SearchAgentWrapper: React.FC<AgentWrapperProps> = ({ children, enabledAgents }) => {
@@ -106,6 +108,7 @@ export const EnviveProvider: React.FC<EnviveProviderProps> = ({
106
108
  mockV3ConfigToDeprecatedConfig = false,
107
109
  requestV3Config = false,
108
110
  mockSalesAgentData,
111
+ hardcopyOverride,
109
112
  ...config
110
113
  }) => {
111
114
  const [userId, setUserId] = useState<string>('');
@@ -184,7 +187,7 @@ export const EnviveProvider: React.FC<EnviveProviderProps> = ({
184
187
  <PageProvider previewMode={previewMode}>
185
188
  <UiConfigProvider>
186
189
  <WidgetConfigProvider>
187
- <HardcopyProvider>
190
+ <HardcopyProvider hardcopyOverride={hardcopyOverride}>
188
191
  <EnviveCssProvider>
189
192
  <SearchAgentWrapper enabledAgents={enabledAgents}>
190
193
  <WindowChatToggleBinder />
@@ -133,6 +133,9 @@ export const mockV3FrontendConfig: FrontendConfigV3 = {
133
133
  welcomeMessageText:
134
134
  'Your personal shopper trained on the collective knowledge of thousands of real experts!',
135
135
  chatFooterTextFieldPlaceholderText: 'Ask me anything...',
136
+ partialViewConfig: {
137
+ disabled: true,
138
+ },
136
139
  },
137
140
  customerServiceIntegration: {
138
141
  provider: CustomerServiceType.unsupported,
@@ -10,6 +10,7 @@ import { appDetailsAtom } from 'src/atoms/app';
10
10
  import { EnviveMetricsEventName } from 'src/services/amplitudeService/amplitudeService';
11
11
  import { toCamelCase } from 'src/application/models/utils/snakeToCamelTransformer';
12
12
  import { UserEvent } from 'src/application/models';
13
+ import { getQueryParam } from 'src/application/utils';
13
14
  import { WidgetTypeV3 } from '../typesV3';
14
15
  import { useFeatureFlagService } from '../featureFlagServiceContext/featureFlagServiceContext';
15
16
  import { useAmplitude } from '../amplitudeContext';
@@ -197,7 +198,15 @@ const MOCK_HARDCOPY_RESPONSE: Partial<Record<WidgetTypeV3, HardcopyResponse>> =
197
198
 
198
199
  const HardcopyContext = createContext<HardcopyContextType | undefined>(undefined);
199
200
 
200
- export const HardcopyProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
201
+ interface HardcopyProviderProps {
202
+ children: ReactNode;
203
+ hardcopyOverride?: Partial<Record<WidgetTypeV3, HardcopyResponse>>;
204
+ }
205
+
206
+ export const HardcopyProvider: React.FC<HardcopyProviderProps> = ({
207
+ children,
208
+ hardcopyOverride,
209
+ }) => {
201
210
  const languages = useMemo(() => navigator.languages, []);
202
211
  const [isLoading, setIsLoading] = useState(false);
203
212
  const context = useAtomValue(appDetailsAtom);
@@ -206,12 +215,21 @@ export const HardcopyProvider: React.FC<{ children: ReactNode }> = ({ children }
206
215
  const { featureFlagService } = useFeatureFlagService();
207
216
  const getHardcopyFromBackend = useCallback(
208
217
  async (request: HardcopyRequest): Promise<HardcopyResponse> => {
218
+ if (hardcopyOverride?.[request.widgetType]) {
219
+ Logger.logInfo('hardcopyContext | using hardcopy override', request.widgetType);
220
+ return hardcopyOverride[request.widgetType]!;
221
+ }
222
+ const overrideConfigVersion =
223
+ getQueryParam('spiffy_config_version') ||
224
+ getQueryParam('envive_config_version') ||
225
+ undefined;
209
226
  const widgetTextRequest: WidgetTextRequest = {
210
227
  requestId: uuid(),
211
228
  widgetType: request.widgetType,
212
229
  context,
213
230
  featureFlags: featureFlagService?.getFeatureFlags() || {},
214
231
  language: languages[0] || 'en',
232
+ overrideConfigVersion,
215
233
  url: window.location.href,
216
234
  };
217
235
  trackEvent({
@@ -247,7 +265,7 @@ export const HardcopyProvider: React.FC<{ children: ReactNode }> = ({ children }
247
265
  }
248
266
  throw new Error(`No hardcopy response found for widget type: ${request.widgetType}`);
249
267
  },
250
- [context, featureFlagService, languages, trackEvent],
268
+ [context, featureFlagService, hardcopyOverride, languages, trackEvent],
251
269
  );
252
270
 
253
271
  const getHardcopy = useCallback(
@@ -67,11 +67,15 @@ export const PageProvider: React.FC<{
67
67
 
68
68
  const setVariantFromUrlResolver = useCallback(
69
69
  (url: string, response: UrlResolverResponse) => {
70
- const newVariantInfo = mapUrlResolverResponseToVariantInfo(url, response);
71
- const newUserEvent = mapApiUserEventToUserEvent(response.user_event ?? undefined);
72
- setVariantInfo(newVariantInfo);
73
- console.log('=== newUserEvent ===', newUserEvent);
74
- setUserEvent(newUserEvent);
70
+ if (response.ready) {
71
+ const newVariantInfo = mapUrlResolverResponseToVariantInfo(url, response);
72
+ const newUserEvent = mapApiUserEventToUserEvent(response.user_event ?? undefined);
73
+ setVariantInfo(newVariantInfo);
74
+ setUserEvent(newUserEvent);
75
+ } else {
76
+ setUserEvent(undefined);
77
+ setVariantInfo(undefined);
78
+ }
75
79
  },
76
80
  [setVariantInfo, setUserEvent],
77
81
  );
@@ -56,7 +56,6 @@ export const useSalesAgentChatAPI = () => {
56
56
  const logPageVisit = useCallback(
57
57
  ({ pageVisitCategory }: { pageVisitCategory: PageVisitCategory }) => {
58
58
  const eventId = uuid();
59
- console.log('=== logPageVisit ===', eventId);
60
59
  trackEvent({
61
60
  eventName: EnviveMetricsEventName.ChatRequest,
62
61
  eventProps: {
@@ -22,10 +22,13 @@ import {
22
22
  suggestionsAtom,
23
23
  } from 'src/atoms/chat/chatState';
24
24
  import { useMessageInterceptor } from 'src/interceptors/useMessageInterceptor';
25
- import { SpiffyMetricsEventName, useAmplitude } from 'src/contexts/amplitudeContext';
25
+ import { useAmplitude } from 'src/contexts/amplitudeContext';
26
+ import {
27
+ EnviveMetricsEventName,
28
+ SpiffyMetricsEventName,
29
+ } from 'src/services/amplitudeService/amplitudeService';
26
30
  import { useFeatureFlagService } from 'src/contexts/featureFlagServiceContext';
27
31
  import { UserEventCategory } from '@spiffy-ai/commerce-api-client';
28
- import { EnviveMetricsEventName } from 'src/services/amplitudeService/amplitudeService';
29
32
  import { analyticsContextAtom } from 'src/atoms/app/variant';
30
33
 
31
34
  import { StatusCodeError } from './statusCodeError';
@@ -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'
@@ -937,6 +938,7 @@ export interface EnviveConfig {
937
938
  enviveOn?: boolean;
938
939
  publicKey?: string;
939
940
  featureGates?: OrgConfigFeatureGate[];
941
+ hardcopyOverride?: Partial<Record<WidgetTypeV3, HardcopyResponse>>;
940
942
  }
941
943
 
942
944
  export type {
@@ -184,6 +184,32 @@ 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
+
204
+ type PartialViewConfig = {
205
+ /**
206
+ * When true, only full-screen mode is supported (no partial/draggable middle state).
207
+ * Useful when partial view causes usability issues on mobile.
208
+ * Default: false (undefined and false = partial view enabled).
209
+ */
210
+ disabled?: boolean;
211
+ };
212
+
187
213
  type FloatingChatConfig = {
188
214
  headerBackgroundColor?: string;
189
215
  headerMode: Mode;
@@ -196,6 +222,8 @@ type FloatingChatConfig = {
196
222
  welcomeMessageTitle: string;
197
223
  welcomeMessageText: string;
198
224
  chatFooterTextFieldPlaceholderText: string;
225
+ autoPopupConfig?: AutoPopupConfig;
226
+ partialViewConfig?: PartialViewConfig;
199
227
  };
200
228
 
201
229
  type CustomerServiceIntegration = {
@@ -1,10 +1,9 @@
1
1
  import React from 'react';
2
- import { act, render, screen, waitFor } from '@testing-library/react';
2
+ import { render, screen, waitFor } from '@testing-library/react';
3
3
  import { Provider, useStore } from 'jotai';
4
4
  import { userIdAtom } from 'src/atoms/app';
5
5
  import { LocalStorageProvider } from 'src/contexts/localStorageContext';
6
6
  import Logger from 'src/application/logging/logger';
7
- import CommerceApiClient from 'src/application/commerce-api';
8
7
  import { UserIdentityService } from 'src/services/userIdentityService';
9
8
  import { UserIdentityProvider, useUserIdentity } from '../userIdentityContext';
10
9
 
@@ -13,13 +12,6 @@ vi.spyOn(Logger, 'logInfo').mockImplementation(() => {});
13
12
  vi.spyOn(Logger, 'logWarn').mockImplementation(() => {});
14
13
  vi.spyOn(Logger, 'logError').mockImplementation(() => {});
15
14
 
16
- // Mock CommerceApiClient
17
- vi.mock('src/application/commerce-api', () => ({
18
- default: {
19
- identifyUser: vi.fn().mockResolvedValue(undefined),
20
- },
21
- }));
22
-
23
15
  // Mock uuid to have predictable values in tests
24
16
  vi.mock('uuid', () => ({
25
17
  v4: vi.fn(() => 'test-uuid-12345'),
@@ -97,31 +89,6 @@ const AtomReaderComponent: React.FC = () => {
97
89
  return <div data-testid="atom-reader">{userId}</div>;
98
90
  };
99
91
 
100
- // Component that uses the hook and triggers identifyUser
101
- const IdentifyUserComponent: React.FC = () => {
102
- const context = useUserIdentity();
103
- const [identifying, setIdentifying] = React.useState(false);
104
-
105
- const handleIdentify = async () => {
106
- setIdentifying(true);
107
- await context.identifyUser();
108
- setIdentifying(false);
109
- };
110
-
111
- return (
112
- <div>
113
- <button
114
- type="button"
115
- data-testid="identify-button"
116
- onClick={handleIdentify}
117
- >
118
- Identify
119
- </button>
120
- {identifying && <div data-testid="identifying">Identifying...</div>}
121
- </div>
122
- );
123
- };
124
-
125
92
  describe('UserIdentityProvider', () => {
126
93
  beforeEach(() => {
127
94
  vi.clearAllMocks();
@@ -334,36 +301,4 @@ describe('UserIdentityProvider', () => {
334
301
  });
335
302
  });
336
303
  });
337
-
338
- describe('identifyUser', () => {
339
- it('should call CommerceApiClient.identifyUser with correct parameters', async () => {
340
- const identifySpy = vi.spyOn(CommerceApiClient, 'identifyUser');
341
-
342
- renderWithProviders(<IdentifyUserComponent />);
343
-
344
- await waitFor(() => {
345
- expect(screen.getByTestId('identify-button')).toBeInTheDocument();
346
- });
347
-
348
- await act(async () => {
349
- screen.getByTestId('identify-button').click();
350
- });
351
-
352
- await waitFor(
353
- () => {
354
- expect(identifySpy).toHaveBeenCalled();
355
- const callArgs = identifySpy.mock.calls[0];
356
- expect(callArgs[0]).toContain('spiffy-user-id-'); // spiffyUserId
357
- expect(callArgs[1]).toBe('UNKNOWN_CDP_USER_ID'); // merchantUserId (cdpUserId)
358
- // userAgentDetails - in test environment, some values may be undefined
359
- expect(callArgs[2]).toBeDefined();
360
- expect(typeof callArgs[2]).toBe('object');
361
- // Verify it has the expected structure (values may be undefined in test env)
362
- expect(callArgs[2]).toHaveProperty('os');
363
- expect(callArgs[2]).toHaveProperty('browser');
364
- },
365
- { timeout: 3000 },
366
- );
367
- });
368
- });
369
304
  });
@@ -7,34 +7,13 @@ import React, {
7
7
  useMemo,
8
8
  useState,
9
9
  } from 'react';
10
- import UAParser from 'ua-parser-js';
11
10
  import Logger from 'src/application/logging/logger';
12
- import CommerceApiClient from 'src/application/commerce-api';
13
- import { ClientDetails } from 'src/application/models/clientDetails';
14
11
  import { useLocalStorage } from 'src/contexts/localStorageContext';
15
12
  import { useSetAtom } from 'jotai';
16
13
  import { userIdAtom } from 'src/atoms/app';
17
14
  import { UserIdentityService } from 'src/services/userIdentityService';
18
15
 
19
- // Helper function from the original service
20
- const getUserAgentDetails = (): ClientDetails => {
21
- const uaParser = new UAParser();
22
- const result = uaParser.getResult();
23
-
24
- return {
25
- os: result?.os?.name,
26
- osVersion: result?.os?.version,
27
- deviceBrand: result?.device?.vendor,
28
- deviceManufacturer: result?.device?.vendor,
29
- deviceModel: result?.device?.model,
30
- browser: result?.browser?.name,
31
- browserVersion: result?.browser?.version,
32
- userAgent: result?.ua,
33
- };
34
- };
35
-
36
16
  export interface UserIdentityContextType {
37
- identifyUser: () => Promise<void>;
38
17
  getUserIdOrDefault: () => Promise<string>;
39
18
  getUserIdOverrideFromLocalStorage: () => string | undefined;
40
19
  setUserIdOverrideInLocalStorage: (userId: string) => string;
@@ -113,33 +92,8 @@ export const UserIdentityProvider: React.FC<UserIdentityProviderProps> = ({
113
92
  }
114
93
  }, [getUserIdOverrideFromLocalStorage]);
115
94
 
116
- const identifyUser = useCallback(async (): Promise<void> => {
117
- if (!isReady) {
118
- Logger.logWarn('[UserIdentityContext] Context not ready, skipping identifyUser', undefined);
119
- return;
120
- }
121
-
122
- try {
123
- // Temporarily commented out until WindowDataLayerService is resolved
124
- // const cdpUserId = WindowDataLayerService.getGoogleAnalyticsClientId();
125
- const cdpUserId = 'UNKNOWN_CDP_USER_ID'; // Placeholder
126
- const userId = await getUserIdOrDefault();
127
- const userAgentDetails = getUserAgentDetails();
128
-
129
- if (!cdpUserId) {
130
- Logger.logWarn('[spiffy-ai] No GA Client ID found, skipping identifyUser', undefined);
131
- return;
132
- }
133
-
134
- await CommerceApiClient.identifyUser(userId, cdpUserId, userAgentDetails);
135
- } catch (error) {
136
- Logger.logError('[spiffy-ai] Error identifying user', error);
137
- }
138
- }, [isReady, getUserIdOrDefault]);
139
-
140
95
  const value = useMemo(
141
96
  () => ({
142
- identifyUser,
143
97
  getUserIdOrDefault,
144
98
  getUserIdOverrideFromLocalStorage,
145
99
  setUserIdOverrideInLocalStorage,
@@ -147,7 +101,6 @@ export const UserIdentityProvider: React.FC<UserIdentityProviderProps> = ({
147
101
  isReady,
148
102
  }),
149
103
  [
150
- identifyUser,
151
104
  getUserIdOrDefault,
152
105
  getUserIdOverrideFromLocalStorage,
153
106
  setUserIdOverrideInLocalStorage,
@@ -1,8 +1,6 @@
1
1
  import { useCallback, useState } from 'react';
2
- import {
3
- SpiffyMetricsEventName,
4
- useAmplitude,
5
- } from 'src/contexts/amplitudeContext/amplitudeContext';
2
+ import { useAmplitude } from 'src/contexts/amplitudeContext/amplitudeContext';
3
+ import { SpiffyMetricsEventName } from 'src/services/amplitudeService/amplitudeService';
6
4
 
7
5
  export const useAmplitudeTracking = () => {
8
6
  const { trackEvent, isReady } = useAmplitude();
@@ -1,10 +1,8 @@
1
1
  import { useAtomValue, useSetAtom } from 'jotai';
2
2
  import { ChatElementDisplayLocationV3 } from 'src/application/models';
3
3
  import { chatAtom, chatOnToggleAtom } from 'src/atoms/chat';
4
- import {
5
- SpiffyMetricsEventName,
6
- useAmplitude,
7
- } from 'src/contexts/amplitudeContext/amplitudeContext';
4
+ import { useAmplitude } from 'src/contexts/amplitudeContext/amplitudeContext';
5
+ import { SpiffyMetricsEventName } from 'src/services/amplitudeService/amplitudeService';
8
6
 
9
7
  export const useChatToggle = () => {
10
8
  const onToggle = useSetAtom(chatOnToggleAtom);