@envive-ai/react-hooks 0.3.22 → 0.3.24

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 (84) hide show
  1. package/dist/application/models/featureGates.cjs +2 -1
  2. package/dist/application/models/featureGates.d.cts +2 -1
  3. package/dist/application/models/featureGates.d.ts +2 -1
  4. package/dist/application/models/featureGates.js +2 -1
  5. package/dist/atoms/app/index.d.ts +7 -7
  6. package/dist/atoms/app/variant.d.cts +6 -6
  7. package/dist/atoms/app/variant.d.ts +6 -6
  8. package/dist/atoms/chat/chatState.cjs +3 -1
  9. package/dist/atoms/chat/chatState.d.cts +22 -19
  10. package/dist/atoms/chat/chatState.d.ts +22 -19
  11. package/dist/atoms/chat/chatState.js +3 -2
  12. package/dist/atoms/chat/form.d.cts +3 -3
  13. package/dist/atoms/chat/form.d.ts +2 -2
  14. package/dist/atoms/chat/index.cjs +1 -0
  15. package/dist/atoms/chat/index.d.cts +2 -2
  16. package/dist/atoms/chat/index.d.ts +4 -4
  17. package/dist/atoms/chat/index.js +2 -2
  18. package/dist/atoms/chat/lastMessage.d.ts +2 -2
  19. package/dist/atoms/chat/messageQueue.d.cts +6 -6
  20. package/dist/atoms/chat/messageQueue.d.ts +6 -6
  21. package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
  22. package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
  23. package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
  24. package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
  25. package/dist/atoms/chat/replies.d.cts +3 -3
  26. package/dist/atoms/chat/replies.d.ts +2 -2
  27. package/dist/atoms/chat/suggestions.d.cts +2 -2
  28. package/dist/atoms/chat/suggestions.d.ts +2 -2
  29. package/dist/atoms/envive/enviveConfig.d.cts +13 -13
  30. package/dist/atoms/envive/enviveConfig.d.ts +13 -13
  31. package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
  32. package/dist/atoms/globalSearch/globalSearch.d.ts +5 -5
  33. package/dist/atoms/org/customerService.d.cts +6 -6
  34. package/dist/atoms/org/customerService.d.ts +6 -6
  35. package/dist/atoms/org/graphqlConfig.d.cts +4 -4
  36. package/dist/atoms/org/graphqlConfig.d.ts +4 -4
  37. package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
  38. package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
  39. package/dist/atoms/org/orgAnalyticsConfig.d.cts +5 -5
  40. package/dist/atoms/org/orgAnalyticsConfig.d.ts +5 -5
  41. package/dist/atoms/search/chatSearch.d.cts +17 -17
  42. package/dist/atoms/search/chatSearch.d.ts +17 -17
  43. package/dist/atoms/search/searchAPI.d.cts +13 -13
  44. package/dist/atoms/search/searchAPI.d.ts +13 -13
  45. package/dist/atoms/search/types.d.cts +1 -1
  46. package/dist/atoms/widget/chatPreviewLoading.d.cts +2 -2
  47. package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
  48. package/dist/contexts/graphqlContext/graphqlContext.cjs +4 -4
  49. package/dist/contexts/graphqlContext/graphqlContext.js +4 -4
  50. package/dist/contexts/hardcopyContext/hardcopyContext.cjs +5 -3
  51. package/dist/contexts/hardcopyContext/hardcopyContext.js +5 -3
  52. package/dist/contexts/salesAgentContext/chatAPI.cjs +12 -5
  53. package/dist/contexts/salesAgentContext/chatAPI.js +13 -6
  54. package/dist/contexts/systemSettingsContext/systemSettingsContext.d.ts +2 -2
  55. package/dist/contexts/types.d.cts +1 -1
  56. package/dist/contexts/types.d.ts +1 -1
  57. package/dist/contexts/typesV3.cjs +1 -1
  58. package/dist/contexts/typesV3.d.cts +2 -1
  59. package/dist/contexts/typesV3.d.ts +2 -1
  60. package/dist/contexts/typesV3.js +1 -1
  61. package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.ts +2 -2
  62. package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.cjs +8 -2
  63. package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.js +8 -2
  64. package/dist/hooks/WidgetInteraction/types.cjs +6 -2
  65. package/dist/hooks/WidgetInteraction/types.d.cts +8 -3
  66. package/dist/hooks/WidgetInteraction/types.d.ts +8 -3
  67. package/dist/hooks/WidgetInteraction/types.js +6 -2
  68. package/dist/hooks/utils.d.ts +1 -1
  69. package/dist/services/ga4ProjectionService/ga4EventSchema.cjs +31 -27
  70. package/dist/services/ga4ProjectionService/ga4EventSchema.js +31 -27
  71. package/dist/services/ga4ProjectionService/ga4ProjectionService.cjs +31 -5
  72. package/dist/services/ga4ProjectionService/ga4ProjectionService.js +31 -5
  73. package/package.json +1 -1
  74. package/src/application/models/featureGates.ts +1 -0
  75. package/src/atoms/chat/chatState.ts +1 -0
  76. package/src/contexts/graphqlContext/graphqlContext.tsx +6 -8
  77. package/src/contexts/hardcopyContext/hardcopyContext.tsx +10 -2
  78. package/src/contexts/salesAgentContext/chatAPI.ts +6 -2
  79. package/src/contexts/typesV3.ts +1 -0
  80. package/src/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.ts +10 -2
  81. package/src/hooks/WidgetInteraction/types.ts +10 -1
  82. package/src/services/ga4ProjectionService/__tests__/ga4ProjectionService.test.ts +110 -49
  83. package/src/services/ga4ProjectionService/ga4EventSchema.ts +35 -27
  84. package/src/services/ga4ProjectionService/ga4ProjectionService.ts +60 -6
