@envive-ai/react-hooks 0.3.32 → 0.3.33
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/commerce-api.d.cts +1 -1
- package/dist/application/commerce-api.d.ts +1 -1
- package/dist/atoms/app/index.d.cts +9 -9
- package/dist/atoms/app/index.d.ts +9 -9
- package/dist/atoms/app/variant.d.cts +8 -8
- package/dist/atoms/app/variant.d.ts +8 -8
- package/dist/atoms/chat/chatState.d.cts +20 -20
- package/dist/atoms/chat/chatState.d.ts +20 -20
- package/dist/atoms/chat/form.d.cts +2 -2
- package/dist/atoms/chat/form.d.ts +2 -2
- package/dist/atoms/chat/index.cjs +1 -1
- package/dist/atoms/chat/index.d.cts +3 -3
- package/dist/atoms/chat/index.d.ts +2 -2
- package/dist/atoms/chat/index.js +1 -1
- 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.ts +6 -6
- package/dist/atoms/chat/renderedWidgetRefs.d.cts +2 -2
- package/dist/atoms/chat/renderedWidgetRefs.d.ts +3 -3
- package/dist/atoms/chat/replies.d.ts +3 -3
- 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 +6 -6
- 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 +5 -5
- package/dist/atoms/org/graphqlConfig.d.ts +5 -5
- package/dist/atoms/org/index.cjs +2 -3
- package/dist/atoms/org/index.d.cts +2 -2
- package/dist/atoms/org/index.d.ts +2 -2
- package/dist/atoms/org/index.js +3 -3
- package/dist/atoms/org/newOrgConfigAtom.d.cts +2 -2
- package/dist/atoms/org/newOrgConfigAtom.d.ts +2 -2
- package/dist/atoms/org/orgAnalyticsConfig.cjs +1 -3
- package/dist/atoms/org/orgAnalyticsConfig.d.cts +7 -8
- package/dist/atoms/org/orgAnalyticsConfig.d.ts +7 -8
- package/dist/atoms/org/orgAnalyticsConfig.js +2 -3
- package/dist/atoms/search/chatSearch.cjs +1 -1
- package/dist/atoms/search/chatSearch.d.cts +17 -17
- package/dist/atoms/search/chatSearch.d.ts +17 -17
- package/dist/atoms/search/chatSearch.js +1 -1
- package/dist/atoms/search/searchAPI.cjs +1 -1
- package/dist/atoms/search/searchAPI.d.cts +13 -13
- package/dist/atoms/search/searchAPI.d.ts +13 -13
- package/dist/atoms/search/searchAPI.js +1 -1
- package/dist/atoms/widget/chatPreviewLoading.d.ts +2 -2
- package/dist/contexts/amplitudeContext/amplitudeContext.cjs +1 -5
- package/dist/contexts/amplitudeContext/amplitudeContext.js +1 -5
- package/dist/contexts/enviveConfigContext/enviveConfigContext.cjs +18 -23
- package/dist/contexts/enviveConfigContext/enviveConfigContext.d.cts +10 -12
- package/dist/contexts/enviveConfigContext/enviveConfigContext.d.ts +10 -12
- package/dist/contexts/enviveConfigContext/enviveConfigContext.js +18 -23
- package/dist/contexts/enviveContext/enviveContext.cjs +41 -74
- package/dist/contexts/enviveContext/enviveContext.d.cts +15 -32
- package/dist/contexts/enviveContext/enviveContext.d.ts +15 -32
- package/dist/contexts/enviveContext/enviveContext.js +41 -74
- package/dist/contexts/enviveContext/index.d.cts +2 -2
- package/dist/contexts/enviveContext/index.d.ts +2 -2
- package/dist/contexts/enviveCssContext/enviveCssContext.cjs +31 -16
- package/dist/contexts/enviveCssContext/enviveCssContext.js +31 -16
- package/dist/contexts/graphqlContext/graphqlContext.cjs +3 -212
- package/dist/contexts/graphqlContext/graphqlContext.d.cts +2 -10
- package/dist/contexts/graphqlContext/graphqlContext.d.ts +2 -10
- package/dist/contexts/graphqlContext/graphqlContext.js +3 -212
- package/dist/contexts/graphqlContext/mockV3Config.cjs +31 -16
- package/dist/contexts/graphqlContext/mockV3Config.js +31 -16
- package/dist/contexts/hardcopyContext/hardcopyContext.cjs +9 -238
- package/dist/contexts/hardcopyContext/hardcopyContext.d.cts +5 -17
- package/dist/contexts/hardcopyContext/hardcopyContext.d.ts +5 -17
- package/dist/contexts/hardcopyContext/hardcopyContext.js +9 -238
- package/dist/contexts/hardcopyContext/index.d.cts +3 -2
- package/dist/contexts/hardcopyContext/index.d.ts +3 -2
- package/dist/contexts/newOrgConfigContext/newOrgConfigContext.cjs +10 -32
- package/dist/contexts/newOrgConfigContext/newOrgConfigContext.d.cts +2 -2
- package/dist/contexts/newOrgConfigContext/newOrgConfigContext.d.ts +2 -2
- package/dist/contexts/newOrgConfigContext/newOrgConfigContext.js +12 -34
- package/dist/contexts/pageContext/mapping.d.cts +1 -1
- package/dist/contexts/pageContext/mapping.d.ts +1 -1
- package/dist/contexts/pageContext/types.d.cts +1 -1
- package/dist/contexts/salesAgentContext/chatAPI.cjs +2 -2
- package/dist/contexts/salesAgentContext/chatAPI.js +2 -2
- package/dist/contexts/salesAgentContext/salesAgentService.cjs +1 -1
- package/dist/contexts/salesAgentContext/salesAgentService.js +1 -1
- package/dist/contexts/searchContext/searchContext.cjs +1 -1
- package/dist/contexts/searchContext/searchContext.js +1 -1
- package/dist/contexts/systemSettingsContext/systemSettingsContext.d.cts +2 -2
- package/dist/contexts/types.d.cts +2 -2
- package/dist/contexts/types.d.ts +2 -2
- package/dist/contexts/typesV3.cjs +31 -16
- package/dist/contexts/typesV3.d.cts +62 -31
- package/dist/contexts/typesV3.d.ts +62 -31
- package/dist/contexts/typesV3.js +31 -16
- package/dist/contexts/userIdentityContext/userIdentityContext.cjs +1 -1
- package/dist/contexts/userIdentityContext/userIdentityContext.d.cts +3 -3
- package/dist/contexts/userIdentityContext/userIdentityContext.d.ts +3 -3
- package/dist/contexts/userIdentityContext/userIdentityContext.js +1 -1
- package/dist/hooks/ChatToggle/useChatToggle.cjs +1 -1
- package/dist/hooks/ChatToggle/useChatToggle.js +1 -1
- package/dist/hooks/GrabAndScroll/useGrabAndScroll.d.cts +2 -2
- package/dist/hooks/GraphQLConfig/index.cjs +0 -1
- package/dist/hooks/GraphQLConfig/index.d.cts +2 -2
- package/dist/hooks/GraphQLConfig/index.d.ts +2 -2
- package/dist/hooks/GraphQLConfig/index.js +2 -2
- package/dist/hooks/GraphQLConfig/useGraphQLConfig.cjs +7 -66
- package/dist/hooks/GraphQLConfig/useGraphQLConfig.d.cts +5 -13
- package/dist/hooks/GraphQLConfig/useGraphQLConfig.d.ts +5 -13
- package/dist/hooks/GraphQLConfig/useGraphQLConfig.js +8 -66
- package/dist/hooks/Search/useSearch.cjs +3 -3
- package/dist/hooks/Search/useSearch.js +3 -3
- package/dist/services/amplitudeService/amplitudeService.cjs +4 -3
- package/dist/services/amplitudeService/amplitudeService.d.cts +1 -2
- package/dist/services/amplitudeService/amplitudeService.d.ts +1 -2
- package/dist/services/amplitudeService/amplitudeService.js +4 -3
- package/dist/services/enviveConfigService/enviveConfigService.cjs +25 -5
- package/dist/services/enviveConfigService/enviveConfigService.d.cts +24 -5
- package/dist/services/enviveConfigService/enviveConfigService.d.ts +24 -5
- package/dist/services/enviveConfigService/enviveConfigService.js +25 -6
- package/dist/services/enviveConfigService/fetchGraphQLConfig.cjs +181 -0
- package/dist/services/enviveConfigService/fetchGraphQLConfig.js +180 -0
- package/dist/services/enviveConfigService/index.cjs +2 -1
- package/dist/services/enviveConfigService/index.d.cts +2 -2
- package/dist/services/enviveConfigService/index.d.ts +2 -2
- package/dist/services/enviveConfigService/index.js +2 -2
- package/dist/services/hardcopyService/hardcopyService.cjs +232 -0
- package/dist/services/hardcopyService/hardcopyService.d.cts +39 -0
- package/dist/services/hardcopyService/hardcopyService.d.ts +39 -0
- package/dist/services/hardcopyService/hardcopyService.js +229 -0
- package/dist/services/hardcopyService/index.cjs +5 -0
- package/dist/services/hardcopyService/index.d.cts +2 -0
- package/dist/services/hardcopyService/index.d.ts +2 -0
- package/dist/services/hardcopyService/index.js +3 -0
- package/dist/services/userIdentityService/index.cjs +1 -0
- package/dist/services/userIdentityService/index.d.cts +2 -2
- package/dist/services/userIdentityService/index.d.ts +2 -2
- package/dist/services/userIdentityService/index.js +2 -2
- package/dist/services/userIdentityService/userIdentityService.cjs +13 -1
- package/dist/services/userIdentityService/userIdentityService.d.cts +12 -2
- package/dist/services/userIdentityService/userIdentityService.d.ts +12 -2
- package/dist/services/userIdentityService/userIdentityService.js +13 -2
- package/dist/types/enviveConfig.d.cts +1 -1
- package/dist/types/enviveConfig.d.ts +1 -1
- package/package.json +5 -1
- package/src/atoms/org/orgAnalyticsConfig.ts +0 -5
- package/src/contexts/amplitudeContext/amplitudeContext.tsx +0 -4
- package/src/contexts/enviveConfigContext/enviveConfigContext.tsx +37 -49
- package/src/contexts/enviveContext/enviveContext.tsx +72 -134
- package/src/contexts/enviveCssContext/enviveCssContext.tsx +32 -17
- package/src/contexts/graphqlContext/__tests__/graphqlContext.test.tsx +3 -36
- package/src/contexts/graphqlContext/graphqlContext.tsx +4 -304
- package/src/contexts/graphqlContext/mockV3Config.ts +30 -15
- package/src/contexts/hardcopyContext/hardcopyContext.tsx +12 -270
- package/src/contexts/newOrgConfigContext/__tests__/newOrgConfigContext.test.tsx +54 -478
- package/src/contexts/newOrgConfigContext/newOrgConfigContext.tsx +9 -26
- package/src/contexts/typesV3.ts +61 -30
- package/src/contexts/userIdentityContext/userIdentityContext.tsx +2 -2
- package/src/hooks/GraphQLConfig/useGraphQLConfig.ts +2 -62
- package/src/hooks/Search/__tests__/useSearch.test.tsx +2 -2
- package/src/services/amplitudeService/__tests__/amplitudeService.test.ts +3 -5
- package/src/services/amplitudeService/amplitudeService.ts +5 -3
- package/src/services/enviveConfigService/__tests__/fetchGraphQLConfig.test.ts +425 -0
- package/src/services/enviveConfigService/enviveConfigService.ts +41 -13
- package/src/services/enviveConfigService/fetchGraphQLConfig.ts +225 -0
- package/src/services/hardcopyService/__tests__/hardcopyService.test.ts +367 -0
- package/src/services/hardcopyService/hardcopyService.ts +271 -0
- package/src/services/hardcopyService/index.ts +1 -0
- package/src/services/userIdentityService/userIdentityService.ts +18 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import Logger from 'src/application/logging/logger';
|
|
2
|
+
import {
|
|
3
|
+
CamelCasedPropertiesDeep,
|
|
4
|
+
transformSnakeToCamel,
|
|
5
|
+
validateAndTransformMountingConfig,
|
|
6
|
+
validateAndTransformPageVariants,
|
|
7
|
+
} from 'src/application/models';
|
|
8
|
+
import { FrontendConfigV3 } from 'src/application/models/frontendConfigV3';
|
|
9
|
+
import { ColorMappingV3 } from 'src/application/models/colorsConfigV3';
|
|
10
|
+
import { FloatingButtonLocation } from '@envive-ai/react-toolkit-v3/FloatingButton';
|
|
11
|
+
import { getColorsAndFrontendQuery } from 'src/application/models/graphql/queries/getColorsAndFrontendQuery';
|
|
12
|
+
import { mockV3ColorsConfig, mockV3FrontendConfig } from 'src/contexts/graphqlContext/mockV3Config';
|
|
13
|
+
import { WidgetConfigV3 } from 'src/contexts/typesV3';
|
|
14
|
+
import { PageVariantConfig, PageVariantTestType, WidgetMountingConfig } from 'src/contexts/types';
|
|
15
|
+
import { GraphQlConfigValues } from 'src/contexts/graphqlContext';
|
|
16
|
+
|
|
17
|
+
const logger = new Logger('fetchGraphQLConfig');
|
|
18
|
+
|
|
19
|
+
type FrontendConfigV3Response = CamelCasedPropertiesDeep<FrontendConfigV3>;
|
|
20
|
+
type ColorsConfigV3Response = CamelCasedPropertiesDeep<ColorMappingV3>;
|
|
21
|
+
|
|
22
|
+
export const DEFAULT_PAGE_VARIANTS: PageVariantConfig[] = [
|
|
23
|
+
{
|
|
24
|
+
variantId: 'plp',
|
|
25
|
+
variantType: 'plp',
|
|
26
|
+
plpIdExtractor: 'url-resolver-plp-id',
|
|
27
|
+
widgetMounting: [],
|
|
28
|
+
variantTests: [{ testType: PageVariantTestType.UrlResolver }],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
variantId: 'pdp',
|
|
32
|
+
variantType: 'pdp',
|
|
33
|
+
productIdExtractor: 'url-resolver-product-id',
|
|
34
|
+
widgetMounting: [],
|
|
35
|
+
variantTests: [{ testType: PageVariantTestType.UrlResolver }],
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const mapPositionToCamelCase = (position: string): FloatingButtonLocation => {
|
|
40
|
+
if (position === 'bottom-left') return FloatingButtonLocation.BOTTOM_LEFT;
|
|
41
|
+
if (position === 'middle-left') return FloatingButtonLocation.MIDDLE_LEFT;
|
|
42
|
+
if (position === 'middle-right') return FloatingButtonLocation.MIDDLE_RIGHT;
|
|
43
|
+
if (position === 'bottom-right') return FloatingButtonLocation.BOTTOM_RIGHT;
|
|
44
|
+
throw new Error(`Invalid position: ${position}`);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const v3FrontendConfigCleanup = (
|
|
48
|
+
v3RootConfig: FrontendConfigV3Response,
|
|
49
|
+
): FrontendConfigV3Response => {
|
|
50
|
+
const { uiConfigs } = v3RootConfig;
|
|
51
|
+
if (!uiConfigs) return v3RootConfig;
|
|
52
|
+
const { floatingButton, lookAndFeel } = uiConfigs as any;
|
|
53
|
+
if (!floatingButton || !lookAndFeel) return v3RootConfig;
|
|
54
|
+
const { fontSize, lineHeight, letterSpacing } = lookAndFeel.typography as any;
|
|
55
|
+
return {
|
|
56
|
+
...v3RootConfig,
|
|
57
|
+
uiConfigs: {
|
|
58
|
+
...uiConfigs,
|
|
59
|
+
floatingButton: {
|
|
60
|
+
...floatingButton,
|
|
61
|
+
position: mapPositionToCamelCase(
|
|
62
|
+
v3RootConfig.uiConfigs?.floatingButton?.position as string,
|
|
63
|
+
),
|
|
64
|
+
},
|
|
65
|
+
lookAndFeel: {
|
|
66
|
+
...lookAndFeel,
|
|
67
|
+
chatHeaderLogoDarkSrc: lookAndFeel.chatHeaderLogoDarkSrc || lookAndFeel.chatHeaderLogoSrc,
|
|
68
|
+
chatHeaderLogoLightSrc: lookAndFeel.chatHeaderLogoLightSrc || lookAndFeel.chatHeaderLogoSrc,
|
|
69
|
+
typography: {
|
|
70
|
+
...lookAndFeel.typography,
|
|
71
|
+
fontSize: {
|
|
72
|
+
b1: fontSize?.b1 || fontSize?.b_1,
|
|
73
|
+
b2: fontSize?.b2 || fontSize?.b_2,
|
|
74
|
+
b3: fontSize?.b3 || fontSize?.b_3,
|
|
75
|
+
b4: fontSize?.b4 || fontSize?.b_4,
|
|
76
|
+
b5: fontSize?.b5 || fontSize?.b_5,
|
|
77
|
+
h1: fontSize?.h1 || fontSize?.h_1,
|
|
78
|
+
h2: fontSize?.h2 || fontSize?.h_2,
|
|
79
|
+
h3: fontSize?.h3 || fontSize?.h_3,
|
|
80
|
+
l1: fontSize?.l1 || fontSize?.l_1,
|
|
81
|
+
l2: fontSize?.l2 || fontSize?.l_2,
|
|
82
|
+
t1: fontSize?.t1 || fontSize?.t_1,
|
|
83
|
+
t2: fontSize?.t2 || fontSize?.t_2,
|
|
84
|
+
t3: fontSize?.t3 || fontSize?.t_3,
|
|
85
|
+
},
|
|
86
|
+
letterSpacing: {
|
|
87
|
+
...lookAndFeel.typography.letterSpacing,
|
|
88
|
+
b1: letterSpacing?.b1 || letterSpacing?.b_1,
|
|
89
|
+
b2: letterSpacing?.b2 || letterSpacing?.b_2,
|
|
90
|
+
b3: letterSpacing?.b3 || letterSpacing?.b_3,
|
|
91
|
+
b4: letterSpacing?.b4 || letterSpacing?.b_4,
|
|
92
|
+
b5: letterSpacing?.b5 || letterSpacing?.b_5,
|
|
93
|
+
h1: letterSpacing?.h1 || letterSpacing?.h_1,
|
|
94
|
+
h2: letterSpacing?.h2 || letterSpacing?.h_2,
|
|
95
|
+
h3: letterSpacing?.h3 || letterSpacing?.h_3,
|
|
96
|
+
l1: letterSpacing?.l1 || letterSpacing?.l_1,
|
|
97
|
+
l2: letterSpacing?.l2 || letterSpacing?.l_2,
|
|
98
|
+
t1: letterSpacing?.t1 || letterSpacing?.t_1,
|
|
99
|
+
t2: letterSpacing?.t2 || letterSpacing?.t_2,
|
|
100
|
+
t3: letterSpacing?.t3 || letterSpacing?.t_3,
|
|
101
|
+
},
|
|
102
|
+
lineHeight: {
|
|
103
|
+
...lookAndFeel.typography.lineHeight,
|
|
104
|
+
'114': lineHeight?.lh_114 || lineHeight?.[114],
|
|
105
|
+
'116': lineHeight?.lh_116 || lineHeight?.[116],
|
|
106
|
+
'118': lineHeight?.lh_118 || lineHeight?.[118],
|
|
107
|
+
'120': lineHeight?.lh_120 || lineHeight?.[120],
|
|
108
|
+
'124': lineHeight?.lh_124 || lineHeight?.[124],
|
|
109
|
+
'128': lineHeight?.lh_128 || lineHeight?.[128],
|
|
110
|
+
'130': lineHeight?.lh_130 || lineHeight?.[130],
|
|
111
|
+
'133': lineHeight?.lh_133 || lineHeight?.[133],
|
|
112
|
+
'140': lineHeight?.lh_140 || lineHeight?.[140],
|
|
113
|
+
'148': lineHeight?.lh_148 || lineHeight?.[148],
|
|
114
|
+
b1: lineHeight?.b1 || lineHeight?.b_1,
|
|
115
|
+
b2: lineHeight?.b2 || lineHeight?.b_2,
|
|
116
|
+
b3: lineHeight?.b3 || lineHeight?.b_3,
|
|
117
|
+
b4: lineHeight?.b4 || lineHeight?.b_4,
|
|
118
|
+
b5: lineHeight?.b5 || lineHeight?.b_5,
|
|
119
|
+
h1: lineHeight?.h1 || lineHeight?.h_1,
|
|
120
|
+
h2: lineHeight?.h2 || lineHeight?.h_2,
|
|
121
|
+
h3: lineHeight?.h3 || lineHeight?.h_3,
|
|
122
|
+
l1: lineHeight?.l1 || lineHeight?.l_1,
|
|
123
|
+
l2: lineHeight?.l2 || lineHeight?.l_2,
|
|
124
|
+
t1: lineHeight?.t1 || lineHeight?.t_1,
|
|
125
|
+
t2: lineHeight?.t2 || lineHeight?.t_2,
|
|
126
|
+
t3: lineHeight?.t3 || lineHeight?.t_3,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export const fetchGraphQLConfig = async (
|
|
135
|
+
baseUrl: string,
|
|
136
|
+
apiKey: string,
|
|
137
|
+
): Promise<GraphQlConfigValues> => {
|
|
138
|
+
try {
|
|
139
|
+
const query = getColorsAndFrontendQuery();
|
|
140
|
+
const response = await fetch(`${baseUrl}/v1/graphql`, {
|
|
141
|
+
method: 'POST',
|
|
142
|
+
headers: {
|
|
143
|
+
'Content-Type': 'application/json',
|
|
144
|
+
Authorization: `Bearer ${apiKey}`,
|
|
145
|
+
},
|
|
146
|
+
body: JSON.stringify({ query }),
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
if (!response.ok) {
|
|
150
|
+
throw new Error(`GraphQL request failed: ${response.statusText}`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const result = await response.json();
|
|
154
|
+
if (result.errors) {
|
|
155
|
+
throw new Error(`GraphQL errors: ${JSON.stringify(result.errors)}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const v3RootConfig = result.data.me.getProductsConfigByVersion?.v_three_config?.values;
|
|
159
|
+
const frontendValues = result.data.me.getProductsConfigByVersion?.frontend?.values;
|
|
160
|
+
|
|
161
|
+
if (!v3RootConfig?.colors) {
|
|
162
|
+
logger.logDebug('fetchGraphQLConfig | No colors found, returning mock config');
|
|
163
|
+
return {
|
|
164
|
+
colorsConfig: mockV3ColorsConfig,
|
|
165
|
+
frontendConfig: mockV3FrontendConfig as FrontendConfigV3Response,
|
|
166
|
+
orgPageConfig: {
|
|
167
|
+
pageVariants: DEFAULT_PAGE_VARIANTS,
|
|
168
|
+
widgetConfigs: {},
|
|
169
|
+
mountingConfigs: {},
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const v3FrontendConfig = v3FrontendConfigCleanup(
|
|
175
|
+
transformSnakeToCamel(v3RootConfig) as FrontendConfigV3Response,
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
const merchantOverrideCss =
|
|
179
|
+
v3FrontendConfig.uiConfigs?.merchantOverrideCss || frontendValues?.merchant_override_css;
|
|
180
|
+
|
|
181
|
+
const v3MountingConfigsArray = (transformSnakeToCamel(v3RootConfig?.mounting_configs) ??
|
|
182
|
+
[]) as unknown as { key: string; config: WidgetMountingConfig }[];
|
|
183
|
+
const v3MountingConfigs = v3MountingConfigsArray.reduce(
|
|
184
|
+
(acc, { key, config }) => {
|
|
185
|
+
acc[key] = validateAndTransformMountingConfig(config, key);
|
|
186
|
+
return acc;
|
|
187
|
+
},
|
|
188
|
+
{} as Record<string, WidgetMountingConfig>,
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const v3widgetConfigsArray = (transformSnakeToCamel(v3RootConfig?.widget_configs) ??
|
|
192
|
+
[]) as unknown as WidgetConfigV3[];
|
|
193
|
+
const v3WidgetConfigs = Object.fromEntries(
|
|
194
|
+
v3widgetConfigsArray?.map(({ widgetConfigId, ...rest }: WidgetConfigV3) => [
|
|
195
|
+
widgetConfigId,
|
|
196
|
+
{ widgetConfigId, ...rest } as WidgetConfigV3,
|
|
197
|
+
]),
|
|
198
|
+
) as Record<string, WidgetConfigV3>;
|
|
199
|
+
|
|
200
|
+
const v3pageVariants: PageVariantConfig[] = Array.isArray(v3RootConfig?.page_variants)
|
|
201
|
+
? v3RootConfig.page_variants.map(validateAndTransformPageVariants)
|
|
202
|
+
: DEFAULT_PAGE_VARIANTS;
|
|
203
|
+
|
|
204
|
+
const v3ColorsConfig = transformSnakeToCamel(v3RootConfig?.colors?.values);
|
|
205
|
+
|
|
206
|
+
logger.logDebug('fetchGraphQLConfig | Returning v3 config');
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
colorsConfig: v3ColorsConfig as ColorsConfigV3Response,
|
|
210
|
+
frontendConfig: {
|
|
211
|
+
...(v3FrontendConfig as FrontendConfigV3Response),
|
|
212
|
+
merchantOverrideCss,
|
|
213
|
+
widgetConfigs: v3WidgetConfigs,
|
|
214
|
+
},
|
|
215
|
+
orgPageConfig: {
|
|
216
|
+
pageVariants: v3pageVariants,
|
|
217
|
+
widgetConfigs: v3WidgetConfigs,
|
|
218
|
+
mountingConfigs: v3MountingConfigs,
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
} catch (err) {
|
|
222
|
+
logger.logError('fetchGraphQLConfig | Error fetching GraphQL config', err);
|
|
223
|
+
return { colorsConfig: undefined, frontendConfig: undefined };
|
|
224
|
+
}
|
|
225
|
+
};
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import { HardcopyService, MockHardcopyService, MOCK_HARDCOPY_RESPONSE } from '../hardcopyService';
|
|
2
|
+
import { WidgetTypeV3 } from 'src/contexts/typesV3';
|
|
3
|
+
import type { WidgetText } from 'src/application/models/api/widgetText';
|
|
4
|
+
import type { AppDetails } from 'src/atoms/app';
|
|
5
|
+
import { EnviveMetricsEventName } from 'src/services/amplitudeService';
|
|
6
|
+
|
|
7
|
+
const { MockLogger, mockGetHardcopy, mockGetQueryParam } = vi.hoisted(() => {
|
|
8
|
+
const MockLogger = vi.fn(function () {
|
|
9
|
+
return { logDebug: vi.fn(), logError: vi.fn() };
|
|
10
|
+
});
|
|
11
|
+
const mockGetHardcopy = vi.fn();
|
|
12
|
+
const mockGetQueryParam = vi.fn().mockReturnValue(null);
|
|
13
|
+
return { MockLogger, mockGetHardcopy, mockGetQueryParam };
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
vi.mock('src/application/logging/logger', () => ({ default: MockLogger }));
|
|
17
|
+
vi.mock('src/application/commerce-api', () => ({
|
|
18
|
+
default: { getHardcopy: mockGetHardcopy },
|
|
19
|
+
}));
|
|
20
|
+
vi.mock('src/application/utils', () => ({ getQueryParam: mockGetQueryParam }));
|
|
21
|
+
vi.mock('uuid', () => ({ v4: () => 'test-uuid' }));
|
|
22
|
+
|
|
23
|
+
const mockAppDetails: AppDetails = {
|
|
24
|
+
orgId: 'org-1',
|
|
25
|
+
orgShortName: 'test-org',
|
|
26
|
+
chatId: 'chat-1',
|
|
27
|
+
userId: 'user-1',
|
|
28
|
+
source: 'app_block' as any,
|
|
29
|
+
env: 'dev' as any,
|
|
30
|
+
variantInfo: {} as any,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const makeService = (trackEvent = vi.fn()) =>
|
|
34
|
+
new HardcopyService({
|
|
35
|
+
getAppDetails: () => mockAppDetails,
|
|
36
|
+
getFeatureFlags: () => ({ flag_a: true }),
|
|
37
|
+
trackEvent,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const makeWidgetTextResponse = (overrides: Partial<WidgetText> = {}): WidgetText => ({
|
|
41
|
+
responseId: 'resp-1',
|
|
42
|
+
requestId: 'req-1',
|
|
43
|
+
language: 'en',
|
|
44
|
+
values: {
|
|
45
|
+
title_label: [{ id: 'id1', value: 'Hello World' }],
|
|
46
|
+
prompt_button_texts: [
|
|
47
|
+
{ id: 'id2', value: 'Prompt 1' },
|
|
48
|
+
{ id: 'id3', value: 'Prompt 2' },
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
...overrides,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
vi.clearAllMocks();
|
|
56
|
+
mockGetQueryParam.mockReturnValue(null);
|
|
57
|
+
Object.defineProperty(navigator, 'languages', {
|
|
58
|
+
value: ['en-US'],
|
|
59
|
+
configurable: true,
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('HardcopyService', () => {
|
|
64
|
+
describe('successful API response', () => {
|
|
65
|
+
it('returns a converted HardcopyResponse with camelCased keys', async () => {
|
|
66
|
+
mockGetHardcopy.mockResolvedValueOnce(makeWidgetTextResponse());
|
|
67
|
+
|
|
68
|
+
const result = await makeService().getHardcopy({
|
|
69
|
+
widgetType: WidgetTypeV3.PromptCarouselV3,
|
|
70
|
+
userEvent: {} as any,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
expect(result).toEqual({
|
|
74
|
+
responseId: 'resp-1',
|
|
75
|
+
language: 'en',
|
|
76
|
+
rawValues: {
|
|
77
|
+
title_label: [{ id: 'id1', value: 'Hello World' }],
|
|
78
|
+
prompt_button_texts: [
|
|
79
|
+
{ id: 'id2', value: 'Prompt 1' },
|
|
80
|
+
{ id: 'id3', value: 'Prompt 2' },
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
values: {
|
|
84
|
+
titleLabel: 'Hello World',
|
|
85
|
+
promptButtonTexts: ['Prompt 1', 'Prompt 2'],
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('unwraps a single-element array to a scalar string', async () => {
|
|
91
|
+
mockGetHardcopy.mockResolvedValueOnce(
|
|
92
|
+
makeWidgetTextResponse({
|
|
93
|
+
values: { single_key: [{ id: 'x', value: 'only one' }] },
|
|
94
|
+
}),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const result = await makeService().getHardcopy({
|
|
98
|
+
widgetType: WidgetTypeV3.PromptCarouselV3,
|
|
99
|
+
userEvent: {} as any,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
expect(result.values.singleKey).toBe('only one');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('keeps a multi-element array as an array of strings', async () => {
|
|
106
|
+
mockGetHardcopy.mockResolvedValueOnce(
|
|
107
|
+
makeWidgetTextResponse({
|
|
108
|
+
values: {
|
|
109
|
+
items: [
|
|
110
|
+
{ id: 'a', value: 'first' },
|
|
111
|
+
{ id: 'b', value: 'second' },
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const result = await makeService().getHardcopy({
|
|
118
|
+
widgetType: WidgetTypeV3.PromptCarouselV3,
|
|
119
|
+
userEvent: {} as any,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
expect(result.values.items).toEqual(['first', 'second']);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
describe('request construction', () => {
|
|
127
|
+
it('calls CommerceApiClient.getHardcopy with the expected request shape', async () => {
|
|
128
|
+
mockGetHardcopy.mockResolvedValueOnce(makeWidgetTextResponse());
|
|
129
|
+
|
|
130
|
+
await makeService().getHardcopy({
|
|
131
|
+
widgetType: WidgetTypeV3.ChatPreviewV3,
|
|
132
|
+
userEvent: {} as any,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(mockGetHardcopy).toHaveBeenCalledWith(
|
|
136
|
+
expect.objectContaining({
|
|
137
|
+
requestId: 'test-uuid',
|
|
138
|
+
widgetType: WidgetTypeV3.ChatPreviewV3,
|
|
139
|
+
context: mockAppDetails,
|
|
140
|
+
featureFlags: { flag_a: true },
|
|
141
|
+
language: 'en-US',
|
|
142
|
+
url: globalThis.location.href,
|
|
143
|
+
overrideConfigVersion: undefined,
|
|
144
|
+
}),
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('reads overrideConfigVersion from the spiffy_config_version query param', async () => {
|
|
149
|
+
mockGetQueryParam.mockImplementation((key: string) =>
|
|
150
|
+
key === 'spiffy_config_version' ? 'v2' : null,
|
|
151
|
+
);
|
|
152
|
+
mockGetHardcopy.mockResolvedValueOnce(makeWidgetTextResponse());
|
|
153
|
+
|
|
154
|
+
await makeService().getHardcopy({
|
|
155
|
+
widgetType: WidgetTypeV3.PromptCarouselV3,
|
|
156
|
+
userEvent: {} as any,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
expect(mockGetHardcopy).toHaveBeenCalledWith(
|
|
160
|
+
expect.objectContaining({ overrideConfigVersion: 'v2' }),
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('falls back to envive_config_version when spiffy_config_version is absent', async () => {
|
|
165
|
+
mockGetQueryParam.mockImplementation((key: string) =>
|
|
166
|
+
key === 'envive_config_version' ? 'v3' : null,
|
|
167
|
+
);
|
|
168
|
+
mockGetHardcopy.mockResolvedValueOnce(makeWidgetTextResponse());
|
|
169
|
+
|
|
170
|
+
await makeService().getHardcopy({
|
|
171
|
+
widgetType: WidgetTypeV3.PromptCarouselV3,
|
|
172
|
+
userEvent: {} as any,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
expect(mockGetHardcopy).toHaveBeenCalledWith(
|
|
176
|
+
expect.objectContaining({ overrideConfigVersion: 'v3' }),
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('uses the first navigator language as the request language', async () => {
|
|
181
|
+
Object.defineProperty(navigator, 'languages', {
|
|
182
|
+
value: ['fr-FR', 'en-US'],
|
|
183
|
+
configurable: true,
|
|
184
|
+
});
|
|
185
|
+
mockGetHardcopy.mockResolvedValueOnce(makeWidgetTextResponse());
|
|
186
|
+
|
|
187
|
+
await makeService().getHardcopy({
|
|
188
|
+
widgetType: WidgetTypeV3.PromptCarouselV3,
|
|
189
|
+
userEvent: {} as any,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
expect(mockGetHardcopy).toHaveBeenCalledWith(expect.objectContaining({ language: 'fr-FR' }));
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe('analytics events', () => {
|
|
197
|
+
it('fires WidgetTextRequest before calling the API', async () => {
|
|
198
|
+
const trackEvent = vi.fn();
|
|
199
|
+
mockGetHardcopy.mockResolvedValueOnce(makeWidgetTextResponse());
|
|
200
|
+
|
|
201
|
+
await makeService(trackEvent).getHardcopy({
|
|
202
|
+
widgetType: WidgetTypeV3.ChatPreviewV3,
|
|
203
|
+
userEvent: {} as any,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
expect(trackEvent).toHaveBeenCalledWith(
|
|
207
|
+
expect.objectContaining({
|
|
208
|
+
eventName: EnviveMetricsEventName.WidgetTextRequest,
|
|
209
|
+
eventProps: expect.objectContaining({
|
|
210
|
+
widget_type: WidgetTypeV3.ChatPreviewV3,
|
|
211
|
+
request_id: 'test-uuid',
|
|
212
|
+
}),
|
|
213
|
+
}),
|
|
214
|
+
);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('fires WidgetTextResponse after a successful API call', async () => {
|
|
218
|
+
const trackEvent = vi.fn();
|
|
219
|
+
const response = makeWidgetTextResponse();
|
|
220
|
+
mockGetHardcopy.mockResolvedValueOnce(response);
|
|
221
|
+
|
|
222
|
+
await makeService(trackEvent).getHardcopy({
|
|
223
|
+
widgetType: WidgetTypeV3.ChatPreviewV3,
|
|
224
|
+
userEvent: {} as any,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
expect(trackEvent).toHaveBeenCalledWith(
|
|
228
|
+
expect.objectContaining({
|
|
229
|
+
eventName: EnviveMetricsEventName.WidgetTextResponse,
|
|
230
|
+
eventProps: expect.objectContaining({
|
|
231
|
+
widget_type: WidgetTypeV3.ChatPreviewV3,
|
|
232
|
+
response_id: 'resp-1',
|
|
233
|
+
}),
|
|
234
|
+
}),
|
|
235
|
+
);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('does not crash when trackEvent is not provided', async () => {
|
|
239
|
+
const service = new HardcopyService({
|
|
240
|
+
getAppDetails: () => mockAppDetails,
|
|
241
|
+
getFeatureFlags: () => ({}),
|
|
242
|
+
});
|
|
243
|
+
mockGetHardcopy.mockResolvedValueOnce(makeWidgetTextResponse());
|
|
244
|
+
|
|
245
|
+
await expect(
|
|
246
|
+
service.getHardcopy({ widgetType: WidgetTypeV3.ChatPreviewV3, userEvent: {} as any }),
|
|
247
|
+
).resolves.toBeDefined();
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe('fallback behaviour', () => {
|
|
252
|
+
it('returns the MOCK_HARDCOPY_RESPONSE entry when the API throws', async () => {
|
|
253
|
+
mockGetHardcopy.mockRejectedValueOnce(new Error('Network error'));
|
|
254
|
+
|
|
255
|
+
const result = await makeService().getHardcopy({
|
|
256
|
+
widgetType: WidgetTypeV3.PromptCarouselV3,
|
|
257
|
+
userEvent: {} as any,
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
expect(result).toBe(MOCK_HARDCOPY_RESPONSE[WidgetTypeV3.PromptCarouselV3]);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('returns the MOCK_HARDCOPY_RESPONSE entry when the API returns falsy', async () => {
|
|
264
|
+
mockGetHardcopy.mockResolvedValueOnce(null);
|
|
265
|
+
|
|
266
|
+
const result = await makeService().getHardcopy({
|
|
267
|
+
widgetType: WidgetTypeV3.SocialProofV3,
|
|
268
|
+
userEvent: {} as any,
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
expect(result).toBe(MOCK_HARDCOPY_RESPONSE[WidgetTypeV3.SocialProofV3]);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('does not fire WidgetTextResponse when falling back to mock', async () => {
|
|
275
|
+
const trackEvent = vi.fn();
|
|
276
|
+
mockGetHardcopy.mockRejectedValueOnce(new Error('fail'));
|
|
277
|
+
|
|
278
|
+
await makeService(trackEvent).getHardcopy({
|
|
279
|
+
widgetType: WidgetTypeV3.PromptCarouselV3,
|
|
280
|
+
userEvent: {} as any,
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const responseEvents = trackEvent.mock.calls.filter(
|
|
284
|
+
([p]: [{ eventName: string }]) => p.eventName === EnviveMetricsEventName.WidgetTextResponse,
|
|
285
|
+
);
|
|
286
|
+
expect(responseEvents).toHaveLength(0);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('throws when the API fails and there is no mock entry for the widget type', async () => {
|
|
290
|
+
mockGetHardcopy.mockRejectedValueOnce(new Error('fail'));
|
|
291
|
+
|
|
292
|
+
await expect(
|
|
293
|
+
makeService().getHardcopy({
|
|
294
|
+
widgetType: 'UnknownWidget' as WidgetTypeV3,
|
|
295
|
+
userEvent: {} as any,
|
|
296
|
+
}),
|
|
297
|
+
).rejects.toThrow('No hardcopy response found for widget type: UnknownWidget');
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
describe('MockHardcopyService', () => {
|
|
303
|
+
it('returns the override for the requested widget type', async () => {
|
|
304
|
+
const override = { responseId: 'override', language: 'fr', values: { label: 'Bonjour' } };
|
|
305
|
+
const service = new MockHardcopyService({
|
|
306
|
+
[WidgetTypeV3.ChatPreviewV3]: override,
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
const result = await service.getHardcopy({
|
|
310
|
+
widgetType: WidgetTypeV3.ChatPreviewV3,
|
|
311
|
+
userEvent: {} as any,
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
expect(result).toBe(override);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('falls back to MOCK_HARDCOPY_RESPONSE when no override is set', async () => {
|
|
318
|
+
const service = new MockHardcopyService();
|
|
319
|
+
|
|
320
|
+
const result = await service.getHardcopy({
|
|
321
|
+
widgetType: WidgetTypeV3.SocialProofV3,
|
|
322
|
+
userEvent: {} as any,
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
expect(result).toBe(MOCK_HARDCOPY_RESPONSE[WidgetTypeV3.SocialProofV3]);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('uses the ImagePromptCardV3 override as a fallback for ProductCardV3', async () => {
|
|
329
|
+
const fallback = {
|
|
330
|
+
responseId: 'fallback',
|
|
331
|
+
language: 'en',
|
|
332
|
+
values: { headline: 'fallback headline' },
|
|
333
|
+
};
|
|
334
|
+
const service = new MockHardcopyService({
|
|
335
|
+
[WidgetTypeV3.ImagePromptCardV3]: fallback,
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
const result = await service.getHardcopy({
|
|
339
|
+
widgetType: WidgetTypeV3.ProductCardV3,
|
|
340
|
+
userEvent: {} as any,
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
expect(result).toBe(fallback);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('throws when neither override nor MOCK_HARDCOPY_RESPONSE has an entry', async () => {
|
|
347
|
+
const service = new MockHardcopyService();
|
|
348
|
+
|
|
349
|
+
await expect(
|
|
350
|
+
service.getHardcopy({
|
|
351
|
+
widgetType: 'UnknownWidget' as WidgetTypeV3,
|
|
352
|
+
userEvent: {} as any,
|
|
353
|
+
}),
|
|
354
|
+
).rejects.toThrow('No hardcopy response found for widget type: UnknownWidget');
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('uses no overrides by default', async () => {
|
|
358
|
+
const service = new MockHardcopyService();
|
|
359
|
+
|
|
360
|
+
const result = await service.getHardcopy({
|
|
361
|
+
widgetType: WidgetTypeV3.TypingAnimationV3,
|
|
362
|
+
userEvent: {} as any,
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
expect(result).toBe(MOCK_HARDCOPY_RESPONSE[WidgetTypeV3.TypingAnimationV3]);
|
|
366
|
+
});
|
|
367
|
+
});
|