@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,297 @@
1
+ import { renderHook } from '@testing-library/react';
2
+ import { VariantTypeEnum } from 'src/application/models';
3
+ import { EnviveMetricsEventName } from 'src/contexts/amplitudeContext';
4
+ import {
5
+ FullPageSalesAgentVariantInfo,
6
+ HomeVariantInfo,
7
+ OtherVariantInfo,
8
+ PDPPageVariantInfo,
9
+ PLPPageVariantInfo,
10
+ PageVariantInfo,
11
+ VisitPageVariantInfo,
12
+ } from 'src/contexts/pageContext/types';
13
+ import { extractPageViewedContext, usePageViewedEvent } from '../usePageViewedEvent';
14
+
15
+ const mockTrackEvent = vi.fn();
16
+
17
+ vi.mock('src/contexts/amplitudeContext', async () => {
18
+ const actual = await vi.importActual('src/contexts/amplitudeContext');
19
+ return {
20
+ ...actual,
21
+ useAmplitude: () => ({
22
+ trackEvent: mockTrackEvent,
23
+ }),
24
+ };
25
+ });
26
+
27
+ const mockUsePage = vi.fn();
28
+ vi.mock('src/contexts/pageContext', () => ({
29
+ usePage: () => mockUsePage(),
30
+ }));
31
+
32
+ const mockUseAtomValue = vi.fn();
33
+ vi.mock('jotai', async () => {
34
+ const actual = await vi.importActual('jotai');
35
+ return {
36
+ ...actual,
37
+ useAtomValue: () => mockUseAtomValue(),
38
+ };
39
+ });
40
+
41
+ describe('extractPageViewedContext', () => {
42
+ it('should return pdp context', () => {
43
+ const variant: PDPPageVariantInfo = {
44
+ variantType: VariantTypeEnum.Pdp,
45
+ productId: 'product-123',
46
+ collections: [],
47
+ numberOfReviews: 0,
48
+ merchantTags: [],
49
+ url: 'https://example.com/products/product-123',
50
+ };
51
+ expect(extractPageViewedContext(variant)).toEqual({
52
+ page_type: 'pdp',
53
+ page_id: 'product-123',
54
+ });
55
+ });
56
+
57
+ it('should return plp context', () => {
58
+ const variant: PLPPageVariantInfo = {
59
+ variantType: VariantTypeEnum.Plp,
60
+ plpId: 'collection-456',
61
+ topCategory: 'shoes',
62
+ url: 'https://example.com/collections/shoes',
63
+ };
64
+ expect(extractPageViewedContext(variant)).toEqual({
65
+ page_type: 'plp',
66
+ page_id: 'collection-456',
67
+ });
68
+ });
69
+
70
+ it('should return homepage context', () => {
71
+ const variant: HomeVariantInfo = {
72
+ variantType: VariantTypeEnum.Home,
73
+ url: 'https://example.com/',
74
+ };
75
+ expect(extractPageViewedContext(variant)).toEqual({
76
+ page_type: 'homepage',
77
+ page_id: 'https://example.com/',
78
+ });
79
+ });
80
+
81
+ it('should return other context for Other variant', () => {
82
+ const variant: OtherVariantInfo = {
83
+ variantType: VariantTypeEnum.Other,
84
+ url: 'https://example.com/about',
85
+ };
86
+ expect(extractPageViewedContext(variant)).toEqual({
87
+ page_type: 'other',
88
+ page_id: 'https://example.com/about',
89
+ });
90
+ });
91
+
92
+ it('should return other context for PageVisit variant', () => {
93
+ const variant: VisitPageVariantInfo = {
94
+ variantType: VariantTypeEnum.PageVisit,
95
+ url: 'https://example.com/contact',
96
+ };
97
+ expect(extractPageViewedContext(variant)).toEqual({
98
+ page_type: 'other',
99
+ page_id: 'https://example.com/contact',
100
+ });
101
+ });
102
+
103
+ it('should return full_page_sales_agent context', () => {
104
+ const variant: FullPageSalesAgentVariantInfo = {
105
+ variantType: VariantTypeEnum.FullPageSalesAgent,
106
+ url: 'https://example.com/agent',
107
+ };
108
+ expect(extractPageViewedContext(variant)).toEqual({
109
+ page_type: 'full_page_sales_agent',
110
+ page_id: 'https://example.com/agent',
111
+ });
112
+ });
113
+
114
+ it('should return null for unknown variant type', () => {
115
+ const variant = { variantType: 'unknown' } as unknown as PageVariantInfo;
116
+ expect(extractPageViewedContext(variant)).toBeNull();
117
+ });
118
+ });
119
+
120
+ describe('usePageViewedEvent', () => {
121
+ beforeEach(() => {
122
+ vi.clearAllMocks();
123
+ });
124
+
125
+ it('should not fire when still loading', () => {
126
+ mockUsePage.mockReturnValue({
127
+ variantInfo: {
128
+ variantType: VariantTypeEnum.Pdp,
129
+ productId: 'p1',
130
+ collections: [],
131
+ numberOfReviews: 0,
132
+ merchantTags: [],
133
+ url: '',
134
+ },
135
+ isSupported: true,
136
+ isLoading: true,
137
+ });
138
+ mockUseAtomValue
139
+ .mockReturnValueOnce({ variantId: 'v1', variant: 'pdp' })
140
+ .mockReturnValueOnce(true);
141
+
142
+ renderHook(() => usePageViewedEvent());
143
+ expect(mockTrackEvent).not.toHaveBeenCalled();
144
+ });
145
+
146
+ it('should not fire when hasParsedVariantInfo is false', () => {
147
+ mockUsePage.mockReturnValue({
148
+ variantInfo: {
149
+ variantType: VariantTypeEnum.Pdp,
150
+ productId: 'p1',
151
+ collections: [],
152
+ numberOfReviews: 0,
153
+ merchantTags: [],
154
+ url: '',
155
+ },
156
+ isSupported: true,
157
+ isLoading: false,
158
+ });
159
+ mockUseAtomValue
160
+ .mockReturnValueOnce({ variantId: 'v1', variant: 'pdp' })
161
+ .mockReturnValueOnce(false);
162
+
163
+ renderHook(() => usePageViewedEvent());
164
+ expect(mockTrackEvent).not.toHaveBeenCalled();
165
+ });
166
+
167
+ it('should not fire when pageVariantInfo is undefined', () => {
168
+ mockUsePage.mockReturnValue({
169
+ variantInfo: undefined,
170
+ isSupported: false,
171
+ isLoading: false,
172
+ });
173
+ mockUseAtomValue
174
+ .mockReturnValueOnce({ variantId: 'v1', variant: 'pdp' })
175
+ .mockReturnValueOnce(true);
176
+
177
+ renderHook(() => usePageViewedEvent());
178
+ expect(mockTrackEvent).not.toHaveBeenCalled();
179
+ });
180
+
181
+ it('should fire with correct props for pdp page', () => {
182
+ mockUsePage.mockReturnValue({
183
+ variantInfo: {
184
+ variantType: VariantTypeEnum.Pdp,
185
+ productId: 'product-123',
186
+ collections: [],
187
+ numberOfReviews: 5,
188
+ merchantTags: [],
189
+ url: 'https://example.com/products/product-123',
190
+ },
191
+ isSupported: true,
192
+ isLoading: false,
193
+ });
194
+ mockUseAtomValue
195
+ .mockReturnValueOnce({ variantId: 'variant-A', variant: 'pdp' })
196
+ .mockReturnValueOnce(true);
197
+
198
+ renderHook(() => usePageViewedEvent());
199
+
200
+ expect(mockTrackEvent).toHaveBeenCalledTimes(1);
201
+ expect(mockTrackEvent).toHaveBeenCalledWith({
202
+ eventName: EnviveMetricsEventName.PageViewed,
203
+ eventProps: {
204
+ 'context.page_type': 'pdp',
205
+ 'context.page_id': 'product-123',
206
+ 'context.supported': true,
207
+ 'context.ready': true,
208
+ 'context.page_variant_id': 'variant-A',
209
+ },
210
+ });
211
+ });
212
+
213
+ it('should fire only once even if dependencies change', () => {
214
+ mockUsePage.mockReturnValue({
215
+ variantInfo: {
216
+ variantType: VariantTypeEnum.Pdp,
217
+ productId: 'product-123',
218
+ collections: [],
219
+ numberOfReviews: 0,
220
+ merchantTags: [],
221
+ url: '',
222
+ },
223
+ isSupported: true,
224
+ isLoading: false,
225
+ });
226
+ mockUseAtomValue
227
+ .mockReturnValueOnce({ variantId: 'v1', variant: 'pdp' })
228
+ .mockReturnValueOnce(true);
229
+
230
+ const { rerender } = renderHook(() => usePageViewedEvent());
231
+
232
+ mockUseAtomValue
233
+ .mockReturnValueOnce({ variantId: 'v1', variant: 'pdp' })
234
+ .mockReturnValueOnce(true);
235
+
236
+ rerender();
237
+
238
+ expect(mockTrackEvent).toHaveBeenCalledTimes(1);
239
+ });
240
+
241
+ it('should fire with full_page_sales_agent page type', () => {
242
+ mockUsePage.mockReturnValue({
243
+ variantInfo: {
244
+ variantType: VariantTypeEnum.FullPageSalesAgent,
245
+ url: 'https://example.com/agent',
246
+ },
247
+ isSupported: true,
248
+ isLoading: false,
249
+ });
250
+ mockUseAtomValue
251
+ .mockReturnValueOnce({ variantId: 'fpsa-variant', variant: 'full_page' })
252
+ .mockReturnValueOnce(true);
253
+
254
+ renderHook(() => usePageViewedEvent());
255
+
256
+ expect(mockTrackEvent).toHaveBeenCalledTimes(1);
257
+ expect(mockTrackEvent).toHaveBeenCalledWith({
258
+ eventName: EnviveMetricsEventName.PageViewed,
259
+ eventProps: {
260
+ 'context.page_type': 'full_page_sales_agent',
261
+ 'context.page_id': 'https://example.com/agent',
262
+ 'context.supported': true,
263
+ 'context.ready': true,
264
+ 'context.page_variant_id': 'fpsa-variant',
265
+ },
266
+ });
267
+ });
268
+
269
+ it('should set supported and ready to false when isSupported is false', () => {
270
+ mockUsePage.mockReturnValue({
271
+ variantInfo: {
272
+ variantType: VariantTypeEnum.Pdp,
273
+ productId: 'product-456',
274
+ collections: [],
275
+ numberOfReviews: 0,
276
+ merchantTags: [],
277
+ url: '',
278
+ },
279
+ isSupported: false,
280
+ isLoading: false,
281
+ });
282
+ mockUseAtomValue
283
+ .mockReturnValueOnce({ variantId: 'v2', variant: 'pdp' })
284
+ .mockReturnValueOnce(true);
285
+
286
+ renderHook(() => usePageViewedEvent());
287
+
288
+ expect(mockTrackEvent).toHaveBeenCalledWith(
289
+ expect.objectContaining({
290
+ eventProps: expect.objectContaining({
291
+ 'context.supported': false,
292
+ 'context.ready': false,
293
+ }),
294
+ }),
295
+ );
296
+ });
297
+ });
@@ -0,0 +1 @@
1
+ export * from './usePageViewedEvent';
@@ -0,0 +1,103 @@
1
+ import { useAtomValue } from 'jotai';
2
+ import { useEffect, useRef } from 'react';
3
+ import { VariantTypeEnum } from 'src/application/models';
4
+ import { hasParsedVariantInfoAtom, variantInfoAtom } from 'src/atoms/app/variant';
5
+ import { EnviveMetricsEventName, useAmplitude } from 'src/contexts/amplitudeContext';
6
+ import { usePage } from 'src/contexts/pageContext';
7
+ import {
8
+ FullPageSalesAgentVariantInfo,
9
+ HomeVariantInfo,
10
+ OtherVariantInfo,
11
+ PDPPageVariantInfo,
12
+ PLPPageVariantInfo,
13
+ PageVariantInfo,
14
+ VisitPageVariantInfo,
15
+ } from 'src/contexts/pageContext/types';
16
+
17
+ interface PageViewedContext {
18
+ page_type: string;
19
+ page_id: string;
20
+ }
21
+
22
+ export const extractPageViewedContext = (
23
+ pageVariant: PageVariantInfo,
24
+ ): PageViewedContext | null => {
25
+ switch (pageVariant.variantType) {
26
+ case VariantTypeEnum.Pdp:
27
+ return {
28
+ page_type: 'pdp',
29
+ page_id: (pageVariant as PDPPageVariantInfo).productId,
30
+ };
31
+ case VariantTypeEnum.Plp:
32
+ return {
33
+ page_type: 'plp',
34
+ page_id: (pageVariant as PLPPageVariantInfo).plpId,
35
+ };
36
+ case VariantTypeEnum.Home:
37
+ return {
38
+ page_type: 'homepage',
39
+ page_id: (pageVariant as HomeVariantInfo).url,
40
+ };
41
+ case VariantTypeEnum.Other:
42
+ return {
43
+ page_type: 'other',
44
+ page_id: (pageVariant as OtherVariantInfo).url,
45
+ };
46
+ case VariantTypeEnum.PageVisit:
47
+ return {
48
+ page_type: 'other',
49
+ page_id: (pageVariant as VisitPageVariantInfo).url,
50
+ };
51
+ case VariantTypeEnum.FullPageSalesAgent:
52
+ return {
53
+ page_type: 'full_page_sales_agent',
54
+ page_id: (pageVariant as FullPageSalesAgentVariantInfo).url,
55
+ };
56
+ default:
57
+ return null;
58
+ }
59
+ };
60
+
61
+ /**
62
+ * Fires the [Envive] Page Viewed event once per page load when page context data is ready.
63
+ *
64
+ * This event captures page context information and is intended to eventually replace
65
+ * the [Amplitude] Page Viewed event.
66
+ */
67
+ export const usePageViewedEvent = () => {
68
+ const hasFired = useRef(false);
69
+ const { trackEvent } = useAmplitude();
70
+ const { variantInfo: pageVariantInfo, isSupported, isLoading } = usePage();
71
+ const variantInfo = useAtomValue(variantInfoAtom);
72
+ const hasParsedVariantInfo = useAtomValue(hasParsedVariantInfoAtom);
73
+
74
+ useEffect(() => {
75
+ if (hasFired.current) {
76
+ return;
77
+ }
78
+
79
+ if (isLoading || !hasParsedVariantInfo || !pageVariantInfo) {
80
+ return;
81
+ }
82
+
83
+ const pageContext = extractPageViewedContext(pageVariantInfo);
84
+ if (!pageContext) {
85
+ return;
86
+ }
87
+
88
+ hasFired.current = true;
89
+
90
+ trackEvent({
91
+ eventName: EnviveMetricsEventName.PageViewed,
92
+ eventProps: {
93
+ 'context.page_type': pageContext.page_type,
94
+ 'context.page_id': pageContext.page_id,
95
+ // context.supported and context.ready both derive from isSupported (response.ready)
96
+ // because the supportedEventAtom is not currently populated.
97
+ 'context.supported': isSupported,
98
+ 'context.ready': isSupported,
99
+ 'context.page_variant_id': variantInfo.variantId,
100
+ },
101
+ });
102
+ }, [isLoading, isSupported, hasParsedVariantInfo, pageVariantInfo, variantInfo, trackEvent]);
103
+ };