@envive-ai/react-hooks 0.3.19 → 0.3.20

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 (72) hide show
  1. package/dist/atoms/app/index.d.cts +7 -7
  2. package/dist/atoms/app/index.d.ts +7 -7
  3. package/dist/atoms/chat/chatState.d.cts +18 -18
  4. package/dist/atoms/chat/chatState.d.ts +18 -18
  5. package/dist/atoms/chat/form.d.cts +2 -2
  6. package/dist/atoms/chat/form.d.ts +2 -2
  7. package/dist/atoms/chat/index.d.cts +3 -3
  8. package/dist/atoms/chat/index.d.ts +2 -2
  9. package/dist/atoms/chat/lastMessage.d.cts +2 -2
  10. package/dist/atoms/chat/lastMessage.d.ts +2 -2
  11. package/dist/atoms/chat/messageQueue.d.cts +6 -6
  12. package/dist/atoms/chat/messageQueue.d.ts +6 -6
  13. package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
  14. package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
  15. package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
  16. package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
  17. package/dist/atoms/chat/replies.d.cts +3 -3
  18. package/dist/atoms/chat/replies.d.ts +3 -3
  19. package/dist/atoms/chat/suggestions.d.cts +2 -2
  20. package/dist/atoms/chat/suggestions.d.ts +2 -2
  21. package/dist/atoms/envive/enviveConfig.d.cts +13 -13
  22. package/dist/atoms/envive/enviveConfig.d.ts +13 -13
  23. package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
  24. package/dist/atoms/org/customerService.d.cts +6 -6
  25. package/dist/atoms/org/customerService.d.ts +6 -6
  26. package/dist/atoms/org/graphqlConfig.d.cts +4 -4
  27. package/dist/atoms/org/graphqlConfig.d.ts +4 -4
  28. package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
  29. package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
  30. package/dist/atoms/org/orgAnalyticsConfig.d.cts +5 -5
  31. package/dist/atoms/org/orgAnalyticsConfig.d.ts +5 -5
  32. package/dist/atoms/search/chatSearch.d.cts +17 -17
  33. package/dist/atoms/search/chatSearch.d.ts +17 -17
  34. package/dist/atoms/search/searchAPI.d.cts +13 -13
  35. package/dist/atoms/search/searchAPI.d.ts +13 -13
  36. package/dist/atoms/search/utils.d.ts +1 -1
  37. package/dist/atoms/widget/chatPreviewLoading.d.cts +2 -2
  38. package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
  39. package/dist/contexts/enviveContext/enviveContext.cjs +41 -7
  40. package/dist/contexts/enviveContext/enviveContext.d.cts +8 -2
  41. package/dist/contexts/enviveContext/enviveContext.d.ts +8 -2
  42. package/dist/contexts/enviveContext/enviveContext.js +42 -8
  43. package/dist/contexts/enviveContext/index.d.cts +2 -2
  44. package/dist/contexts/enviveContext/index.d.ts +2 -2
  45. package/dist/contexts/pageContext/pageContext.cjs +78 -3
  46. package/dist/contexts/pageContext/pageContext.d.cts +3 -1
  47. package/dist/contexts/pageContext/pageContext.d.ts +3 -1
  48. package/dist/contexts/pageContext/pageContext.js +81 -6
  49. package/dist/contexts/systemSettingsContext/systemSettingsContext.d.cts +2 -2
  50. package/dist/contexts/types.d.cts +1 -1
  51. package/dist/contexts/types.d.ts +1 -1
  52. package/dist/contexts/typesV3.d.cts +1 -1
  53. package/dist/contexts/typesV3.d.ts +1 -1
  54. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.cts +2 -2
  55. package/dist/hooks/PageViewedEvent/index.cjs +4 -0
  56. package/dist/hooks/PageViewedEvent/index.d.cts +2 -0
  57. package/dist/hooks/PageViewedEvent/index.d.ts +2 -0
  58. package/dist/hooks/PageViewedEvent/index.js +3 -0
  59. package/dist/hooks/PageViewedEvent/usePageViewedEvent.cjs +84 -0
  60. package/dist/hooks/PageViewedEvent/usePageViewedEvent.d.cts +18 -0
  61. package/dist/hooks/PageViewedEvent/usePageViewedEvent.d.ts +18 -0
  62. package/dist/hooks/PageViewedEvent/usePageViewedEvent.js +82 -0
  63. package/dist/hooks/SystemSettingsContext/useSystemSettingsContext.d.cts +2 -2
  64. package/dist/hooks/utils.d.cts +1 -1
  65. package/dist/hooks/utils.d.ts +1 -1
  66. package/package.json +5 -1
  67. package/src/contexts/enviveContext/enviveContext.tsx +71 -7
  68. package/src/contexts/pageContext/__tests__/pageContext.test.tsx +6 -0
  69. package/src/contexts/pageContext/pageContext.tsx +79 -2
  70. package/src/hooks/PageViewedEvent/__tests__/usePageViewedEvent.test.ts +297 -0
  71. package/src/hooks/PageViewedEvent/index.ts +1 -0
  72. package/src/hooks/PageViewedEvent/usePageViewedEvent.ts +103 -0