@@ -34,6 +34,11 @@ export type WidgetInteractionDataProjection = Record<string, Record<string, stri
34
34
  export interface GA4ProjectedEventConfig {
35
35
  gaEventName: string;
36
36
  allowedFields: readonly string[];
37
+ /**
38
+ * When present, used instead of `allowedFields` to both filter and rename fields.
39
+ * Key: the desired GA4 parameter name. Value: the source dot-notation key in eventProps.
40
+ */
41
+ fieldProjections?: Record<string, string>;
37
42
  widgetInteractionDataProjections?: WidgetInteractionDataProjection;
38
43
  }
39
44
 
@@ -44,34 +49,36 @@ export interface GA4ExcludedEventConfig {
44
49
  export type GA4EventSchemaEntry = GA4ProjectedEventConfig | GA4ExcludedEventConfig;
45
50
 
46
51
  const WIDGET_INTERACTION_DATA_PROJECTIONS: WidgetInteractionDataProjection = {
47
- widget_collapsed: { trigger_collapse_source: 'collapse_source' },
48
- product_card_clicked: { trigger_product_id: 'product_id' },
49
- suggestion_scrolled: { trigger_suggestion_id: 'suggestion_id' },
52
+ widget_collapsed: { interaction_collapse_source: 'widget_collapsed.collapse_source' },
53
+ product_card_clicked: { interaction_product_id: 'product_card_clicked.product_id' },
54
+ suggestion_scrolled: { interaction_suggestion_id: 'suggestion_scrolled.suggestion_id' },
50
55
  };
51
56
 
52
57
  export const GA4_EVENT_SCHEMA: Record<EnviveMetricsEventName, GA4EventSchemaEntry> = {
53
58
  [EnviveMetricsEventName.WidgetRendered]: {
54
59
  gaEventName: 'envive_widget_rendered',
55
- allowedFields: [
56
- 'context.page_type',
57
- 'context.page_id',
58
- 'trigger.widget',
59
- 'trigger.widget_role',
60
- 'context.surface',
61
- ],
60
+ allowedFields: [],
61
+ fieldProjections: {
62
+ page_type: 'context.page_type',
63
+ page_id: 'context.page_id',
64
+ surface: 'context.surface',
65
+ widget: 'trigger.widget',
66
+ widget_role: 'trigger.widget_role',
67
+ },
62
68
  },
63
69
 
64
- // This event is not currently implemented
65
70
  [EnviveMetricsEventName.WidgetInteraction]: {
66
71
  gaEventName: 'envive_widget_interaction',
67
- allowedFields: [
68
- 'context.page_type',
69
- 'context.page_id',
70
- 'trigger.widget',
71
- 'trigger.widget_interaction',
72
- 'trigger.entity_role',
73
- 'context.surface',
74
- ],
72
+ allowedFields: [],
73
+ fieldProjections: {
74
+ page_type: 'context.page_type',
75
+ page_id: 'context.page_id',
76
+ surface: 'context.surface',
77
+ widget: 'trigger.widget',
78
+ interaction_type: 'trigger.widget_interaction',
79
+ interaction_class: 'trigger.interaction_class',
80
+ widget_role: 'trigger.widget_role',
81
+ },
75
82
  widgetInteractionDataProjections: WIDGET_INTERACTION_DATA_PROJECTIONS,
76
83
  },
77
84
 
@@ -120,14 +127,15 @@ export const GA4_EVENT_SCHEMA: Record<EnviveMetricsEventName, GA4EventSchemaEntr
120
127
  // This event is not currently implemented
121
128
  [EnviveMetricsEventName.PageViewed]: {
122
129
  gaEventName: 'envive_page_context_evaluated',
123
- allowedFields: [
124
- 'context.page_type',
125
- 'context.page_id',
126
- 'context.supported',
127
- 'context.ready',
128
- 'context.page_variant_id',
129
- 'environment.envive_enabled',
130
- ],
130
+ allowedFields: [],
131
+ fieldProjections: {
132
+ page_type: 'context.page_type',
133
+ page_id: 'context.page_id',
134
+ context_supported: 'context.supported',
135
+ context_ready: 'context.ready',
136
+ context_page_variant_id: 'context.page_variant_id',
137
+ environment_envive_enabled: 'environment.envive_enabled',
138
+ },
131
139
  },
132
140
 
133
141
  [EnviveMetricsEventName.WidgetTextRequest]: {
@@ -17,6 +17,42 @@ const filterToSchema = (
17
17
  return result;
18
18
  };
19
19
 
20
+ // Flatten only true top-level nested objects (keys with no dots) one level deep.
21
+ // Keys that already contain dots are left intact so that e.g.
22
+ // `trigger.widget_interaction_data: { ... }` is preserved for downstream extraction.
23
+ const flattenOneLevel = (obj: Record<string, unknown>): Record<string, unknown> => {
24
+ const result: Record<string, unknown> = {};
25
+ for (const [key, value] of Object.entries(obj)) {
26
+ if (
27
+ !key.includes('.') &&
28
+ value !== null &&
29
+ typeof value === 'object' &&
30
+ !Array.isArray(value)
31
+ ) {
32
+ for (const [subKey, subValue] of Object.entries(value as Record<string, unknown>)) {
33
+ result[`${key}.${subKey}`] = subValue;
34
+ }
35
+ } else {
36
+ result[key] = value;
37
+ }
38
+ }
39
+ return result;
40
+ };
41
+
42
+ // Apply a GA4 projection map { ga4Key: sourceKey } to extract and rename fields.
43
+ const filterWithProjections = (
44
+ eventProps: Record<string, unknown>,
45
+ projections: Record<string, string>,
46
+ ): Record<string, unknown> => {
47
+ const result: Record<string, unknown> = {};
48
+ for (const [ga4Key, sourceKey] of Object.entries(projections)) {
49
+ if (sourceKey in eventProps) {
50
+ result[ga4Key] = eventProps[sourceKey];
51
+ }
52
+ }
53
+ return result;
54
+ };
55
+
20
56
  // "context.page_type" → "context_page_type"
21
57
  const flattenDotKeys = (obj: Record<string, unknown>): Record<string, unknown> => {
22
58
  const result: Record<string, unknown> = {};
@@ -32,16 +68,28 @@ const flattenDotKeys = (obj: Record<string, unknown>): Record<string, unknown> =
32
68
  // Search: search query
33
69
  // Other: page url
34
70
  // We want to omit all but pdp and plp page types to provide a clear, consistent interface for merchants.
71
+ // Handles both dot-notation keys (allowedFields path) and renamed GA4 keys (fieldProjections path).
35
72
  const sanitizePageId = (filtered: Record<string, unknown>): Record<string, unknown> => {
36
- const pageType = filtered['context.page_type'];
73
+ const pageType = filtered['page_type'] ?? filtered['context.page_type'];
37
74
  if (pageType === 'pdp' || pageType === 'plp') {
38
75
  return filtered;
39
76
  }
40
77
  const rest = { ...filtered };
78
+ delete rest['page_id'];
41
79
  delete rest['context.page_id'];
42
80
  return rest;
43
81
  };
44
82
 
83
+ const getNestedValue = (obj: Record<string, unknown>, path: string): unknown => {
84
+ const parts = path.split('.');
85
+ let current: unknown = obj;
86
+ for (const part of parts) {
87
+ if (current === null || typeof current !== 'object') return undefined;
88
+ current = (current as Record<string, unknown>)[part];
89
+ }
90
+ return current;
91
+ };
92
+
45
93
  // Extract whitelisted sub-fields from trigger.widget_interaction_data
46
94
  const projectWidgetInteractionData = (
47
95
  eventProps: Record<string, unknown>,
@@ -72,9 +120,10 @@ const projectWidgetInteractionData = (
72
120
 
73
121
  const data = interactionData as Record<string, unknown>;
74
122
  const result: Record<string, unknown> = {};
75
- for (const [gaKey, sourceField] of Object.entries(projectionMap)) {
76
- if (sourceField in data) {
77
- result[gaKey] = data[sourceField];
123
+ for (const [gaKey, sourcePath] of Object.entries(projectionMap)) {
124
+ const value = getNestedValue(data, sourcePath);
125
+ if (value !== undefined) {
126
+ result[gaKey] = value;
78
127
  }
79
128
  }
80
129
  return result;
@@ -113,9 +162,14 @@ export const projectToGA4 = (
113
162
  }
114
163
 
115
164
  const config = schemaEntry;
116
- const props = eventProps ?? {};
165
+ const props = flattenOneLevel(eventProps ?? {});
117
166
 
118
- let filtered = filterToSchema(props, config.allowedFields);
167
+ let filtered: Record<string, unknown>;
168
+ if (config.fieldProjections) {
169
+ filtered = filterWithProjections(props, config.fieldProjections);
170
+ } else {
171
+ filtered = filterToSchema(props, config.allowedFields);
172
+ }
119
173
  filtered = sanitizePageId(filtered);
120
174
 
121
175
  const interactionFields = projectWidgetInteractionData(props, config);