@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.
- package/dist/application/models/featureGates.cjs +2 -1
- package/dist/application/models/featureGates.d.cts +2 -1
- package/dist/application/models/featureGates.d.ts +2 -1
- package/dist/application/models/featureGates.js +2 -1
- package/dist/atoms/app/index.d.ts +7 -7
- package/dist/atoms/app/variant.d.cts +6 -6
- package/dist/atoms/app/variant.d.ts +6 -6
- package/dist/atoms/chat/chatState.cjs +3 -1
- package/dist/atoms/chat/chatState.d.cts +22 -19
- package/dist/atoms/chat/chatState.d.ts +22 -19
- package/dist/atoms/chat/chatState.js +3 -2
- package/dist/atoms/chat/form.d.cts +3 -3
- package/dist/atoms/chat/form.d.ts +2 -2
- package/dist/atoms/chat/index.cjs +1 -0
- package/dist/atoms/chat/index.d.cts +2 -2
- package/dist/atoms/chat/index.d.ts +4 -4
- package/dist/atoms/chat/index.js +2 -2
- package/dist/atoms/chat/lastMessage.d.ts +2 -2
- package/dist/atoms/chat/messageQueue.d.cts +6 -6
- package/dist/atoms/chat/messageQueue.d.ts +6 -6
- package/dist/atoms/chat/performanceMetrics.d.cts +6 -6
- package/dist/atoms/chat/performanceMetrics.d.ts +6 -6
- package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
- package/dist/atoms/chat/renderedWidgetRefs.d.ts +2 -2
- package/dist/atoms/chat/replies.d.cts +3 -3
- package/dist/atoms/chat/replies.d.ts +2 -2
- package/dist/atoms/chat/suggestions.d.cts +2 -2
- package/dist/atoms/chat/suggestions.d.ts +2 -2
- package/dist/atoms/envive/enviveConfig.d.cts +13 -13
- package/dist/atoms/envive/enviveConfig.d.ts +13 -13
- package/dist/atoms/globalSearch/globalSearch.d.cts +5 -5
- package/dist/atoms/globalSearch/globalSearch.d.ts +5 -5
- package/dist/atoms/org/customerService.d.cts +6 -6
- package/dist/atoms/org/customerService.d.ts +6 -6
- package/dist/atoms/org/graphqlConfig.d.cts +4 -4
- package/dist/atoms/org/graphqlConfig.d.ts +4 -4
- package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
- package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
- package/dist/atoms/org/orgAnalyticsConfig.d.cts +5 -5
- package/dist/atoms/org/orgAnalyticsConfig.d.ts +5 -5
- package/dist/atoms/search/chatSearch.d.cts +17 -17
- package/dist/atoms/search/chatSearch.d.ts +17 -17
- package/dist/atoms/search/searchAPI.d.cts +13 -13
- package/dist/atoms/search/searchAPI.d.ts +13 -13
- package/dist/atoms/search/types.d.cts +1 -1
- package/dist/atoms/widget/chatPreviewLoading.d.cts +2 -2
- package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
- package/dist/contexts/graphqlContext/graphqlContext.cjs +4 -4
- package/dist/contexts/graphqlContext/graphqlContext.js +4 -4
- package/dist/contexts/hardcopyContext/hardcopyContext.cjs +5 -3
- package/dist/contexts/hardcopyContext/hardcopyContext.js +5 -3
- package/dist/contexts/salesAgentContext/chatAPI.cjs +12 -5
- package/dist/contexts/salesAgentContext/chatAPI.js +13 -6
- package/dist/contexts/systemSettingsContext/systemSettingsContext.d.ts +2 -2
- package/dist/contexts/types.d.cts +1 -1
- package/dist/contexts/types.d.ts +1 -1
- package/dist/contexts/typesV3.cjs +1 -1
- package/dist/contexts/typesV3.d.cts +2 -1
- package/dist/contexts/typesV3.d.ts +2 -1
- package/dist/contexts/typesV3.js +1 -1
- package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.ts +2 -2
- package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.cjs +8 -2
- package/dist/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.js +8 -2
- package/dist/hooks/WidgetInteraction/types.cjs +6 -2
- package/dist/hooks/WidgetInteraction/types.d.cts +8 -3
- package/dist/hooks/WidgetInteraction/types.d.ts +8 -3
- package/dist/hooks/WidgetInteraction/types.js +6 -2
- package/dist/hooks/utils.d.ts +1 -1
- package/dist/services/ga4ProjectionService/ga4EventSchema.cjs +31 -27
- package/dist/services/ga4ProjectionService/ga4EventSchema.js +31 -27
- package/dist/services/ga4ProjectionService/ga4ProjectionService.cjs +31 -5
- package/dist/services/ga4ProjectionService/ga4ProjectionService.js +31 -5
- package/package.json +1 -1
- package/src/application/models/featureGates.ts +1 -0
- package/src/atoms/chat/chatState.ts +1 -0
- package/src/contexts/graphqlContext/graphqlContext.tsx +6 -8
- package/src/contexts/hardcopyContext/hardcopyContext.tsx +10 -2
- package/src/contexts/salesAgentContext/chatAPI.ts +6 -2
- package/src/contexts/typesV3.ts +1 -0
- package/src/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent.ts +10 -2
- package/src/hooks/WidgetInteraction/types.ts +10 -1
- package/src/services/ga4ProjectionService/__tests__/ga4ProjectionService.test.ts +110 -49
- package/src/services/ga4ProjectionService/ga4EventSchema.ts +35 -27
- package/src/services/ga4ProjectionService/ga4ProjectionService.ts +60 -6
|
@@ -8,18 +8,39 @@ const filterToSchema = (eventProps, allowedFields) => {
|
|
|
8
8
|
for (const field of allowedFields) if (field in eventProps) result[field] = eventProps[field];
|
|
9
9
|
return result;
|
|
10
10
|
};
|
|
11
|
+
const flattenOneLevel = (obj) => {
|
|
12
|
+
const result = {};
|
|
13
|
+
for (const [key, value] of Object.entries(obj)) if (!key.includes(".") && value !== null && typeof value === "object" && !Array.isArray(value)) for (const [subKey, subValue] of Object.entries(value)) result[`${key}.${subKey}`] = subValue;
|
|
14
|
+
else result[key] = value;
|
|
15
|
+
return result;
|
|
16
|
+
};
|
|
17
|
+
const filterWithProjections = (eventProps, projections) => {
|
|
18
|
+
const result = {};
|
|
19
|
+
for (const [ga4Key, sourceKey] of Object.entries(projections)) if (sourceKey in eventProps) result[ga4Key] = eventProps[sourceKey];
|
|
20
|
+
return result;
|
|
21
|
+
};
|
|
11
22
|
const flattenDotKeys = (obj) => {
|
|
12
23
|
const result = {};
|
|
13
24
|
for (const [key, value] of Object.entries(obj)) result[key.replace(/\./g, "_")] = value;
|
|
14
25
|
return result;
|
|
15
26
|
};
|
|
16
27
|
const sanitizePageId = (filtered) => {
|
|
17
|
-
const pageType = filtered["context.page_type"];
|
|
28
|
+
const pageType = filtered["page_type"] ?? filtered["context.page_type"];
|
|
18
29
|
if (pageType === "pdp" || pageType === "plp") return filtered;
|
|
19
30
|
const rest = { ...filtered };
|
|
31
|
+
delete rest["page_id"];
|
|
20
32
|
delete rest["context.page_id"];
|
|
21
33
|
return rest;
|
|
22
34
|
};
|
|
35
|
+
const getNestedValue = (obj, path) => {
|
|
36
|
+
const parts = path.split(".");
|
|
37
|
+
let current = obj;
|
|
38
|
+
for (const part of parts) {
|
|
39
|
+
if (current === null || typeof current !== "object") return void 0;
|
|
40
|
+
current = current[part];
|
|
41
|
+
}
|
|
42
|
+
return current;
|
|
43
|
+
};
|
|
23
44
|
const projectWidgetInteractionData = (eventProps, config) => {
|
|
24
45
|
if (!config.widgetInteractionDataProjections) return {};
|
|
25
46
|
const interaction = eventProps["trigger.widget_interaction"];
|
|
@@ -30,7 +51,10 @@ const projectWidgetInteractionData = (eventProps, config) => {
|
|
|
30
51
|
if (interactionData === null || interactionData === void 0 || typeof interactionData !== "object") return {};
|
|
31
52
|
const data = interactionData;
|
|
32
53
|
const result = {};
|
|
33
|
-
for (const [gaKey,
|
|
54
|
+
for (const [gaKey, sourcePath] of Object.entries(projectionMap)) {
|
|
55
|
+
const value = getNestedValue(data, sourcePath);
|
|
56
|
+
if (value !== void 0) result[gaKey] = value;
|
|
57
|
+
}
|
|
34
58
|
return result;
|
|
35
59
|
};
|
|
36
60
|
const truncateString = (value) => {
|
|
@@ -50,8 +74,10 @@ const projectToGA4 = (eventName, eventProps) => {
|
|
|
50
74
|
const schemaEntry = GA4_EVENT_SCHEMA[eventName];
|
|
51
75
|
if (schemaEntry.gaEventName === null) return;
|
|
52
76
|
const config = schemaEntry;
|
|
53
|
-
const props = eventProps ?? {};
|
|
54
|
-
let filtered
|
|
77
|
+
const props = flattenOneLevel(eventProps ?? {});
|
|
78
|
+
let filtered;
|
|
79
|
+
if (config.fieldProjections) filtered = filterWithProjections(props, config.fieldProjections);
|
|
80
|
+
else filtered = filterToSchema(props, config.allowedFields);
|
|
55
81
|
filtered = sanitizePageId(filtered);
|
|
56
82
|
const interactionFields = projectWidgetInteractionData(props, config);
|
|
57
83
|
const truncatedParams = truncateValues({
|
|
@@ -69,4 +95,4 @@ const projectToGA4 = (eventName, eventProps) => {
|
|
|
69
95
|
|
|
70
96
|
//#endregion
|
|
71
97
|
export { projectToGA4 };
|
|
72
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2E0UHJvamVjdGlvblNlcnZpY2UuanMiLCJuYW1lcyI6WyJMb2dnZXIiLCJyZXN1bHQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZpY2VzL2dhNFByb2plY3Rpb25TZXJ2aWNlL2dhNFByb2plY3Rpb25TZXJ2aWNlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBMb2dnZXIgZnJvbSAnc3JjL2FwcGxpY2F0aW9uL2xvZ2dpbmcvbG9nZ2VyJztcbmltcG9ydCB7IEVudml2ZU1ldHJpY3NFdmVudE5hbWUgfSBmcm9tICcuLi9hbXBsaXR1ZGVTZXJ2aWNlL2V2ZW50TmFtZXMnO1xuaW1wb3J0IHsgR0E0UHJvamVjdGVkRXZlbnRDb25maWcsIEdBNF9FVkVOVF9TQ0hFTUEgfSBmcm9tICcuL2dhNEV2ZW50U2NoZW1hJztcblxuY29uc3QgbG9nZ2VyID0gbmV3IExvZ2dlcignZ2E0UHJvamVjdGlvblNlcnZpY2UnKTtcblxuY29uc3QgZmlsdGVyVG9TY2hlbWEgPSAoXG4gIGV2ZW50UHJvcHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBhbGxvd2VkRmllbGRzOiByZWFkb25seSBzdHJpbmdbXSxcbik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0+IHtcbiAgY29uc3QgcmVzdWx0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICBmb3IgKGNvbnN0IGZpZWxkIG9mIGFsbG93ZWRGaWVsZHMpIHtcbiAgICBpZiAoZmllbGQgaW4gZXZlbnRQcm9wcykge1xuICAgICAgcmVzdWx0W2ZpZWxkXSA9IGV2ZW50UHJvcHNbZmllbGRdO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufTtcblxuLy8gXCJjb250ZXh0LnBhZ2VfdHlwZVwiIOKGkiBcImNvbnRleHRfcGFnZV90eXBlXCJcbmNvbnN0IGZsYXR0ZW5Eb3RLZXlzID0gKG9iajogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9PiB7XG4gIGNvbnN0IHJlc3VsdDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMob2JqKSkge1xuICAgIHJlc3VsdFtrZXkucmVwbGFjZSgvXFwuL2csICdfJyldID0gdmFsdWU7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbi8vIE9taXQgY29udGV4dC5wYWdlX2lkIGZvciBub24tcGRwL3BscCBwYWdlIHR5cGVzLiBUaGUgY3VycmVudCBpbXBsZW1lbnRhdGlvbiBmb3IgY29udGV4dC5wYWdlX2lkIGlzOlxuLy8gUERQOiBwcm9kdWN0X2lkXG4vLyBQTFA6IHBscF9pZFxuLy8gU2VhcmNoOiBzZWFyY2ggcXVlcnlcbi8vIE90aGVyOiBwYWdlIHVybFxuLy8gV2Ugd2FudCB0byBvbWl0IGFsbCBidXQgcGRwIGFuZCBwbHAgcGFnZSB0eXBlcyB0byBwcm92aWRlIGEgY2xlYXIsIGNvbnNpc3RlbnQgaW50ZXJmYWNlIGZvciBtZXJjaGFudHMuXG5jb25zdCBzYW5pdGl6ZVBhZ2VJZCA9IChmaWx0ZXJlZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9PiB7XG4gIGNvbnN0IHBhZ2VUeXBlID0gZmlsdGVyZWRbJ2NvbnRleHQucGFnZV90eXBlJ107XG4gIGlmIChwYWdlVHlwZSA9PT0gJ3BkcCcgfHwgcGFnZVR5cGUgPT09ICdwbHAnKSB7XG4gICAgcmV0dXJuIGZpbHRlcmVkO1xuICB9XG4gIGNvbnN0IHJlc3QgPSB7IC4uLmZpbHRlcmVkIH07XG4gIGRlbGV0ZSByZXN0Wydjb250ZXh0LnBhZ2VfaWQnXTtcbiAgcmV0dXJuIHJlc3Q7XG59O1xuXG4vLyBFeHRyYWN0IHdoaXRlbGlzdGVkIHN1Yi1maWVsZHMgZnJvbSB0cmlnZ2VyLndpZGdldF9pbnRlcmFjdGlvbl9kYXRhXG5jb25zdCBwcm9qZWN0V2lkZ2V0SW50ZXJhY3Rpb25EYXRhID0gKFxuICBldmVudFByb3BzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgY29uZmlnOiBHQTRQcm9qZWN0ZWRFdmVudENvbmZpZyxcbik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0+IHtcbiAgaWYgKCFjb25maWcud2lkZ2V0SW50ZXJhY3Rpb25EYXRhUHJvamVjdGlvbnMpIHtcbiAgICByZXR1cm4ge307XG4gIH1cblxuICBjb25zdCBpbnRlcmFjdGlvbiA9IGV2ZW50UHJvcHNbJ3RyaWdnZXIud2lkZ2V0X2ludGVyYWN0aW9uJ107XG4gIGlmICh0eXBlb2YgaW50ZXJhY3Rpb24gIT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG5cbiAgY29uc3QgcHJvamVjdGlvbk1hcCA9IGNvbmZpZy53aWRnZXRJbnRlcmFjdGlvbkRhdGFQcm9qZWN0aW9uc1tpbnRlcmFjdGlvbl07XG4gIGlmICghcHJvamVjdGlvbk1hcCkge1xuICAgIHJldHVybiB7fTtcbiAgfVxuXG4gIGNvbnN0IGludGVyYWN0aW9uRGF0YSA9IGV2ZW50UHJvcHNbJ3RyaWdnZXIud2lkZ2V0X2ludGVyYWN0aW9uX2RhdGEnXTtcbiAgaWYgKFxuICAgIGludGVyYWN0aW9uRGF0YSA9PT0gbnVsbCB8fFxuICAgIGludGVyYWN0aW9uRGF0YSA9PT0gdW5kZWZpbmVkIHx8XG4gICAgdHlwZW9mIGludGVyYWN0aW9uRGF0YSAhPT0gJ29iamVjdCdcbiAgKSB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG5cbiAgY29uc3QgZGF0YSA9IGludGVyYWN0aW9uRGF0YSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgY29uc3QgcmVzdWx0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICBmb3IgKGNvbnN0IFtnYUtleSwgc291cmNlRmllbGRdIG9mIE9iamVjdC5lbnRyaWVzKHByb2plY3Rpb25NYXApKSB7XG4gICAgaWYgKHNvdXJjZUZpZWxkIGluIGRhdGEpIHtcbiAgICAgIHJlc3VsdFtnYUtleV0gPSBkYXRhW3NvdXJjZUZpZWxkXTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbmNvbnN0IHRydW5jYXRlU3RyaW5nID0gKHZhbHVlOiB1bmtub3duKTogdW5rbm93biA9PiB7XG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmIHZhbHVlLmxlbmd0aCA+IDEwMCkge1xuICAgIHJldHVybiBgJHt2YWx1ZS5zdWJzdHJpbmcoMCwgOTcpfS4uLmA7XG4gIH1cbiAgcmV0dXJuIHZhbHVlO1xufTtcblxuY29uc3QgdHJ1bmNhdGVWYWx1ZXMgPSAob2JqOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0+IHtcbiAgY29uc3QgcmVzdWx0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvYmopKSB7XG4gICAgcmVzdWx0W2tleV0gPSB0cnVuY2F0ZVN0cmluZyh2YWx1ZSk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbmNvbnN0IHB1c2hUb0RhdGFMYXllciA9IChnYUV2ZW50OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IHZvaWQgPT4ge1xuICBpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93LmRhdGFMYXllcikge1xuICAgIHdpbmRvdy5kYXRhTGF5ZXIucHVzaChnYUV2ZW50KTtcbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IHByb2plY3RUb0dBNCA9IChcbiAgZXZlbnROYW1lOiBFbnZpdmVNZXRyaWNzRXZlbnROYW1lLFxuICBldmVudFByb3BzPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4pOiB2b2lkID0+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBzY2hlbWFFbnRyeSA9IEdBNF9FVkVOVF9TQ0hFTUFbZXZlbnROYW1lXTtcblxuICAgIGlmIChzY2hlbWFFbnRyeS5nYUV2ZW50TmFtZSA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbmZpZyA9IHNjaGVtYUVudHJ5O1xuICAgIGNvbnN0IHByb3BzID0gZXZlbnRQcm9wcyA/PyB7fTtcblxuICAgIGxldCBmaWx0ZXJlZCA9IGZpbHRlclRvU2NoZW1hKHByb3BzLCBjb25maWcuYWxsb3dlZEZpZWxkcyk7XG4gICAgZmlsdGVyZWQgPSBzYW5pdGl6ZVBhZ2VJZChmaWx0ZXJlZCk7XG5cbiAgICBjb25zdCBpbnRlcmFjdGlvbkZpZWxkcyA9IHByb2plY3RXaWRnZXRJbnRlcmFjdGlvbkRhdGEocHJvcHMsIGNvbmZpZyk7XG5cbiAgICBjb25zdCBmbGF0UGFyYW1zID0ge1xuICAgICAgLi4uZmxhdHRlbkRvdEtleXMoZmlsdGVyZWQpLFxuICAgICAgLi4uaW50ZXJhY3Rpb25GaWVsZHMsXG4gICAgfTtcblxuICAgIGNvbnN0IHRydW5jYXRlZFBhcmFtcyA9IHRydW5jYXRlVmFsdWVzKGZsYXRQYXJhbXMpO1xuXG4gICAgcHVzaFRvRGF0YUxheWVyKHtcbiAgICAgIGV2ZW50OiBjb25maWcuZ2FFdmVudE5hbWUsXG4gICAgICAuLi50cnVuY2F0ZWRQYXJhbXMsXG4gICAgfSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZ2dlci5sb2dFcnJvcignRXJyb3IgcHJvamVjdGluZyBldmVudCB0byBHQTQnLCBlcnIsIHtcbiAgICAgIGV2ZW50TmFtZSxcbiAgICB9KTtcbiAgfVxufTtcbiJdLCJtYXBwaW5ncyI6Ijs7OztBQUlBLE1BQU0sU0FBUyxJQUFJQSxlQUFPLHVCQUF1QjtBQUVqRCxNQUFNLGtCQUNKLFlBQ0Esa0JBQzRCO0NBQzVCLE1BQU1DLFNBQWtDLEVBQUU7QUFDMUMsTUFBSyxNQUFNLFNBQVMsY0FDbEIsS0FBSSxTQUFTLFdBQ1gsUUFBTyxTQUFTLFdBQVc7QUFHL0IsUUFBTzs7QUFJVCxNQUFNLGtCQUFrQixRQUEwRDtDQUNoRixNQUFNQSxTQUFrQyxFQUFFO0FBQzFDLE1BQUssTUFBTSxDQUFDLEtBQUssVUFBVSxPQUFPLFFBQVEsSUFBSSxDQUM1QyxRQUFPLElBQUksUUFBUSxPQUFPLElBQUksSUFBSTtBQUVwQyxRQUFPOztBQVNULE1BQU0sa0JBQWtCLGFBQStEO0NBQ3JGLE1BQU0sV0FBVyxTQUFTO0FBQzFCLEtBQUksYUFBYSxTQUFTLGFBQWEsTUFDckMsUUFBTztDQUVULE1BQU0sT0FBTyxFQUFFLEdBQUcsVUFBVTtBQUM1QixRQUFPLEtBQUs7QUFDWixRQUFPOztBQUlULE1BQU0sZ0NBQ0osWUFDQSxXQUM0QjtBQUM1QixLQUFJLENBQUMsT0FBTyxpQ0FDVixRQUFPLEVBQUU7Q0FHWCxNQUFNLGNBQWMsV0FBVztBQUMvQixLQUFJLE9BQU8sZ0JBQWdCLFNBQ3pCLFFBQU8sRUFBRTtDQUdYLE1BQU0sZ0JBQWdCLE9BQU8saUNBQWlDO0FBQzlELEtBQUksQ0FBQyxjQUNILFFBQU8sRUFBRTtDQUdYLE1BQU0sa0JBQWtCLFdBQVc7QUFDbkMsS0FDRSxvQkFBb0IsUUFDcEIsb0JBQW9CLFVBQ3BCLE9BQU8sb0JBQW9CLFNBRTNCLFFBQU8sRUFBRTtDQUdYLE1BQU0sT0FBTztDQUNiLE1BQU1BLFNBQWtDLEVBQUU7QUFDMUMsTUFBSyxNQUFNLENBQUMsT0FBTyxnQkFBZ0IsT0FBTyxRQUFRLGNBQWMsQ0FDOUQsS0FBSSxlQUFlLEtBQ2pCLFFBQU8sU0FBUyxLQUFLO0FBR3pCLFFBQU87O0FBR1QsTUFBTSxrQkFBa0IsVUFBNEI7QUFDbEQsS0FBSSxPQUFPLFVBQVUsWUFBWSxNQUFNLFNBQVMsSUFDOUMsUUFBTyxHQUFHLE1BQU0sVUFBVSxHQUFHLEdBQUcsQ0FBQztBQUVuQyxRQUFPOztBQUdULE1BQU0sa0JBQWtCLFFBQTBEO0NBQ2hGLE1BQU1BLFNBQWtDLEVBQUU7QUFDMUMsTUFBSyxNQUFNLENBQUMsS0FBSyxVQUFVLE9BQU8sUUFBUSxJQUFJLENBQzVDLFFBQU8sT0FBTyxlQUFlLE1BQU07QUFFckMsUUFBTzs7QUFHVCxNQUFNLG1CQUFtQixZQUEyQztBQUNsRSxLQUFJLE9BQU8sV0FBVyxlQUFlLE9BQU8sVUFDMUMsUUFBTyxVQUFVLEtBQUssUUFBUTs7QUFJbEMsTUFBYSxnQkFDWCxXQUNBLGVBQ1M7QUFDVCxLQUFJO0VBQ0YsTUFBTSxjQUFjLGlCQUFpQjtBQUVyQyxNQUFJLFlBQVksZ0JBQWdCLEtBQzlCO0VBR0YsTUFBTSxTQUFTO0VBQ2YsTUFBTSxRQUFRLGNBQWMsRUFBRTtFQUU5QixJQUFJLFdBQVcsZUFBZSxPQUFPLE9BQU8sY0FBYztBQUMxRCxhQUFXLGVBQWUsU0FBUztFQUVuQyxNQUFNLG9CQUFvQiw2QkFBNkIsT0FBTyxPQUFPO0VBT3JFLE1BQU0sa0JBQWtCLGVBTEw7R0FDakIsR0FBRyxlQUFlLFNBQVM7R0FDM0IsR0FBRztHQUNKLENBRWlEO0FBRWxELGtCQUFnQjtHQUNkLE9BQU8sT0FBTztHQUNkLEdBQUc7R0FDSixDQUFDO1VBQ0ssS0FBSztBQUNaLFNBQU8sU0FBUyxpQ0FBaUMsS0FBSyxFQUNwRCxXQUNELENBQUMifQ==
|
|
98
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2E0UHJvamVjdGlvblNlcnZpY2UuanMiLCJuYW1lcyI6WyJMb2dnZXIiLCJyZXN1bHQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IiwiY3VycmVudDogdW5rbm93biIsImZpbHRlcmVkOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZXJ2aWNlcy9nYTRQcm9qZWN0aW9uU2VydmljZS9nYTRQcm9qZWN0aW9uU2VydmljZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgTG9nZ2VyIGZyb20gJ3NyYy9hcHBsaWNhdGlvbi9sb2dnaW5nL2xvZ2dlcic7XG5pbXBvcnQgeyBFbnZpdmVNZXRyaWNzRXZlbnROYW1lIH0gZnJvbSAnLi4vYW1wbGl0dWRlU2VydmljZS9ldmVudE5hbWVzJztcbmltcG9ydCB7IEdBNFByb2plY3RlZEV2ZW50Q29uZmlnLCBHQTRfRVZFTlRfU0NIRU1BIH0gZnJvbSAnLi9nYTRFdmVudFNjaGVtYSc7XG5cbmNvbnN0IGxvZ2dlciA9IG5ldyBMb2dnZXIoJ2dhNFByb2plY3Rpb25TZXJ2aWNlJyk7XG5cbmNvbnN0IGZpbHRlclRvU2NoZW1hID0gKFxuICBldmVudFByb3BzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgYWxsb3dlZEZpZWxkczogcmVhZG9ubHkgc3RyaW5nW10sXG4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9PiB7XG4gIGNvbnN0IHJlc3VsdDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgZm9yIChjb25zdCBmaWVsZCBvZiBhbGxvd2VkRmllbGRzKSB7XG4gICAgaWYgKGZpZWxkIGluIGV2ZW50UHJvcHMpIHtcbiAgICAgIHJlc3VsdFtmaWVsZF0gPSBldmVudFByb3BzW2ZpZWxkXTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbi8vIEZsYXR0ZW4gb25seSB0cnVlIHRvcC1sZXZlbCBuZXN0ZWQgb2JqZWN0cyAoa2V5cyB3aXRoIG5vIGRvdHMpIG9uZSBsZXZlbCBkZWVwLlxuLy8gS2V5cyB0aGF0IGFscmVhZHkgY29udGFpbiBkb3RzIGFyZSBsZWZ0IGludGFjdCBzbyB0aGF0IGUuZy5cbi8vIGB0cmlnZ2VyLndpZGdldF9pbnRlcmFjdGlvbl9kYXRhOiB7IC4uLiB9YCBpcyBwcmVzZXJ2ZWQgZm9yIGRvd25zdHJlYW0gZXh0cmFjdGlvbi5cbmNvbnN0IGZsYXR0ZW5PbmVMZXZlbCA9IChvYmo6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPT4ge1xuICBjb25zdCByZXN1bHQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9iaikpIHtcbiAgICBpZiAoXG4gICAgICAha2V5LmluY2x1ZGVzKCcuJykgJiZcbiAgICAgIHZhbHVlICE9PSBudWxsICYmXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmXG4gICAgICAhQXJyYXkuaXNBcnJheSh2YWx1ZSlcbiAgICApIHtcbiAgICAgIGZvciAoY29uc3QgW3N1YktleSwgc3ViVmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHZhbHVlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KSkge1xuICAgICAgICByZXN1bHRbYCR7a2V5fS4ke3N1YktleX1gXSA9IHN1YlZhbHVlO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICByZXN1bHRba2V5XSA9IHZhbHVlO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufTtcblxuLy8gQXBwbHkgYSBHQTQgcHJvamVjdGlvbiBtYXAgeyBnYTRLZXk6IHNvdXJjZUtleSB9IHRvIGV4dHJhY3QgYW5kIHJlbmFtZSBmaWVsZHMuXG5jb25zdCBmaWx0ZXJXaXRoUHJvamVjdGlvbnMgPSAoXG4gIGV2ZW50UHJvcHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBwcm9qZWN0aW9uczogUmVjb3JkPHN0cmluZywgc3RyaW5nPixcbik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0+IHtcbiAgY29uc3QgcmVzdWx0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICBmb3IgKGNvbnN0IFtnYTRLZXksIHNvdXJjZUtleV0gb2YgT2JqZWN0LmVudHJpZXMocHJvamVjdGlvbnMpKSB7XG4gICAgaWYgKHNvdXJjZUtleSBpbiBldmVudFByb3BzKSB7XG4gICAgICByZXN1bHRbZ2E0S2V5XSA9IGV2ZW50UHJvcHNbc291cmNlS2V5XTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbi8vIFwiY29udGV4dC5wYWdlX3R5cGVcIiDihpIgXCJjb250ZXh0X3BhZ2VfdHlwZVwiXG5jb25zdCBmbGF0dGVuRG90S2V5cyA9IChvYmo6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPT4ge1xuICBjb25zdCByZXN1bHQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9iaikpIHtcbiAgICByZXN1bHRba2V5LnJlcGxhY2UoL1xcLi9nLCAnXycpXSA9IHZhbHVlO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59O1xuXG4vLyBPbWl0IGNvbnRleHQucGFnZV9pZCBmb3Igbm9uLXBkcC9wbHAgcGFnZSB0eXBlcy4gVGhlIGN1cnJlbnQgaW1wbGVtZW50YXRpb24gZm9yIGNvbnRleHQucGFnZV9pZCBpczpcbi8vIFBEUDogcHJvZHVjdF9pZFxuLy8gUExQOiBwbHBfaWRcbi8vIFNlYXJjaDogc2VhcmNoIHF1ZXJ5XG4vLyBPdGhlcjogcGFnZSB1cmxcbi8vIFdlIHdhbnQgdG8gb21pdCBhbGwgYnV0IHBkcCBhbmQgcGxwIHBhZ2UgdHlwZXMgdG8gcHJvdmlkZSBhIGNsZWFyLCBjb25zaXN0ZW50IGludGVyZmFjZSBmb3IgbWVyY2hhbnRzLlxuLy8gSGFuZGxlcyBib3RoIGRvdC1ub3RhdGlvbiBrZXlzIChhbGxvd2VkRmllbGRzIHBhdGgpIGFuZCByZW5hbWVkIEdBNCBrZXlzIChmaWVsZFByb2plY3Rpb25zIHBhdGgpLlxuY29uc3Qgc2FuaXRpemVQYWdlSWQgPSAoZmlsdGVyZWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPT4ge1xuICBjb25zdCBwYWdlVHlwZSA9IGZpbHRlcmVkWydwYWdlX3R5cGUnXSA/PyBmaWx0ZXJlZFsnY29udGV4dC5wYWdlX3R5cGUnXTtcbiAgaWYgKHBhZ2VUeXBlID09PSAncGRwJyB8fCBwYWdlVHlwZSA9PT0gJ3BscCcpIHtcbiAgICByZXR1cm4gZmlsdGVyZWQ7XG4gIH1cbiAgY29uc3QgcmVzdCA9IHsgLi4uZmlsdGVyZWQgfTtcbiAgZGVsZXRlIHJlc3RbJ3BhZ2VfaWQnXTtcbiAgZGVsZXRlIHJlc3RbJ2NvbnRleHQucGFnZV9pZCddO1xuICByZXR1cm4gcmVzdDtcbn07XG5cbmNvbnN0IGdldE5lc3RlZFZhbHVlID0gKG9iajogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIHBhdGg6IHN0cmluZyk6IHVua25vd24gPT4ge1xuICBjb25zdCBwYXJ0cyA9IHBhdGguc3BsaXQoJy4nKTtcbiAgbGV0IGN1cnJlbnQ6IHVua25vd24gPSBvYmo7XG4gIGZvciAoY29uc3QgcGFydCBvZiBwYXJ0cykge1xuICAgIGlmIChjdXJyZW50ID09PSBudWxsIHx8IHR5cGVvZiBjdXJyZW50ICE9PSAnb2JqZWN0JykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBjdXJyZW50ID0gKGN1cnJlbnQgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW3BhcnRdO1xuICB9XG4gIHJldHVybiBjdXJyZW50O1xufTtcblxuLy8gRXh0cmFjdCB3aGl0ZWxpc3RlZCBzdWItZmllbGRzIGZyb20gdHJpZ2dlci53aWRnZXRfaW50ZXJhY3Rpb25fZGF0YVxuY29uc3QgcHJvamVjdFdpZGdldEludGVyYWN0aW9uRGF0YSA9IChcbiAgZXZlbnRQcm9wczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIGNvbmZpZzogR0E0UHJvamVjdGVkRXZlbnRDb25maWcsXG4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9PiB7XG4gIGlmICghY29uZmlnLndpZGdldEludGVyYWN0aW9uRGF0YVByb2plY3Rpb25zKSB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG5cbiAgY29uc3QgaW50ZXJhY3Rpb24gPSBldmVudFByb3BzWyd0cmlnZ2VyLndpZGdldF9pbnRlcmFjdGlvbiddO1xuICBpZiAodHlwZW9mIGludGVyYWN0aW9uICE9PSAnc3RyaW5nJykge1xuICAgIHJldHVybiB7fTtcbiAgfVxuXG4gIGNvbnN0IHByb2plY3Rpb25NYXAgPSBjb25maWcud2lkZ2V0SW50ZXJhY3Rpb25EYXRhUHJvamVjdGlvbnNbaW50ZXJhY3Rpb25dO1xuICBpZiAoIXByb2plY3Rpb25NYXApIHtcbiAgICByZXR1cm4ge307XG4gIH1cblxuICBjb25zdCBpbnRlcmFjdGlvbkRhdGEgPSBldmVudFByb3BzWyd0cmlnZ2VyLndpZGdldF9pbnRlcmFjdGlvbl9kYXRhJ107XG4gIGlmIChcbiAgICBpbnRlcmFjdGlvbkRhdGEgPT09IG51bGwgfHxcbiAgICBpbnRlcmFjdGlvbkRhdGEgPT09IHVuZGVmaW5lZCB8fFxuICAgIHR5cGVvZiBpbnRlcmFjdGlvbkRhdGEgIT09ICdvYmplY3QnXG4gICkge1xuICAgIHJldHVybiB7fTtcbiAgfVxuXG4gIGNvbnN0IGRhdGEgPSBpbnRlcmFjdGlvbkRhdGEgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGNvbnN0IHJlc3VsdDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgZm9yIChjb25zdCBbZ2FLZXksIHNvdXJjZVBhdGhdIG9mIE9iamVjdC5lbnRyaWVzKHByb2plY3Rpb25NYXApKSB7XG4gICAgY29uc3QgdmFsdWUgPSBnZXROZXN0ZWRWYWx1ZShkYXRhLCBzb3VyY2VQYXRoKTtcbiAgICBpZiAodmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmVzdWx0W2dhS2V5XSA9IHZhbHVlO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufTtcblxuY29uc3QgdHJ1bmNhdGVTdHJpbmcgPSAodmFsdWU6IHVua25vd24pOiB1bmtub3duID0+IHtcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUubGVuZ3RoID4gMTAwKSB7XG4gICAgcmV0dXJuIGAke3ZhbHVlLnN1YnN0cmluZygwLCA5Nyl9Li4uYDtcbiAgfVxuICByZXR1cm4gdmFsdWU7XG59O1xuXG5jb25zdCB0cnVuY2F0ZVZhbHVlcyA9IChvYmo6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPT4ge1xuICBjb25zdCByZXN1bHQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9iaikpIHtcbiAgICByZXN1bHRba2V5XSA9IHRydW5jYXRlU3RyaW5nKHZhbHVlKTtcbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufTtcblxuY29uc3QgcHVzaFRvRGF0YUxheWVyID0gKGdhRXZlbnQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogdm9pZCA9PiB7XG4gIGlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJiB3aW5kb3cuZGF0YUxheWVyKSB7XG4gICAgd2luZG93LmRhdGFMYXllci5wdXNoKGdhRXZlbnQpO1xuICB9XG59O1xuXG5leHBvcnQgY29uc3QgcHJvamVjdFRvR0E0ID0gKFxuICBldmVudE5hbWU6IEVudml2ZU1ldHJpY3NFdmVudE5hbWUsXG4gIGV2ZW50UHJvcHM/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbik6IHZvaWQgPT4ge1xuICB0cnkge1xuICAgIGNvbnN0IHNjaGVtYUVudHJ5ID0gR0E0X0VWRU5UX1NDSEVNQVtldmVudE5hbWVdO1xuXG4gICAgaWYgKHNjaGVtYUVudHJ5LmdhRXZlbnROYW1lID09PSBudWxsKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgY29uZmlnID0gc2NoZW1hRW50cnk7XG4gICAgY29uc3QgcHJvcHMgPSBmbGF0dGVuT25lTGV2ZWwoZXZlbnRQcm9wcyA/PyB7fSk7XG5cbiAgICBsZXQgZmlsdGVyZWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgIGlmIChjb25maWcuZmllbGRQcm9qZWN0aW9ucykge1xuICAgICAgZmlsdGVyZWQgPSBmaWx0ZXJXaXRoUHJvamVjdGlvbnMocHJvcHMsIGNvbmZpZy5maWVsZFByb2plY3Rpb25zKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZmlsdGVyZWQgPSBmaWx0ZXJUb1NjaGVtYShwcm9wcywgY29uZmlnLmFsbG93ZWRGaWVsZHMpO1xuICAgIH1cbiAgICBmaWx0ZXJlZCA9IHNhbml0aXplUGFnZUlkKGZpbHRlcmVkKTtcblxuICAgIGNvbnN0IGludGVyYWN0aW9uRmllbGRzID0gcHJvamVjdFdpZGdldEludGVyYWN0aW9uRGF0YShwcm9wcywgY29uZmlnKTtcblxuICAgIGNvbnN0IGZsYXRQYXJhbXMgPSB7XG4gICAgICAuLi5mbGF0dGVuRG90S2V5cyhmaWx0ZXJlZCksXG4gICAgICAuLi5pbnRlcmFjdGlvbkZpZWxkcyxcbiAgICB9O1xuXG4gICAgY29uc3QgdHJ1bmNhdGVkUGFyYW1zID0gdHJ1bmNhdGVWYWx1ZXMoZmxhdFBhcmFtcyk7XG5cbiAgICBwdXNoVG9EYXRhTGF5ZXIoe1xuICAgICAgZXZlbnQ6IGNvbmZpZy5nYUV2ZW50TmFtZSxcbiAgICAgIC4uLnRydW5jYXRlZFBhcmFtcyxcbiAgICB9KTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nZ2VyLmxvZ0Vycm9yKCdFcnJvciBwcm9qZWN0aW5nIGV2ZW50IHRvIEdBNCcsIGVyciwge1xuICAgICAgZXZlbnROYW1lLFxuICAgIH0pO1xu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
|
package/package.json
CHANGED
|
@@ -27,4 +27,5 @@ export enum FeatureGates {
|
|
|
27
27
|
IsAiSuggestionsVariantEnabled = 'is_ai_suggestions_variant_enabled',
|
|
28
28
|
IsAiSuggestionsVariantAEnabled = 'is_ai_suggestions_variant_a_enabled',
|
|
29
29
|
IsAiSuggestionsVariantBEnabled = 'is_ai_suggestions_variant_b_enabled',
|
|
30
|
+
IsVoiceInputEnabled = 'is_voice_input_enabled',
|
|
30
31
|
}
|
|
@@ -26,6 +26,7 @@ export const initializedAtom = atom<boolean>(false);
|
|
|
26
26
|
export const chatIsOpenAtom = atom<boolean>(false);
|
|
27
27
|
export const requestFailureAtom = atom<boolean>(false);
|
|
28
28
|
export const formSubmitAtom = atom<FormSubmittedAttributes>();
|
|
29
|
+
export const listeningToSpeechAtom = atom<'start' | 'stop' | 'abort' | undefined>(undefined);
|
|
29
30
|
export const chatOnToggleAtom = atom(
|
|
30
31
|
null,
|
|
31
32
|
(
|
|
@@ -254,21 +254,19 @@ export const GraphQLProvider = ({
|
|
|
254
254
|
const isSemanticColors = !window.location.href.includes('globals=merchant');
|
|
255
255
|
const isStorybook = window.top?.location.href.includes('?path=');
|
|
256
256
|
|
|
257
|
-
// If
|
|
258
|
-
if (
|
|
257
|
+
// If no v3 colors are found, return the default mock config to allow unconfigured merchants to work by default
|
|
258
|
+
if (!v3RootConfig?.colors || (isStorybook && isSemanticColors)) {
|
|
259
259
|
logger.logDebug('GraphQLContext | Returning mock v3 config', {
|
|
260
|
-
colorsConfig: mockV3ColorsConfig
|
|
260
|
+
colorsConfig: mockV3ColorsConfig,
|
|
261
261
|
frontendConfig: mockV3FrontendConfig as FrontendConfigV3Response,
|
|
262
262
|
});
|
|
263
263
|
const colorsConfig = mockV3ColorsConfig;
|
|
264
264
|
const frontendConfig = mockV3FrontendConfig;
|
|
265
265
|
return {
|
|
266
|
-
colorsConfig
|
|
267
|
-
? (colorsConfig as ColorsConfigV3Response)
|
|
268
|
-
: (v3ColorsConfig as ColorsConfigV3Response),
|
|
266
|
+
colorsConfig,
|
|
269
267
|
frontendConfig: frontendConfig as FrontendConfigV3Response,
|
|
270
268
|
orgPageConfig: {
|
|
271
|
-
pageVariants:
|
|
269
|
+
pageVariants: DEFAULT_PAGE_VARIANTS,
|
|
272
270
|
widgetConfigs: {},
|
|
273
271
|
mountingConfigs: {},
|
|
274
272
|
},
|
|
@@ -277,7 +275,7 @@ export const GraphQLProvider = ({
|
|
|
277
275
|
|
|
278
276
|
logger.logDebug('GraphQLContext | Returning v3 config', {
|
|
279
277
|
colorsConfig: v3ColorsConfig as ColorsConfigV3Response,
|
|
280
|
-
frontendConfig: v3FrontendConfig
|
|
278
|
+
frontendConfig: v3FrontendConfig,
|
|
281
279
|
orgPageConfig: {
|
|
282
280
|
pageVariants: v3pageVariants,
|
|
283
281
|
widgetConfigs: v3WidgetConfigs,
|
|
@@ -219,10 +219,18 @@ export const HardcopyProvider: React.FC<HardcopyProviderProps> = ({
|
|
|
219
219
|
const { featureFlagService } = useFeatureFlagService();
|
|
220
220
|
const getHardcopyFromBackend = useCallback(
|
|
221
221
|
async (request: HardcopyRequest): Promise<HardcopyResponse> => {
|
|
222
|
-
|
|
222
|
+
const fallbackWidgetType =
|
|
223
|
+
request.widgetType === WidgetTypeV3.ProductCardV3
|
|
224
|
+
? WidgetTypeV3.ImagePromptCardV3
|
|
225
|
+
: request.widgetType;
|
|
226
|
+
|
|
227
|
+
const overrideEntry =
|
|
228
|
+
hardcopyOverride?.[request.widgetType] ?? hardcopyOverride?.[fallbackWidgetType];
|
|
229
|
+
if (overrideEntry) {
|
|
223
230
|
logger.logDebug('using hardcopy override', request.widgetType);
|
|
224
|
-
return
|
|
231
|
+
return overrideEntry;
|
|
225
232
|
}
|
|
233
|
+
|
|
226
234
|
const overrideConfigVersion =
|
|
227
235
|
getQueryParam('spiffy_config_version') ||
|
|
228
236
|
getQueryParam('envive_config_version') ||
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { hasParsedVariantInfoAtom } from 'src/atoms/app';
|
|
15
15
|
import { analyticsContextAtom } from 'src/atoms/app/variant';
|
|
16
16
|
import { formSubmitAtom, replyEventCategoryAtom } from 'src/atoms/chat';
|
|
17
|
+
import { suggestionsAtom } from 'src/atoms/chat/chatState';
|
|
17
18
|
import { queueUserEventAtom } from 'src/atoms/chat/messageQueue';
|
|
18
19
|
import { useWidgetInteraction } from 'src/hooks/WidgetInteraction';
|
|
19
20
|
import {
|
|
@@ -56,6 +57,7 @@ export const useSalesAgentChatAPI = (widget?: WidgetInteractionComponent) => {
|
|
|
56
57
|
const context = useAtomValue(analyticsContextAtom);
|
|
57
58
|
const hasParsedVariantInfo = useAtomValue(hasParsedVariantInfoAtom);
|
|
58
59
|
const queueUserEvent = useSetAtom(queueUserEventAtom);
|
|
60
|
+
const setSuggestions = useSetAtom(suggestionsAtom);
|
|
59
61
|
const setReplyEventCategory = useSetAtom(replyEventCategoryAtom);
|
|
60
62
|
const setFormSubmit = useSetAtom(formSubmitAtom);
|
|
61
63
|
const { trackEvent } = useAmplitude();
|
|
@@ -164,9 +166,10 @@ export const useSalesAgentChatAPI = (widget?: WidgetInteractionComponent) => {
|
|
|
164
166
|
content: suggestion.content,
|
|
165
167
|
},
|
|
166
168
|
};
|
|
169
|
+
setSuggestions([]);
|
|
167
170
|
queueUserEvent(event);
|
|
168
171
|
},
|
|
169
|
-
[queueUserEvent, trackEvent, context],
|
|
172
|
+
[queueUserEvent, setSuggestions, trackEvent, context],
|
|
170
173
|
);
|
|
171
174
|
const onTypedMessageSubmitted = useCallback(
|
|
172
175
|
({
|
|
@@ -229,9 +232,10 @@ export const useSalesAgentChatAPI = (widget?: WidgetInteractionComponent) => {
|
|
|
229
232
|
userTyped,
|
|
230
233
|
},
|
|
231
234
|
};
|
|
235
|
+
setSuggestions([]);
|
|
232
236
|
queueUserEvent(event);
|
|
233
237
|
},
|
|
234
|
-
[queueUserEvent, trackEvent, context],
|
|
238
|
+
[queueUserEvent, setSuggestions, trackEvent, context],
|
|
235
239
|
);
|
|
236
240
|
const onFormResponseSubmitted = useCallback(
|
|
237
241
|
(form: FormSubmittedAttributes) => {
|
package/src/contexts/typesV3.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { useAtomValue } from 'jotai';
|
|
1
2
|
import { RefObject, useEffect, useRef } from 'react';
|
|
2
|
-
import {
|
|
3
|
+
import { pageVariantInfoAtom } from 'src/atoms/app';
|
|
3
4
|
import { useAmplitude } from 'src/contexts/amplitudeContext/amplitudeContext';
|
|
5
|
+
import { PageVariantInfo } from 'src/contexts/pageContext/types';
|
|
6
|
+
import { useIntersection } from 'src/hooks/Intersection/useIntersection';
|
|
7
|
+
import { extractPageContext } from 'src/hooks/WidgetInteraction/utils';
|
|
4
8
|
import {
|
|
5
9
|
EnviveMetricsEventName,
|
|
6
10
|
SpiffyMetricsEventName,
|
|
@@ -23,6 +27,7 @@ export const useTrackComponentVisibleEvent = (
|
|
|
23
27
|
const isVisible = useIntersection(element, rootMargin);
|
|
24
28
|
const hasTrackedEvent = useRef(false);
|
|
25
29
|
const { trackEvent } = useAmplitude();
|
|
30
|
+
const variantInfo = useAtomValue(pageVariantInfoAtom);
|
|
26
31
|
|
|
27
32
|
useEffect(() => {
|
|
28
33
|
if (!enabled || hasTrackedEvent.current) {
|
|
@@ -37,7 +42,10 @@ export const useTrackComponentVisibleEvent = (
|
|
|
37
42
|
eventName: EnviveMetricsEventName.WidgetRendered,
|
|
38
43
|
eventProps: {
|
|
39
44
|
...eventProps,
|
|
40
|
-
|
|
45
|
+
trigger: {
|
|
46
|
+
widget: eventProps?.widget_type,
|
|
47
|
+
},
|
|
48
|
+
context: variantInfo ? extractPageContext(variantInfo as PageVariantInfo) : null,
|
|
41
49
|
},
|
|
42
50
|
});
|
|
43
51
|
hasTrackedEvent.current = true;
|
|
@@ -62,6 +62,8 @@ export enum WidgetInteractionType {
|
|
|
62
62
|
REVIEW_CARD_CLICKED = 'review_card_clicked',
|
|
63
63
|
MESSAGE_SUBMITTED = 'message_submitted',
|
|
64
64
|
MANUAL_SCROLL_TO_BOTTOM = 'manual_scroll_to_bottom',
|
|
65
|
+
VOICE_TRANSCRIPTION_STARTED = 'voice_transcription_started',
|
|
66
|
+
VOICE_TRANSCRIPTION_COMPLETED = 'voice_transcription_completed',
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
export enum InteractionClass {
|
|
@@ -85,6 +87,8 @@ export const INTERACTION_TYPE_CLASS: Record<WidgetInteractionType, InteractionCl
|
|
|
85
87
|
[WidgetInteractionType.REVIEW_CARD_CLICKED]: InteractionClass.INTENTIONAL,
|
|
86
88
|
[WidgetInteractionType.MESSAGE_SUBMITTED]: InteractionClass.INTENTIONAL,
|
|
87
89
|
[WidgetInteractionType.MANUAL_SCROLL_TO_BOTTOM]: InteractionClass.PASSIVE,
|
|
90
|
+
[WidgetInteractionType.VOICE_TRANSCRIPTION_STARTED]: InteractionClass.INTENTIONAL,
|
|
91
|
+
[WidgetInteractionType.VOICE_TRANSCRIPTION_COMPLETED]: InteractionClass.INTENTIONAL,
|
|
88
92
|
};
|
|
89
93
|
|
|
90
94
|
export type URL = {
|
|
@@ -151,6 +155,10 @@ export type MessageSubmitted = {
|
|
|
151
155
|
message_submitted: Request;
|
|
152
156
|
};
|
|
153
157
|
|
|
158
|
+
export type VoiceTranscription = {
|
|
159
|
+
transcription: string;
|
|
160
|
+
};
|
|
161
|
+
|
|
154
162
|
export type WidgetInteractionData =
|
|
155
163
|
| SuggestionScrolled
|
|
156
164
|
| SuggestionClicked
|
|
@@ -161,4 +169,5 @@ export type WidgetInteractionData =
|
|
|
161
169
|
| ArticleLinkClicked
|
|
162
170
|
| ProductCardClicked
|
|
163
171
|
| ReviewCardClicked
|
|
164
|
-
| MessageSubmitted
|
|
172
|
+
| MessageSubmitted
|
|
173
|
+
| VoiceTranscription;
|
|
@@ -28,34 +28,46 @@ describe('projectToGA4', () => {
|
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
describe('Widget Rendered', () => {
|
|
31
|
-
it('should push
|
|
31
|
+
it('should push renamed GA4 fields from nested input', () => {
|
|
32
32
|
projectToGA4(EnviveMetricsEventName.WidgetRendered, {
|
|
33
|
-
|
|
34
|
-
'
|
|
35
|
-
'trigger.widget': 'floating_button',
|
|
36
|
-
'trigger.interaction_id': 'abc-123',
|
|
33
|
+
trigger: { widget: 'floating_button' },
|
|
34
|
+
context: { page_type: 'pdp', page_id: 'product-123' },
|
|
37
35
|
});
|
|
38
36
|
|
|
39
37
|
expect(window.dataLayer).toHaveLength(1);
|
|
40
38
|
expect(window.dataLayer[0]).toEqual({
|
|
41
39
|
event: 'envive_widget_rendered',
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
page_type: 'pdp',
|
|
41
|
+
page_id: 'product-123',
|
|
42
|
+
widget: 'floating_button',
|
|
45
43
|
});
|
|
46
44
|
});
|
|
47
45
|
|
|
48
|
-
it('should
|
|
46
|
+
it('should also accept flat dot-notation input', () => {
|
|
49
47
|
projectToGA4(EnviveMetricsEventName.WidgetRendered, {
|
|
50
48
|
'context.page_type': 'pdp',
|
|
51
49
|
'context.page_id': 'product-123',
|
|
52
50
|
'trigger.widget': 'floating_button',
|
|
53
|
-
'trigger.interaction_id': '
|
|
51
|
+
'trigger.interaction_id': 'abc-123',
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
expect(window.dataLayer[0]).toEqual({
|
|
55
|
+
event: 'envive_widget_rendered',
|
|
56
|
+
page_type: 'pdp',
|
|
57
|
+
page_id: 'product-123',
|
|
58
|
+
widget: 'floating_button',
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should exclude fields not in fieldProjections', () => {
|
|
63
|
+
projectToGA4(EnviveMetricsEventName.WidgetRendered, {
|
|
64
|
+
trigger: { widget: 'floating_button', interaction_id: 'should-be-dropped' },
|
|
65
|
+
context: { page_type: 'pdp', page_id: 'product-123' },
|
|
54
66
|
'some.random_field': 'also-dropped',
|
|
55
67
|
});
|
|
56
68
|
|
|
57
69
|
const pushed = window.dataLayer[0];
|
|
58
|
-
expect(pushed).not.toHaveProperty('
|
|
70
|
+
expect(pushed).not.toHaveProperty('interaction_id');
|
|
59
71
|
expect(pushed).not.toHaveProperty('some_random_field');
|
|
60
72
|
});
|
|
61
73
|
});
|
|
@@ -63,97 +75,146 @@ describe('projectToGA4', () => {
|
|
|
63
75
|
describe('page_id sanitization', () => {
|
|
64
76
|
it('should keep page_id for pdp page type', () => {
|
|
65
77
|
projectToGA4(EnviveMetricsEventName.WidgetRendered, {
|
|
66
|
-
|
|
67
|
-
'
|
|
68
|
-
'trigger.widget': 'floating_button',
|
|
78
|
+
trigger: { widget: 'floating_button' },
|
|
79
|
+
context: { page_type: 'pdp', page_id: 'product-123' },
|
|
69
80
|
});
|
|
70
81
|
|
|
71
|
-
expect(window.dataLayer[0]).toHaveProperty('
|
|
82
|
+
expect(window.dataLayer[0]).toHaveProperty('page_id', 'product-123');
|
|
72
83
|
});
|
|
73
84
|
|
|
74
85
|
it('should keep page_id for plp page type', () => {
|
|
75
86
|
projectToGA4(EnviveMetricsEventName.WidgetRendered, {
|
|
76
|
-
|
|
77
|
-
'
|
|
78
|
-
'trigger.widget': 'floating_button',
|
|
87
|
+
trigger: { widget: 'floating_button' },
|
|
88
|
+
context: { page_type: 'plp', page_id: 'category-456' },
|
|
79
89
|
});
|
|
80
90
|
|
|
81
|
-
expect(window.dataLayer[0]).toHaveProperty('
|
|
91
|
+
expect(window.dataLayer[0]).toHaveProperty('page_id', 'category-456');
|
|
82
92
|
});
|
|
83
93
|
|
|
84
94
|
it('should omit page_id for search page type', () => {
|
|
85
95
|
projectToGA4(EnviveMetricsEventName.WidgetRendered, {
|
|
86
|
-
|
|
87
|
-
'
|
|
88
|
-
'trigger.widget': 'floating_button',
|
|
96
|
+
trigger: { widget: 'floating_button' },
|
|
97
|
+
context: { page_type: 'search', page_id: 'some search query' },
|
|
89
98
|
});
|
|
90
99
|
|
|
91
|
-
expect(window.dataLayer[0]).not.toHaveProperty('
|
|
100
|
+
expect(window.dataLayer[0]).not.toHaveProperty('page_id');
|
|
92
101
|
});
|
|
93
102
|
|
|
94
103
|
it('should omit page_id for homepage page type', () => {
|
|
95
104
|
projectToGA4(EnviveMetricsEventName.WidgetRendered, {
|
|
96
|
-
|
|
97
|
-
'
|
|
98
|
-
'trigger.widget': 'floating_button',
|
|
105
|
+
trigger: { widget: 'floating_button' },
|
|
106
|
+
context: { page_type: 'homepage', page_id: 'https://example.com' },
|
|
99
107
|
});
|
|
100
108
|
|
|
101
|
-
expect(window.dataLayer[0]).not.toHaveProperty('
|
|
109
|
+
expect(window.dataLayer[0]).not.toHaveProperty('page_id');
|
|
102
110
|
});
|
|
103
111
|
|
|
104
112
|
it('should omit page_id for other page type', () => {
|
|
105
113
|
projectToGA4(EnviveMetricsEventName.WidgetRendered, {
|
|
106
|
-
|
|
107
|
-
'
|
|
108
|
-
'trigger.widget': 'floating_button',
|
|
114
|
+
trigger: { widget: 'floating_button' },
|
|
115
|
+
context: { page_type: 'other', page_id: 'https://example.com/about' },
|
|
109
116
|
});
|
|
110
117
|
|
|
111
|
-
expect(window.dataLayer[0]).not.toHaveProperty('
|
|
118
|
+
expect(window.dataLayer[0]).not.toHaveProperty('page_id');
|
|
112
119
|
});
|
|
113
120
|
});
|
|
114
121
|
|
|
115
122
|
describe('Widget Interaction', () => {
|
|
116
|
-
it('should push
|
|
123
|
+
it('should push renamed GA4 fields (flat dot-notation input)', () => {
|
|
117
124
|
projectToGA4(EnviveMetricsEventName.WidgetInteraction, {
|
|
118
125
|
'context.page_type': 'pdp',
|
|
119
126
|
'context.page_id': 'product-123',
|
|
120
127
|
'trigger.widget': 'chat_overlay',
|
|
121
128
|
'trigger.widget_interaction': 'link_clicked',
|
|
129
|
+
'trigger.interaction_class': 'intentional',
|
|
122
130
|
});
|
|
123
131
|
|
|
124
132
|
expect(window.dataLayer[0]).toEqual({
|
|
125
133
|
event: 'envive_widget_interaction',
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
134
|
+
page_type: 'pdp',
|
|
135
|
+
page_id: 'product-123',
|
|
136
|
+
widget: 'chat_overlay',
|
|
137
|
+
interaction_type: 'link_clicked',
|
|
138
|
+
interaction_class: 'intentional',
|
|
130
139
|
});
|
|
131
140
|
});
|
|
132
141
|
|
|
133
|
-
it('should
|
|
142
|
+
it('should project from real Amplitude nested-object props', () => {
|
|
143
|
+
projectToGA4(EnviveMetricsEventName.WidgetInteraction, {
|
|
144
|
+
trigger: {
|
|
145
|
+
widget: 'floating_button',
|
|
146
|
+
widget_interaction: 'widget_clicked',
|
|
147
|
+
interaction_id: '604a2e2c-9848-41dd-a2b1-cb5b8612ec08',
|
|
148
|
+
interaction_class: 'intentional',
|
|
149
|
+
},
|
|
150
|
+
context: {
|
|
151
|
+
page_id: 'hsa-fsa-eligible',
|
|
152
|
+
page_type: 'plp',
|
|
153
|
+
},
|
|
154
|
+
'environment.execution_context': 'bundle',
|
|
155
|
+
'org.short_name': 'dermalogica',
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
expect(window.dataLayer[0]).toEqual({
|
|
159
|
+
event: 'envive_widget_interaction',
|
|
160
|
+
page_type: 'plp',
|
|
161
|
+
page_id: 'hsa-fsa-eligible',
|
|
162
|
+
widget: 'floating_button',
|
|
163
|
+
interaction_type: 'widget_clicked',
|
|
164
|
+
interaction_class: 'intentional',
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('should omit page_id for non-pdp/plp page types (nested input)', () => {
|
|
169
|
+
projectToGA4(EnviveMetricsEventName.WidgetInteraction, {
|
|
170
|
+
trigger: { widget: 'floating_button', widget_interaction: 'widget_clicked' },
|
|
171
|
+
context: { page_type: 'homepage', page_id: 'https://example.com' },
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
expect(window.dataLayer[0]).not.toHaveProperty('page_id');
|
|
175
|
+
expect(window.dataLayer[0]).toHaveProperty('page_type', 'homepage');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('should extract interaction_collapse_source from widget_interaction_data for widget_collapsed', () => {
|
|
134
179
|
projectToGA4(EnviveMetricsEventName.WidgetInteraction, {
|
|
135
180
|
'context.page_type': 'pdp',
|
|
136
181
|
'context.page_id': 'product-123',
|
|
137
182
|
'trigger.widget': 'chat_overlay',
|
|
138
183
|
'trigger.widget_interaction': 'widget_collapsed',
|
|
139
|
-
'trigger.widget_interaction_data': {
|
|
184
|
+
'trigger.widget_interaction_data': {
|
|
185
|
+
widget_collapsed: { collapse_source: 'close_button' },
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
expect(window.dataLayer[0]).toHaveProperty('interaction_collapse_source', 'close_button');
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('should extract interaction_collapse_source from nested real-data trigger object', () => {
|
|
193
|
+
projectToGA4(EnviveMetricsEventName.WidgetInteraction, {
|
|
194
|
+
trigger: {
|
|
195
|
+
widget: 'floating_button',
|
|
196
|
+
widget_interaction: 'widget_collapsed',
|
|
197
|
+
interaction_class: 'navigational',
|
|
198
|
+
widget_interaction_data: { widget_collapsed: { collapse_source: 'swipe' } },
|
|
199
|
+
},
|
|
200
|
+
context: { page_type: 'pdp', page_id: 'product-123' },
|
|
140
201
|
});
|
|
141
202
|
|
|
142
|
-
expect(window.dataLayer[0]).toHaveProperty('
|
|
203
|
+
expect(window.dataLayer[0]).toHaveProperty('interaction_collapse_source', 'swipe');
|
|
204
|
+
expect(window.dataLayer[0]).toHaveProperty('interaction_class', 'navigational');
|
|
143
205
|
});
|
|
144
206
|
|
|
145
|
-
it('should extract
|
|
207
|
+
it('should extract interaction_product_id from widget_interaction_data for product_card_clicked', () => {
|
|
146
208
|
projectToGA4(EnviveMetricsEventName.WidgetInteraction, {
|
|
147
209
|
'context.page_type': 'pdp',
|
|
148
210
|
'context.page_id': 'product-123',
|
|
149
211
|
'trigger.widget': 'chat_overlay',
|
|
150
212
|
'trigger.widget_interaction': 'product_card_clicked',
|
|
151
|
-
'trigger.widget_interaction_data': { product_id: 'sku-789'
|
|
213
|
+
'trigger.widget_interaction_data': { product_card_clicked: { product_id: 'sku-789' } },
|
|
152
214
|
});
|
|
153
215
|
|
|
154
216
|
const pushed = window.dataLayer[0];
|
|
155
|
-
expect(pushed).toHaveProperty('
|
|
156
|
-
expect(pushed).not.toHaveProperty('url');
|
|
217
|
+
expect(pushed).toHaveProperty('interaction_product_id', 'sku-789');
|
|
157
218
|
});
|
|
158
219
|
|
|
159
220
|
it('should extract suggestion_id from widget_interaction_data for suggestion_scrolled', () => {
|
|
@@ -162,10 +223,10 @@ describe('projectToGA4', () => {
|
|
|
162
223
|
'context.page_id': 'product-123',
|
|
163
224
|
'trigger.widget': 'chat_overlay',
|
|
164
225
|
'trigger.widget_interaction': 'suggestion_scrolled',
|
|
165
|
-
'trigger.widget_interaction_data': { suggestion_id: 'sug-456' },
|
|
226
|
+
'trigger.widget_interaction_data': { suggestion_scrolled: { suggestion_id: 'sug-456' } },
|
|
166
227
|
});
|
|
167
228
|
|
|
168
|
-
expect(window.dataLayer[0]).toHaveProperty('
|
|
229
|
+
expect(window.dataLayer[0]).toHaveProperty('interaction_suggestion_id', 'sug-456');
|
|
169
230
|
});
|
|
170
231
|
|
|
171
232
|
it('should drop widget_interaction_data for unwhitelisted interactions', () => {
|
|
@@ -281,8 +342,8 @@ describe('projectToGA4', () => {
|
|
|
281
342
|
|
|
282
343
|
expect(window.dataLayer[0]).toEqual({
|
|
283
344
|
event: 'envive_page_context_evaluated',
|
|
284
|
-
|
|
285
|
-
|
|
345
|
+
page_type: 'pdp',
|
|
346
|
+
page_id: 'product-123',
|
|
286
347
|
context_supported: true,
|
|
287
348
|
context_ready: true,
|
|
288
349
|
context_page_variant_id: 'variant-A',
|
|
@@ -300,8 +361,8 @@ describe('projectToGA4', () => {
|
|
|
300
361
|
});
|
|
301
362
|
|
|
302
363
|
const pushed = window.dataLayer[0];
|
|
303
|
-
expect(pushed).not.toHaveProperty('
|
|
304
|
-
expect(pushed).toHaveProperty('
|
|
364
|
+
expect(pushed).not.toHaveProperty('page_id');
|
|
365
|
+
expect(pushed).toHaveProperty('page_type', 'search');
|
|
305
366
|
});
|
|
306
367
|
});
|
|
307
368
|
|