@@ -0,0 +1,82 @@
1
+ import { VariantTypeEnum } from "../../application/models/variantInfo/variantInfo.js";
2
+ import "../../application/models/index.js";
3
+ import { EnviveMetricsEventName } from "../../services/amplitudeService/eventNames.js";
4
+ import { hasParsedVariantInfoAtom, variantInfoAtom } from "../../atoms/app/variant.js";
5
+ import { useAmplitude } from "../../contexts/amplitudeContext/amplitudeContext.js";
6
+ import "../../contexts/amplitudeContext/index.js";
7
+ import { usePage } from "../../contexts/pageContext/pageContext.js";
8
+ import "../../contexts/pageContext/index.js";
9
+ import { useEffect, useRef } from "react";
10
+ import { useAtomValue } from "jotai";
11
+
12
+ //#region src/hooks/PageViewedEvent/usePageViewedEvent.ts
13
+ const extractPageViewedContext = (pageVariant) => {
14
+ switch (pageVariant.variantType) {
15
+ case VariantTypeEnum.Pdp: return {
16
+ page_type: "pdp",
17
+ page_id: pageVariant.productId
18
+ };
19
+ case VariantTypeEnum.Plp: return {
20
+ page_type: "plp",
21
+ page_id: pageVariant.plpId
22
+ };
23
+ case VariantTypeEnum.Home: return {
24
+ page_type: "homepage",
25
+ page_id: pageVariant.url
26
+ };
27
+ case VariantTypeEnum.Other: return {
28
+ page_type: "other",
29
+ page_id: pageVariant.url
30
+ };
31
+ case VariantTypeEnum.PageVisit: return {
32
+ page_type: "other",
33
+ page_id: pageVariant.url
34
+ };
35
+ case VariantTypeEnum.FullPageSalesAgent: return {
36
+ page_type: "full_page_sales_agent",
37
+ page_id: pageVariant.url
38
+ };
39
+ default: return null;
40
+ }
41
+ };
42
+ /**
43
+ * Fires the [Envive] Page Viewed event once per page load when page context data is ready.
44
+ *
45
+ * This event captures page context information and is intended to eventually replace
46
+ * the [Amplitude] Page Viewed event.
47
+ */
48
+ const usePageViewedEvent = () => {
49
+ const hasFired = useRef(false);
50
+ const { trackEvent } = useAmplitude();
51
+ const { variantInfo: pageVariantInfo, isSupported, isLoading } = usePage();
52
+ const variantInfo = useAtomValue(variantInfoAtom);
53
+ const hasParsedVariantInfo = useAtomValue(hasParsedVariantInfoAtom);
54
+ useEffect(() => {
55
+ if (hasFired.current) return;
56
+ if (isLoading || !hasParsedVariantInfo || !pageVariantInfo) return;
57
+ const pageContext = extractPageViewedContext(pageVariantInfo);
58
+ if (!pageContext) return;
59
+ hasFired.current = true;
60
+ trackEvent({
61
+ eventName: EnviveMetricsEventName.PageViewed,
62
+ eventProps: {
63
+ "context.page_type": pageContext.page_type,
64
+ "context.page_id": pageContext.page_id,
65
+ "context.supported": isSupported,
66
+ "context.ready": isSupported,
67
+ "context.page_variant_id": variantInfo.variantId
68
+ }
69
+ });
70
+ }, [
71
+ isLoading,
72
+ isSupported,
73
+ hasParsedVariantInfo,
74
+ pageVariantInfo,
75
+ variantInfo,
76
+ trackEvent
77
+ ]);
78
+ };
79
+
80
+ //#endregion
81
+ export { extractPageViewedContext, usePageViewedEvent };
82
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlUGFnZVZpZXdlZEV2ZW50LmpzIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9ob29rcy9QYWdlVmlld2VkRXZlbnQvdXNlUGFnZVZpZXdlZEV2ZW50LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHVzZUF0b21WYWx1ZSB9IGZyb20gJ2pvdGFpJztcbmltcG9ydCB7IHVzZUVmZmVjdCwgdXNlUmVmIH0gZnJvbSAncmVhY3QnO1xuaW1wb3J0IHsgVmFyaWFudFR5cGVFbnVtIH0gZnJvbSAnc3JjL2FwcGxpY2F0aW9uL21vZGVscyc7XG5pbXBvcnQgeyBoYXNQYXJzZWRWYXJpYW50SW5mb0F0b20sIHZhcmlhbnRJbmZvQXRvbSB9IGZyb20gJ3NyYy9hdG9tcy9hcHAvdmFyaWFudCc7XG5pbXBvcnQgeyBFbnZpdmVNZXRyaWNzRXZlbnROYW1lLCB1c2VBbXBsaXR1ZGUgfSBmcm9tICdzcmMvY29udGV4dHMvYW1wbGl0dWRlQ29udGV4dCc7XG5pbXBvcnQgeyB1c2VQYWdlIH0gZnJvbSAnc3JjL2NvbnRleHRzL3BhZ2VDb250ZXh0JztcbmltcG9ydCB7XG4gIEZ1bGxQYWdlU2FsZXNBZ2VudFZhcmlhbnRJbmZvLFxuICBIb21lVmFyaWFudEluZm8sXG4gIE90aGVyVmFyaWFudEluZm8sXG4gIFBEUFBhZ2VWYXJpYW50SW5mbyxcbiAgUExQUGFnZVZhcmlhbnRJbmZvLFxuICBQYWdlVmFyaWFudEluZm8sXG4gIFZpc2l0UGFnZVZhcmlhbnRJbmZvLFxufSBmcm9tICdzcmMvY29udGV4dHMvcGFnZUNvbnRleHQvdHlwZXMnO1xuXG5pbnRlcmZhY2UgUGFnZVZpZXdlZENvbnRleHQge1xuICBwYWdlX3R5cGU6IHN0cmluZztcbiAgcGFnZV9pZDogc3RyaW5nO1xufVxuXG5leHBvcnQgY29uc3QgZXh0cmFjdFBhZ2VWaWV3ZWRDb250ZXh0ID0gKFxuICBwYWdlVmFyaWFudDogUGFnZVZhcmlhbnRJbmZvLFxuKTogUGFnZVZpZXdlZENvbnRleHQgfCBudWxsID0+IHtcbiAgc3dpdGNoIChwYWdlVmFyaWFudC52YXJpYW50VHlwZSkge1xuICAgIGNhc2UgVmFyaWFudFR5cGVFbnVtLlBkcDpcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHBhZ2VfdHlwZTogJ3BkcCcsXG4gICAgICAgIHBhZ2VfaWQ6IChwYWdlVmFyaWFudCBhcyBQRFBQYWdlVmFyaWFudEluZm8pLnByb2R1Y3RJZCxcbiAgICAgIH07XG4gICAgY2FzZSBWYXJpYW50VHlwZUVudW0uUGxwOlxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgcGFnZV90eXBlOiAncGxwJyxcbiAgICAgICAgcGFnZV9pZDogKHBhZ2VWYXJpYW50IGFzIFBMUFBhZ2VWYXJpYW50SW5mbykucGxwSWQsXG4gICAgICB9O1xuICAgIGNhc2UgVmFyaWFudFR5cGVFbnVtLkhvbWU6XG4gICAgICByZXR1cm4ge1xuICAgICAgICBwYWdlX3R5cGU6ICdob21lcGFnZScsXG4gICAgICAgIHBhZ2VfaWQ6IChwYWdlVmFyaWFudCBhcyBIb21lVmFyaWFudEluZm8pLnVybCxcbiAgICAgIH07XG4gICAgY2FzZSBWYXJpYW50VHlwZUVudW0uT3RoZXI6XG4gICAgICByZXR1cm4ge1xuICAgICAgICBwYWdlX3R5cGU6ICdvdGhlcicsXG4gICAgICAgIHBhZ2VfaWQ6IChwYWdlVmFyaWFudCBhcyBPdGhlclZhcmlhbnRJbmZvKS51cmwsXG4gICAgICB9O1xuICAgIGNhc2UgVmFyaWFudFR5cGVFbnVtLlBhZ2VWaXNpdDpcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHBhZ2VfdHlwZTogJ290aGVyJyxcbiAgICAgICAgcGFnZV9pZDogKHBhZ2VWYXJpYW50IGFzIFZpc2l0UGFnZVZhcmlhbnRJbmZvKS51cmwsXG4gICAgICB9O1xuICAgIGNhc2UgVmFyaWFudFR5cGVFbnVtLkZ1bGxQYWdlU2FsZXNBZ2VudDpcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHBhZ2VfdHlwZTogJ2Z1bGxfcGFnZV9zYWxlc19hZ2VudCcsXG4gICAgICAgIHBhZ2VfaWQ6IChwYWdlVmFyaWFudCBhcyBGdWxsUGFnZVNhbGVzQWdlbnRWYXJpYW50SW5mbykudXJsLFxuICAgICAgfTtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIG51bGw7XG4gIH1cbn07XG5cbi8qKlxuICogRmlyZXMgdGhlIFtFbnZpdmVdIFBhZ2UgVmlld2VkIGV2ZW50IG9uY2UgcGVyIHBhZ2UgbG9hZCB3aGVuIHBhZ2UgY29udGV4dCBkYXRhIGlzIHJlYWR5LlxuICpcbiAqIFRoaXMgZXZlbnQgY2FwdHVyZXMgcGFnZSBjb250ZXh0IGluZm9ybWF0aW9uIGFuZCBpcyBpbnRlbmRlZCB0byBldmVudHVhbGx5IHJlcGxhY2VcbiAqIHRoZSBbQW1wbGl0dWRlXSBQYWdlIFZpZXdlZCBldmVudC5cbiAqL1xuZXhwb3J0IGNvbnN0IHVzZVBhZ2VWaWV3ZWRFdmVudCA9ICgpID0+IHtcbiAgY29uc3QgaGFzRmlyZWQgPSB1c2VSZWYoZmFsc2UpO1xuICBjb25zdCB7IHRyYWNrRXZlbnQgfSA9IHVzZUFtcGxpdHVkZSgpO1xuICBjb25zdCB7IHZhcmlhbnRJbmZvOiBwYWdlVmFyaWFudEluZm8sIGlzU3VwcG9ydGVkLCBpc0xvYWRpbmcgfSA9IHVzZVBhZ2UoKTtcbiAgY29uc3QgdmFyaWFudEluZm8gPSB1c2VBdG9tVmFsdWUodmFyaWFudEluZm9BdG9tKTtcbiAgY29uc3QgaGFzUGFyc2VkVmFyaWFudEluZm8gPSB1c2VBdG9tVmFsdWUoaGFzUGFyc2VkVmFyaWFudEluZm9BdG9tKTtcblxuICB1c2VFZmZlY3QoKCkgPT4ge1xuICAgIGlmIChoYXNGaXJlZC5jdXJyZW50KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGlzTG9hZGluZyB8fCAhaGFzUGFyc2VkVmFyaWFudEluZm8gfHwgIXBhZ2VWYXJpYW50SW5mbykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHBhZ2VDb250ZXh0ID0gZXh0cmFjdFBhZ2VWaWV3ZWRDb250ZXh0KHBhZ2VWYXJpYW50SW5mbyk7XG4gICAgaWYgKCFwYWdlQ29udGV4dCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGhhc0ZpcmVkLmN1cnJlbnQgPSB0cnVlO1xuXG4gICAgdHJhY2tFdmVudCh7XG4gICAgICBldmVudE5hbWU6IEVudml2ZU1ldHJpY3NFdmVudE5hbWUuUGFnZVZpZXdlZCxcbiAgICAgIGV2ZW50UHJvcHM6IHtcbiAgICAgICAgJ2NvbnRleHQucGFnZV90eXBlJzogcGFnZUNvbnRleHQucGFnZV90eXBlLFxuICAgICAgICAnY29udGV4dC5wYWdlX2lkJzogcGFnZUNvbnRleHQucGFnZV9pZCxcbiAgICAgICAgLy8gY29udGV4dC5zdXBwb3J0ZWQgYW5kIGNvbnRleHQucmVhZHkgYm90aCBkZXJpdmUgZnJvbSBpc1N1cHBvcnRlZCAocmVzcG9uc2UucmVhZHkpXG4gICAgICAgIC8vIGJlY2F1c2UgdGhlIHN1cHBvcnRlZEV2ZW50QXRvbSBpcyBub3QgY3VycmVudGx5IHBvcHVsYXRlZC5cbiAgICAgICAgJ2NvbnRleHQuc3VwcG9ydGVkJzogaXNTdXBwb3J0ZWQsXG4gICAgICAgICdjb250ZXh0LnJlYWR5JzogaXNTdXBwb3J0ZWQsXG4gICAgICAgICdjb250ZXh0LnBhZ2VfdmFyaWFudF9pZCc6IHZhcmlhbnRJbmZvLnZhcmlhbnRJZCxcbiAgICAgIH0sXG4gICAgfSk7XG4gIH0sIFtpc0xvYWRpbmcsIGlzU3VwcG9ydGVkLCBoYXNQYXJzZWRWYXJpYW50SW5mbywgcGFnZVZhcmlhbnRJbmZvLCB2YXJpYW50SW5mbywgdHJhY2tFdmVudF0pO1xufTtcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBcUJBLE1BQWEsNEJBQ1gsZ0JBQzZCO0FBQzdCLFNBQVEsWUFBWSxhQUFwQjtFQUNFLEtBQUssZ0JBQWdCLElBQ25CLFFBQU87R0FDTCxXQUFXO0dBQ1gsU0FBVSxZQUFtQztHQUM5QztFQUNILEtBQUssZ0JBQWdCLElBQ25CLFFBQU87R0FDTCxXQUFXO0dBQ1gsU0FBVSxZQUFtQztHQUM5QztFQUNILEtBQUssZ0JBQWdCLEtBQ25CLFFBQU87R0FDTCxXQUFXO0dBQ1gsU0FBVSxZQUFnQztHQUMzQztFQUNILEtBQUssZ0JBQWdCLE1BQ25CLFFBQU87R0FDTCxXQUFXO0dBQ1gsU0FBVSxZQUFpQztHQUM1QztFQUNILEtBQUssZ0JBQWdCLFVBQ25CLFFBQU87R0FDTCxXQUFXO0dBQ1gsU0FBVSxZQUFxQztHQUNoRDtFQUNILEtBQUssZ0JBQWdCLG1CQUNuQixRQUFPO0dBQ0wsV0FBVztHQUNYLFNBQVUsWUFBOEM7R0FDekQ7RUFDSCxRQUNFLFFBQU87Ozs7Ozs7OztBQVViLE1BQWEsMkJBQTJCO0NBQ3RDLE1BQU0sV0FBVyxPQUFPLE1BQU07Q0FDOUIsTUFBTSxFQUFFLGVBQWUsY0FBYztDQUNyQyxNQUFNLEVBQUUsYUFBYSxpQkFBaUIsYUFBYSxjQUFjLFNBQVM7Q0FDMUUsTUFBTSxjQUFjLGFBQWEsZ0JBQWdCO0NBQ2pELE1BQU0sdUJBQXVCLGFBQWEseUJBQXlCO0FBRW5FLGlCQUFnQjtBQUNkLE1BQUksU0FBUyxRQUNYO0FBR0YsTUFBSSxhQUFhLENBQUMsd0JBQXdCLENBQUMsZ0JBQ3pDO0VBR0YsTUFBTSxjQUFjLHlCQUF5QixnQkFBZ0I7QUFDN0QsTUFBSSxDQUFDLFlBQ0g7QUFHRixXQUFTLFVBQVU7QUFFbkIsYUFBVztHQUNULFdBQVcsdUJBQXVCO0dBQ2xDLFlBQVk7SUFDVixxQkFBcUIsWUFBWTtJQUNqQyxtQkFBbUIsWUFBWTtJQUcvQixxQkFBcUI7SUFDckIsaUJBQWlCO0lBQ2pCLDJCQUEyQixZQUFZO0lBQ3hDO0dBQ0YsQ0FBQztJQUNEO0VBQUM7RUFBVztFQUFhO0VBQXNCO0VBQWlCO0VBQWE7RUFBVyxDQUFDIn0=
@@ -1,12 +1,12 @@
1
1
  import { GenerationParams } from "../../application/models/api/generationParams.cjs";
2
- import * as react1 from "react";
2
+ import * as react0 from "react";
3
3
 
4
4
  //#region src/hooks/SystemSettingsContext/useSystemSettingsContext.d.ts
5
5
  declare const useSystemSettingsContext: () => {
6
6
  generationParams?: GenerationParams;
7
7
  showDebugBar?: boolean;
8
8
  endpointURL?: string;
9
- setGenerationParams: react1.Dispatch<react1.SetStateAction<GenerationParams | undefined>>;
9
+ setGenerationParams: react0.Dispatch<react0.SetStateAction<GenerationParams | undefined>>;
10
10
  };
11
11
  //#endregion
12
12
  export { useSystemSettingsContext };
@@ -19,4 +19,4 @@ declare enum SearchResultsState {
19
19
  declare const getSearchResultsState: (isLoadingSearch: boolean, searchData: SearchResult | null) => SearchResultsState;
20
20
  //#endregion
21
21
  export { SearchResultsState, createAppLoadedEvent, createVisitUserEvent, getSearchResultsState, isElementPartiallyVisible, isWithinBusinessHours };
22
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuZC5jdHMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2hvb2tzL3V0aWxzLmQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgU2VhcmNoUmVzdWx0IH0gZnJvbSAnc3JjL2FwcGxpY2F0aW9uL21vZGVscy9hcGkvc2VhcmNoJztcbmltcG9ydCB7IFVzZXJFdmVudCwgVmFyaWFudEluZm8gfSBmcm9tICdzcmMvYXBwbGljYXRpb24vbW9kZWxzJztcbmV4cG9ydCBkZWNsYXJlIGNvbnN0IGlzRWxlbWVudFBhcnRpYWxseVZpc2libGU6IChlbD86IEhUTUxEaXZFbGVtZW50IHwgbnVsbCkgPT4gYm9vbGVhbjtcbmV4cG9ydCBkZWNsYXJlIGNvbnN0IGNyZWF0ZUFwcExvYWRlZEV2ZW50OiAoKSA9PiBVc2VyRXZlbnQ7XG5leHBvcnQgZGVjbGFyZSBjb25zdCBjcmVhdGVWaXNpdFVzZXJFdmVudDogKHsgdmFyaWFudEluZm8sIH06IHtcbiAgICB2YXJpYW50SW5mbzogVmFyaWFudEluZm87XG59KSA9PiBVc2VyRXZlbnQgfCB1bmRlZmluZWQ7XG5leHBvcnQgZGVjbGFyZSBjb25zdCBpc1dpdGhpbkJ1c2luZXNzSG91cnM6IChzdGFydFRpbWU6IHN0cmluZywgZW5kVGltZTogc3RyaW5nLCB0aW1lWm9uZTogc3RyaW5nKSA9PiBib29sZWFuO1xuZXhwb3J0IGRlY2xhcmUgZW51bSBTZWFyY2hSZXN1bHRzU3RhdGUge1xuICAgIExvYWRpbmcgPSAwLFxuICAgIFJlc3VsdHMgPSAxLFxuICAgIE5vUmVzdWx0cyA9IDJcbn1cbmV4cG9ydCBkZWNsYXJlIGNvbnN0IGdldFNlYXJjaFJlc3VsdHNTdGF0ZTogKGlzTG9hZGluZ1NlYXJjaDogYm9vbGVhbiwgc2VhcmNoRGF0YTogU2VhcmNoUmVzdWx0IHwgbnVsbCkgPT4gU2VhcmNoUmVzdWx0c1N0YXRlO1xuIl0sIm1hcHBpbmdzIjoiOzs7OztBQUVBLElBQVcsNEJBQTRCLENBQUMsV0FBVyxlQUFlO0FBQ2xFLElBQVcsdUJBQXVCLENBQUMsV0FBVyxVQUFVO0FBQ3hELElBQVcsdUJBQXVCO0NBQUM7T0FBVztPQUFnQjtPQUFBO0NBQUE7QUFDOUQsSUFBVyx3QkFBaUIsQ0FBQSxJQUFBO0FBQzVCLElBQVcscUJBQWdCLENBQUEsSUFBQTtBQUMzQixJQUFXLHdCQUF3QjtDQUFDO09BQVc7T0FBb0I7Q0FBbUIifQ==
22
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuZC5jdHMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2hvb2tzL3V0aWxzLmQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgU2VhcmNoUmVzdWx0IH0gZnJvbSAnc3JjL2FwcGxpY2F0aW9uL21vZGVscy9hcGkvc2VhcmNoJztcbmltcG9ydCB7IFVzZXJFdmVudCwgVmFyaWFudEluZm8gfSBmcm9tICdzcmMvYXBwbGljYXRpb24vbW9kZWxzJztcbmV4cG9ydCBkZWNsYXJlIGNvbnN0IGlzRWxlbWVudFBhcnRpYWxseVZpc2libGU6IChlbD86IEhUTUxEaXZFbGVtZW50IHwgbnVsbCkgPT4gYm9vbGVhbjtcbmV4cG9ydCBkZWNsYXJlIGNvbnN0IGNyZWF0ZUFwcExvYWRlZEV2ZW50OiAoKSA9PiBVc2VyRXZlbnQ7XG5leHBvcnQgZGVjbGFyZSBjb25zdCBjcmVhdGVWaXNpdFVzZXJFdmVudDogKHsgdmFyaWFudEluZm8sIH06IHtcbiAgICB2YXJpYW50SW5mbzogVmFyaWFudEluZm87XG59KSA9PiBVc2VyRXZlbnQgfCB1bmRlZmluZWQ7XG5leHBvcnQgZGVjbGFyZSBjb25zdCBpc1dpdGhpbkJ1c2luZXNzSG91cnM6IChzdGFydFRpbWU6IHN0cmluZywgZW5kVGltZTogc3RyaW5nLCB0aW1lWm9uZTogc3RyaW5nKSA9PiBib29sZWFuO1xuZXhwb3J0IGRlY2xhcmUgZW51bSBTZWFyY2hSZXN1bHRzU3RhdGUge1xuICAgIExvYWRpbmcgPSAwLFxuICAgIFJlc3VsdHMgPSAxLFxuICAgIE5vUmVzdWx0cyA9IDJcbn1cbmV4cG9ydCBkZWNsYXJlIGNvbnN0IGdldFNlYXJjaFJlc3VsdHNTdGF0ZTogKGlzTG9hZGluZ1NlYXJjaDogYm9vbGVhbiwgc2VhcmNoRGF0YTogU2VhcmNoUmVzdWx0IHwgbnVsbCkgPT4gU2VhcmNoUmVzdWx0c1N0YXRlO1xuIl0sIm1hcHBpbmdzIjoiOzs7OztBQUVBLElBQVcsNEJBQTRCLENBQUMsU0FBUyxlQUFlO0FBQ2hFLElBQVcsdUJBQXVCLENBQUMsU0FBUyxVQUFVO0FBQ3RELElBQVcsdUJBQXVCO0NBQUM7T0FBUztPQUFrQjtPQUFBO0NBQUE7QUFDOUQsSUFBVyx3QkFBaUIsQ0FBQSxFQUFBO0FBQzVCLElBQVcscUJBQWdCLENBQUEsRUFBQTtBQUMzQixJQUFXLHdCQUF3QjtDQUFDO09BQVM7T0FBb0I7Q0FBbUIifQ==
@@ -19,4 +19,4 @@ declare enum SearchResultsState {
19
19
  declare const getSearchResultsState: (isLoadingSearch: boolean, searchData: SearchResult | null) => SearchResultsState;
20
20
  //#endregion
21
21
  export { SearchResultsState, createAppLoadedEvent, createVisitUserEvent, getSearchResultsState, isElementPartiallyVisible, isWithinBusinessHours };
22
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuZC50cyIsIm5hbWVzIjpbXSwic291cmNlcyI6WyIuLi8uLi9zcmMvaG9va3MvdXRpbHMuZC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBTZWFyY2hSZXN1bHQgfSBmcm9tICdzcmMvYXBwbGljYXRpb24vbW9kZWxzL2FwaS9zZWFyY2gnO1xuaW1wb3J0IHsgVXNlckV2ZW50LCBWYXJpYW50SW5mbyB9IGZyb20gJ3NyYy9hcHBsaWNhdGlvbi9tb2RlbHMnO1xuZXhwb3J0IGRlY2xhcmUgY29uc3QgaXNFbGVtZW50UGFydGlhbGx5VmlzaWJsZTogKGVsPzogSFRNTERpdkVsZW1lbnQgfCBudWxsKSA9PiBib29sZWFuO1xuZXhwb3J0IGRlY2xhcmUgY29uc3QgY3JlYXRlQXBwTG9hZGVkRXZlbnQ6ICgpID0+IFVzZXJFdmVudDtcbmV4cG9ydCBkZWNsYXJlIGNvbnN0IGNyZWF0ZVZpc2l0VXNlckV2ZW50OiAoeyB2YXJpYW50SW5mbywgfToge1xuICAgIHZhcmlhbnRJbmZvOiBWYXJpYW50SW5mbztcbn0pID0+IFVzZXJFdmVudCB8IHVuZGVmaW5lZDtcbmV4cG9ydCBkZWNsYXJlIGNvbnN0IGlzV2l0aGluQnVzaW5lc3NIb3VyczogKHN0YXJ0VGltZTogc3RyaW5nLCBlbmRUaW1lOiBzdHJpbmcsIHRpbWVab25lOiBzdHJpbmcpID0+IGJvb2xlYW47XG5leHBvcnQgZGVjbGFyZSBlbnVtIFNlYXJjaFJlc3VsdHNTdGF0ZSB7XG4gICAgTG9hZGluZyA9IDAsXG4gICAgUmVzdWx0cyA9IDEsXG4gICAgTm9SZXN1bHRzID0gMlxufVxuZXhwb3J0IGRlY2xhcmUgY29uc3QgZ2V0U2VhcmNoUmVzdWx0c1N0YXRlOiAoaXNMb2FkaW5nU2VhcmNoOiBib29sZWFuLCBzZWFyY2hEYXRhOiBTZWFyY2hSZXN1bHQgfCBudWxsKSA9PiBTZWFyY2hSZXN1bHRzU3RhdGU7XG4iXSwibWFwcGluZ3MiOiI7Ozs7O0FBRUEsSUFBVyw0QkFBNEIsQ0FBQyxVQUFVLGVBQWU7QUFDakUsSUFBVyx1QkFBdUIsQ0FBQyxVQUFVLFVBQVU7QUFDdkQsSUFBVyx1QkFBdUI7Q0FBQztPQUFVO09BQWlCO09BQUE7Q0FBQTtBQUM5RCxJQUFXLHdCQUFpQixDQUFBLEdBQUE7QUFDNUIsSUFBVyxxQkFBZ0IsQ0FBQSxHQUFBO0FBQzNCLElBQVcsd0JBQXdCO0NBQUM7T0FBVTtPQUFvQjtDQUFtQiJ9
22
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuZC50cyIsIm5hbWVzIjpbXSwic291cmNlcyI6WyIuLi8uLi9zcmMvaG9va3MvdXRpbHMuZC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBTZWFyY2hSZXN1bHQgfSBmcm9tICdzcmMvYXBwbGljYXRpb24vbW9kZWxzL2FwaS9zZWFyY2gnO1xuaW1wb3J0IHsgVXNlckV2ZW50LCBWYXJpYW50SW5mbyB9IGZyb20gJ3NyYy9hcHBsaWNhdGlvbi9tb2RlbHMnO1xuZXhwb3J0IGRlY2xhcmUgY29uc3QgaXNFbGVtZW50UGFydGlhbGx5VmlzaWJsZTogKGVsPzogSFRNTERpdkVsZW1lbnQgfCBudWxsKSA9PiBib29sZWFuO1xuZXhwb3J0IGRlY2xhcmUgY29uc3QgY3JlYXRlQXBwTG9hZGVkRXZlbnQ6ICgpID0+IFVzZXJFdmVudDtcbmV4cG9ydCBkZWNsYXJlIGNvbnN0IGNyZWF0ZVZpc2l0VXNlckV2ZW50OiAoeyB2YXJpYW50SW5mbywgfToge1xuICAgIHZhcmlhbnRJbmZvOiBWYXJpYW50SW5mbztcbn0pID0+IFVzZXJFdmVudCB8IHVuZGVmaW5lZDtcbmV4cG9ydCBkZWNsYXJlIGNvbnN0IGlzV2l0aGluQnVzaW5lc3NIb3VyczogKHN0YXJ0VGltZTogc3RyaW5nLCBlbmRUaW1lOiBzdHJpbmcsIHRpbWVab25lOiBzdHJpbmcpID0+IGJvb2xlYW47XG5leHBvcnQgZGVjbGFyZSBlbnVtIFNlYXJjaFJlc3VsdHNTdGF0ZSB7XG4gICAgTG9hZGluZyA9IDAsXG4gICAgUmVzdWx0cyA9IDEsXG4gICAgTm9SZXN1bHRzID0gMlxufVxuZXhwb3J0IGRlY2xhcmUgY29uc3QgZ2V0U2VhcmNoUmVzdWx0c1N0YXRlOiAoaXNMb2FkaW5nU2VhcmNoOiBib29sZWFuLCBzZWFyY2hEYXRhOiBTZWFyY2hSZXN1bHQgfCBudWxsKSA9PiBTZWFyY2hSZXN1bHRzU3RhdGU7XG4iXSwibWFwcGluZ3MiOiI7Ozs7O0FBRUEsSUFBVyw0QkFBNEIsQ0FBQyxTQUFTLGVBQWU7QUFDaEUsSUFBVyx1QkFBdUIsQ0FBQyxTQUFTLFVBQVU7QUFDdEQsSUFBVyx1QkFBdUI7Q0FBQztPQUFTO09BQWtCO09BQUE7Q0FBQTtBQUM5RCxJQUFXLHdCQUFpQixDQUFBLEVBQUE7QUFDNUIsSUFBVyxxQkFBZ0IsQ0FBQSxFQUFBO0FBQzNCLElBQVcsd0JBQXdCO0NBQUM7T0FBUztPQUFvQjtDQUFtQiJ9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envive-ai/react-hooks",
3
- "version": "0.3.19",
3
+ "version": "0.3.20",
4
4
  "description": "React hooks for connecting to Envive AI services.",
5
5
  "keywords": [
6
6
  "react",
@@ -342,6 +342,10 @@
342
342
  "import": "./dist/hooks/NewOrgConfig/index.js",
343
343
  "require": "./dist/hooks/NewOrgConfig/index.cjs"
344
344
  },
345
+ "./hooks/PageViewedEvent": {
346
+ "import": "./dist/hooks/PageViewedEvent/index.js",
347
+ "require": "./dist/hooks/PageViewedEvent/index.cjs"
348
+ },
345
349
  "./hooks/ProductImageUrl": {
346
350
  "import": "./dist/hooks/ProductImageUrl/index.js",
347
351
  "require": "./dist/hooks/ProductImageUrl/index.cjs"
@@ -1,4 +1,4 @@
1
- import { ReactNode, useEffect, useMemo, useState } from 'react';
1
+ import { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
2
 
3
3
  import { OrgConfigFeatureGate } from 'src/application/models/api/orgConfigResults';
4
4
  import { EnviveConfigService, EnviveServiceConfig } from 'src/services/enviveConfigService';
@@ -30,6 +30,12 @@ interface AgentWrapperProps {
30
30
  enabledAgents: EnviveAgent[];
31
31
  }
32
32
 
33
+ export interface ExtensionStatusCallbacks {
34
+ onInjectionLoading?: () => Promise<unknown> | void;
35
+ onInjectionSuccess?: () => Promise<unknown> | void;
36
+ onInjectionError?: (error: Error) => Promise<unknown> | void;
37
+ }
38
+
33
39
  interface EnviveProviderProps extends AgentWrapperProps {
34
40
  amplitudeApiKey?: string;
35
41
  dataResidency?: string;
@@ -58,6 +64,7 @@ interface EnviveProviderProps extends AgentWrapperProps {
58
64
  overrideConfig?: GraphQlConfigValues;
59
65
  mockSalesAgentData?: any;
60
66
  hardcopyOverride?: Partial<Record<WidgetTypeV3, HardcopyResponse>>;
67
+ extensionService?: ExtensionStatusCallbacks;
61
68
  }
62
69
 
63
70
  const SearchAgentWrapper: React.FC<AgentWrapperProps> = ({ children, enabledAgents }) => {
@@ -108,9 +115,34 @@ export const EnviveProvider: React.FC<EnviveProviderProps> = ({
108
115
  requestV3Config = false,
109
116
  mockSalesAgentData,
110
117
  hardcopyOverride,
118
+ extensionService,
111
119
  ...config
112
120
  }) => {
113
121
  const [userId, setUserId] = useState<string>('');
122
+ const didReportSuccessRef = useRef(false);
123
+
124
+ const invokeExtensionCallback = useCallback((callback?: () => Promise<unknown> | void) => {
125
+ if (!callback) {
126
+ return;
127
+ }
128
+
129
+ Promise.resolve(callback()).catch(error => {
130
+ logger.logDebug('Extension status callback failed', error);
131
+ });
132
+ }, []);
133
+
134
+ const invokeExtensionErrorCallback = useCallback(
135
+ (error: Error) => {
136
+ if (!extensionService?.onInjectionError) {
137
+ return;
138
+ }
139
+
140
+ Promise.resolve(extensionService.onInjectionError(error)).catch(callbackError => {
141
+ logger.logDebug('Extension error callback failed', callbackError);
142
+ });
143
+ },
144
+ [extensionService],
145
+ );
114
146
 
115
147
  const userIdService = useMemo(
116
148
  () =>
@@ -133,6 +165,8 @@ export const EnviveProvider: React.FC<EnviveProviderProps> = ({
133
165
  const [enviveServiceConfig, setEnviveServiceConfig] = useState<EnviveServiceConfig | null>(null);
134
166
 
135
167
  useEffect(() => {
168
+ invokeExtensionCallback(extensionService?.onInjectionLoading);
169
+
136
170
  // Really not happy with this approach, but I'm seeing 429 errors in the tests
137
171
  // because of the rate limiting on the API.
138
172
  const enviveConfigService =
@@ -144,11 +178,38 @@ export const EnviveProvider: React.FC<EnviveProviderProps> = ({
144
178
  namespace: namespace || '',
145
179
  source: source || '',
146
180
  });
147
- enviveConfigService.getEnviveConfig().then(newConfig => {
148
- setEnviveServiceConfig(newConfig);
149
- return newConfig;
150
- });
151
- }, [config, userId, namespace, source, inputEnviveConfigService]);
181
+ const fetchEnviveConfig = async () => {
182
+ try {
183
+ const newConfig = await enviveConfigService.getEnviveConfig();
184
+ setEnviveServiceConfig(newConfig);
185
+ } catch (error) {
186
+ const resolvedError =
187
+ error instanceof Error ? error : new Error('Failed to load envive config');
188
+ logger.logError('Failed to initialize EnviveProvider', resolvedError);
189
+ invokeExtensionErrorCallback(resolvedError);
190
+ }
191
+ };
192
+
193
+ fetchEnviveConfig();
194
+ }, [
195
+ config,
196
+ userId,
197
+ namespace,
198
+ source,
199
+ inputEnviveConfigService,
200
+ extensionService,
201
+ invokeExtensionCallback,
202
+ invokeExtensionErrorCallback,
203
+ ]);
204
+
205
+ useEffect(() => {
206
+ if (!enviveServiceConfig || didReportSuccessRef.current) {
207
+ return;
208
+ }
209
+
210
+ didReportSuccessRef.current = true;
211
+ invokeExtensionCallback(extensionService?.onInjectionSuccess);
212
+ }, [enviveServiceConfig, extensionService, invokeExtensionCallback]);
152
213
 
153
214
  const enviveConfig = useMemo(
154
215
  () => ({
@@ -182,7 +243,10 @@ export const EnviveProvider: React.FC<EnviveProviderProps> = ({
182
243
  <FeatureFlagServiceProvider featureFlagService={featureFlagService}>
183
244
  <UserIdentityProvider userIdService={userIdService}>
184
245
  <AmplitudeProvider externalAmplitudeService={inputAmplitudeService}>
185
- <PageProvider previewMode={previewMode}>
246
+ <PageProvider
247
+ previewMode={previewMode}
248
+ onUrlResolverNotReady={extensionService?.onInjectionError}
249
+ >
186
250
  <WidgetConfigProvider>
187
251
  <HardcopyProvider hardcopyOverride={hardcopyOverride}>
188
252
  <EnviveCssProvider>
@@ -27,6 +27,12 @@ vi.mock('src/application/commerce-api', () => ({
27
27
  },
28
28
  }));
29
29
 
30
+ // Mock useAmplitude (PageProvider dispatches page viewed event internally)
31
+ vi.mock('src/contexts/amplitudeContext', () => ({
32
+ EnviveMetricsEventName: { PageViewed: 'Page Viewed' },
33
+ useAmplitude: () => ({ trackEvent: vi.fn() }),
34
+ }));
35
+
30
36
  // Component that uses the usePage hook
31
37
  const MockComponent: React.FC = () => {
32
38
  const context = usePage();
@@ -5,19 +5,23 @@ import {
5
5
  useContext,
6
6
  useEffect,
7
7
  useMemo,
8
+ useRef,
8
9
  useState,
9
10
  } from 'react';
10
11
  import {
11
12
  UrlResolverResponse,
13
+ hasParsedVariantInfoAtom,
12
14
  pageUserEventAtom,
13
15
  pageVariantInfoAtom,
14
16
  urlResolverAtom,
17
+ variantInfoAtom,
15
18
  } from 'src/atoms/app/variant';
16
- import { useAtom } from 'jotai';
19
+ import { useAtom, useAtomValue } from 'jotai';
17
20
  import CommerceApiClient from 'src/application/commerce-api';
18
21
  import Logger from 'src/application/logging/logger';
19
22
  import { PageVisitCategory, UserEventCategory } from '@spiffy-ai/commerce-api-client';
20
23
  import { VariantTypeEnum } from 'src/application/models';
24
+ import { EnviveMetricsEventName, useAmplitude } from 'src/contexts/amplitudeContext';
21
25
  import { mapApiUserEventToUserEvent, mapUrlResolverResponseToVariantInfo } from './mapping';
22
26
  import { PageDetails } from './types';
23
27
 
@@ -35,13 +39,17 @@ const PageContext = createContext<
35
39
  export const PageProvider: React.FC<{
36
40
  children: ReactNode;
37
41
  previewMode: boolean;
38
- }> = ({ children, previewMode = false }) => {
42
+ /** When URL resolver returns `ready: false`, invoked for extension/injection failure reporting. */
43
+ onUrlResolverNotReady?: (error: Error) => Promise<unknown> | void;
44
+ }> = ({ children, previewMode = false, onUrlResolverNotReady }) => {
39
45
  const [pageUrl, setPageUrl] = useState<string | undefined>(undefined);
40
46
  const [urlResolverResponse, setUrlResolverResponse] = useAtom(urlResolverAtom);
41
47
  const [isLoading, setIsLoading] = useState(false);
42
48
  const [variantInfo, setVariantInfo] = useAtom(pageVariantInfoAtom);
43
49
  const [userEvent, setUserEvent] = useAtom(pageUserEventAtom);
44
50
  const [isSupported, setIsSupported] = useState(false);
51
+ const lastNotReadyUrlRef = useRef<string | null>(null);
52
+
45
53
  useEffect(() => {
46
54
  setPageUrl(window.location.href);
47
55
  }, []);
@@ -72,11 +80,13 @@ export const PageProvider: React.FC<{
72
80
  if (response.ready) {
73
81
  const newVariantInfo = mapUrlResolverResponseToVariantInfo(url, response);
74
82
  const newUserEvent = mapApiUserEventToUserEvent(response.user_event ?? undefined);
83
+ logger.logDebug('setting variant info and user event', { newVariantInfo, newUserEvent });
75
84
  setVariantInfo(newVariantInfo);
76
85
  setUserEvent(newUserEvent);
77
86
  } else {
78
87
  setUserEvent(undefined);
79
88
  setVariantInfo(undefined);
89
+ logger.logDebug('set variant info and user event to undefined', { variantInfo, userEvent });
80
90
  }
81
91
  },
82
92
  [setVariantInfo, setUserEvent],
@@ -104,6 +114,16 @@ export const PageProvider: React.FC<{
104
114
  setVariantFromUrlResolver(cleansedUrl, response);
105
115
  setIsLoading(false);
106
116
  setIsSupported(response.ready);
117
+
118
+ if (response.ready) {
119
+ lastNotReadyUrlRef.current = null;
120
+ } else if (onUrlResolverNotReady && lastNotReadyUrlRef.current !== cleansedUrl) {
121
+ lastNotReadyUrlRef.current = cleansedUrl;
122
+ const err = new Error(`URL resolver returned ready=false for ${cleansedUrl}`);
123
+ Promise.resolve(onUrlResolverNotReady(err)).catch(callbackError => {
124
+ logger.logDebug('onUrlResolverNotReady callback failed', callbackError);
125
+ });
126
+ }
107
127
  } catch (e) {
108
128
  setIsLoading(false);
109
129
  logger.logError('Failed to resolve page URL', e, { pageUrl });
@@ -118,8 +138,65 @@ export const PageProvider: React.FC<{
118
138
  userEvent,
119
139
  variantInfo,
120
140
  previewMode,
141
+ onUrlResolverNotReady,
121
142
  ]);
122
143
 
144
+ const { trackEvent } = useAmplitude();
145
+ const resolvedVariantInfo = useAtomValue(variantInfoAtom);
146
+ const hasParsedVariantInfo = useAtomValue(hasParsedVariantInfoAtom);
147
+ const pageViewedFired = useRef(false);
148
+
149
+ useEffect(() => {
150
+ if (pageViewedFired.current || isLoading || !hasParsedVariantInfo || !variantInfo) {
151
+ return;
152
+ }
153
+
154
+ let pageType: string;
155
+ let pageId: string;
156
+
157
+ switch (variantInfo.variantType) {
158
+ case VariantTypeEnum.Pdp:
159
+ pageType = 'pdp';
160
+ pageId = variantInfo.productId;
161
+ break;
162
+ case VariantTypeEnum.Plp:
163
+ pageType = 'plp';
164
+ pageId = variantInfo.plpId;
165
+ break;
166
+ case VariantTypeEnum.Home:
167
+ pageType = 'homepage';
168
+ pageId = variantInfo.url;
169
+ break;
170
+ case VariantTypeEnum.Other:
171
+ pageType = 'other';
172
+ pageId = variantInfo.url;
173
+ break;
174
+ case VariantTypeEnum.PageVisit:
175
+ pageType = 'other';
176
+ pageId = variantInfo.url;
177
+ break;
178
+ case VariantTypeEnum.FullPageSalesAgent:
179
+ pageType = 'full_page_sales_agent';
180
+ pageId = variantInfo.url;
181
+ break;
182
+ default:
183
+ return;
184
+ }
185
+
186
+ pageViewedFired.current = true;
187
+
188
+ trackEvent({
189
+ eventName: EnviveMetricsEventName.PageViewed,
190
+ eventProps: {
191
+ 'context.page_type': pageType,
192
+ 'context.page_id': pageId,
193
+ 'context.supported': isSupported,
194
+ 'context.ready': isSupported,
195
+ 'context.page_variant_id': resolvedVariantInfo.variantId,
196
+ },
197
+ });
198
+ }, [isLoading, isSupported, hasParsedVariantInfo, variantInfo, resolvedVariantInfo, trackEvent]);
199
+
123
200
  const setPageUrlStable = useCallback((url: string) => {
124
201
  setPageUrl(url);
125
202
  }, []);