@capillarytech/creatives-library 8.0.304 → 8.0.306
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/constants/unified.js +1 -0
- package/package.json +1 -1
- package/utils/common.js +7 -1
- package/v2Components/CapDeviceContent/index.js +10 -7
- package/v2Components/FormBuilder/index.js +1 -1
- package/v2Components/HtmlEditor/HTMLEditor.js +1 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1 -0
- package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +132 -3
- package/v2Components/HtmlEditor/hooks/useValidation.js +12 -9
- package/v2Components/HtmlEditor/utils/htmlValidator.js +4 -2
- package/v2Containers/BeePopupEditor/index.js +9 -2
- package/v2Containers/CreativesContainer/SlideBoxContent.js +35 -3
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +69 -1
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +121 -4
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +2 -2
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +110 -18
- package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +110 -155
- package/v2Containers/InApp/index.js +183 -14
- package/v2Containers/InApp/tests/mockData.js +1 -1
- package/v2Containers/InappAdvance/index.js +7 -0
- package/v2Containers/MobilePushNew/index.js +7 -0
- package/v2Containers/SmsTrai/Edit/index.js +7 -0
package/constants/unified.js
CHANGED
|
@@ -45,6 +45,7 @@ export const GIFT_CARDS = 'GIFT_CARDS';
|
|
|
45
45
|
export const PROMO_ENGINE = 'PROMO_ENGINE';
|
|
46
46
|
export const LIQUID_SUPPORT = 'ENABLE_LIQUID_SUPPORT';
|
|
47
47
|
export const ENABLE_NEW_MPUSH = 'ENABLE_NEW_MPUSH';
|
|
48
|
+
export const ENABLE_NEW_EDITOR_FLOW_INAPP = 'ENABLE_NEW_EDITOR_FLOW_INAPP';
|
|
48
49
|
export const SUPPORT_CK_EDITOR = 'SUPPORT_CK_EDITOR';
|
|
49
50
|
export const CUSTOM_TAG = 'CustomTagMessage';
|
|
50
51
|
export const CUSTOMER_EXTENDED_FIELD = 'Customer extended fields';
|
package/package.json
CHANGED
package/utils/common.js
CHANGED
|
@@ -24,7 +24,8 @@ import {
|
|
|
24
24
|
ENABLE_WEBPUSH,
|
|
25
25
|
LIQUID_SUPPORT,
|
|
26
26
|
SUPPORT_CK_EDITOR,
|
|
27
|
-
ENABLE_NEW_MPUSH
|
|
27
|
+
ENABLE_NEW_MPUSH,
|
|
28
|
+
ENABLE_NEW_EDITOR_FLOW_INAPP
|
|
28
29
|
} from '../constants/unified';
|
|
29
30
|
import { apiMessageFormatHandler } from './commonUtils';
|
|
30
31
|
|
|
@@ -142,6 +143,11 @@ export const hasNewMobilePushFeatureEnabled = Auth.hasFeatureAccess.bind(
|
|
|
142
143
|
ENABLE_NEW_MPUSH,
|
|
143
144
|
);
|
|
144
145
|
|
|
146
|
+
export const hasNewEditorFlowInAppEnabled = Auth.hasFeatureAccess.bind(
|
|
147
|
+
null,
|
|
148
|
+
ENABLE_NEW_EDITOR_FLOW_INAPP,
|
|
149
|
+
);
|
|
150
|
+
|
|
145
151
|
//filtering tags based on scope
|
|
146
152
|
export const filterTags = (tagsToFilter, tagsList) => tagsList?.filter(
|
|
147
153
|
(tag) => !tagsToFilter?.includes(tag?.definition?.value)
|
|
@@ -63,6 +63,7 @@ const CapDeviceContent = (props) => {
|
|
|
63
63
|
deepLinkValue,
|
|
64
64
|
setDeepLinkValue,
|
|
65
65
|
onCopyTitleAndContent,
|
|
66
|
+
isOtherDeviceSupported,
|
|
66
67
|
tags,
|
|
67
68
|
onTagSelect,
|
|
68
69
|
handleOnTagsContextChange,
|
|
@@ -167,13 +168,15 @@ const CapDeviceContent = (props) => {
|
|
|
167
168
|
return (
|
|
168
169
|
<>
|
|
169
170
|
<CapRow className="creatives-device-content">
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
171
|
+
{isOtherDeviceSupported && (
|
|
172
|
+
<CapLink
|
|
173
|
+
title={isAndroid
|
|
174
|
+
? formatMessage(messages.copyContentFromIOS)
|
|
175
|
+
: formatMessage(messages.copyCotentFromAndroid)}
|
|
176
|
+
className="inapp-copy-content"
|
|
177
|
+
onClick={onCopyTitleAndContent}
|
|
178
|
+
/>
|
|
179
|
+
)}
|
|
177
180
|
<CapRow className="creatives-inapp-title">
|
|
178
181
|
<CapColumn
|
|
179
182
|
className="inapp-content-main"
|
|
@@ -1331,7 +1331,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1331
1331
|
}
|
|
1332
1332
|
onSubmitWrapper = (args) => {
|
|
1333
1333
|
const {singleTab = null} = args || {};
|
|
1334
|
-
if (this.liquidFlow()) {
|
|
1334
|
+
if (this.liquidFlow() && !this.props?.isFullMode) {
|
|
1335
1335
|
// For MPUSH, we need to validate both Android and iOS content separately
|
|
1336
1336
|
if (this.props.channel === MOBILE_PUSH || this.props?.schema?.channel?.toUpperCase() === MOBILE_PUSH) {
|
|
1337
1337
|
this.validateFormBuilderMPush(this.state.formData, singleTab);
|
|
@@ -294,6 +294,7 @@ const HTMLEditor = forwardRef(({
|
|
|
294
294
|
enableSanitization: true,
|
|
295
295
|
securityLevel: 'standard',
|
|
296
296
|
apiValidationErrors, // Pass API validation errors to merge with client-side validation
|
|
297
|
+
isFullMode, // Skip liquid validation in standalone/full mode
|
|
297
298
|
}, formatSanitizerMessage, formatValidatorMessage);
|
|
298
299
|
|
|
299
300
|
// Expose validation and content state via ref
|
|
@@ -155,7 +155,7 @@ describe('useValidation', () => {
|
|
|
155
155
|
await Promise.resolve();
|
|
156
156
|
});
|
|
157
157
|
|
|
158
|
-
expect(validateHTML).toHaveBeenCalledWith('<p>Test</p>', 'email', null);
|
|
158
|
+
expect(validateHTML).toHaveBeenCalledWith('<p>Test</p>', 'email', null, { skipLiquidValidation: false });
|
|
159
159
|
});
|
|
160
160
|
|
|
161
161
|
it('updates validation when content changes', async () => {
|
|
@@ -472,7 +472,7 @@ describe('useValidation', () => {
|
|
|
472
472
|
await Promise.resolve();
|
|
473
473
|
});
|
|
474
474
|
|
|
475
|
-
expect(validateHTML).toHaveBeenCalledWith('<p>Test</p>', 'inapp', null);
|
|
475
|
+
expect(validateHTML).toHaveBeenCalledWith('<p>Test</p>', 'inapp', null, { skipLiquidValidation: false });
|
|
476
476
|
});
|
|
477
477
|
|
|
478
478
|
it('defaults to email variant', async () => {
|
|
@@ -487,7 +487,7 @@ describe('useValidation', () => {
|
|
|
487
487
|
await Promise.resolve();
|
|
488
488
|
});
|
|
489
489
|
|
|
490
|
-
expect(validateHTML).toHaveBeenCalledWith('<p>Test</p>', 'email', null);
|
|
490
|
+
expect(validateHTML).toHaveBeenCalledWith('<p>Test</p>', 'email', null, { skipLiquidValidation: false });
|
|
491
491
|
});
|
|
492
492
|
});
|
|
493
493
|
|
|
@@ -1242,4 +1242,133 @@ describe('useValidation', () => {
|
|
|
1242
1242
|
});
|
|
1243
1243
|
});
|
|
1244
1244
|
});
|
|
1245
|
+
|
|
1246
|
+
describe('isFullMode - skip liquid validation', () => {
|
|
1247
|
+
it('passes skipLiquidValidation: true to validateHTML when isFullMode is true', async () => {
|
|
1248
|
+
const { validateHTML } = require('../../utils/htmlValidator');
|
|
1249
|
+
|
|
1250
|
+
render(<TestComponent content="<p>Test</p>" options={{ isFullMode: true }} />);
|
|
1251
|
+
|
|
1252
|
+
await act(async () => {
|
|
1253
|
+
jest.advanceTimersByTime(500);
|
|
1254
|
+
await Promise.resolve();
|
|
1255
|
+
await Promise.resolve();
|
|
1256
|
+
await Promise.resolve();
|
|
1257
|
+
});
|
|
1258
|
+
|
|
1259
|
+
expect(validateHTML).toHaveBeenCalledWith('<p>Test</p>', 'email', null, { skipLiquidValidation: true });
|
|
1260
|
+
});
|
|
1261
|
+
|
|
1262
|
+
it('excludes API liquid errors from getAllIssues when isFullMode is true', async () => {
|
|
1263
|
+
let validationState;
|
|
1264
|
+
const onStateChange = (state) => { validationState = state; };
|
|
1265
|
+
|
|
1266
|
+
const apiValidationErrors = {
|
|
1267
|
+
liquidErrors: ['Unsupported tag: points_balance'],
|
|
1268
|
+
standardErrors: [],
|
|
1269
|
+
};
|
|
1270
|
+
|
|
1271
|
+
render(
|
|
1272
|
+
<TestComponent
|
|
1273
|
+
content="<p>Test</p>"
|
|
1274
|
+
options={{ apiValidationErrors, isFullMode: true }}
|
|
1275
|
+
onStateChange={onStateChange}
|
|
1276
|
+
/>
|
|
1277
|
+
);
|
|
1278
|
+
|
|
1279
|
+
await act(async () => {
|
|
1280
|
+
jest.advanceTimersByTime(500);
|
|
1281
|
+
await Promise.resolve();
|
|
1282
|
+
await Promise.resolve();
|
|
1283
|
+
await Promise.resolve();
|
|
1284
|
+
});
|
|
1285
|
+
|
|
1286
|
+
await waitFor(() => {
|
|
1287
|
+
expect(validationState).toBeDefined();
|
|
1288
|
+
});
|
|
1289
|
+
|
|
1290
|
+
const issues = validationState.getAllIssues();
|
|
1291
|
+
const liquidIssues = issues.filter((i) => i.source === 'liquid-validator');
|
|
1292
|
+
expect(liquidIssues).toHaveLength(0);
|
|
1293
|
+
});
|
|
1294
|
+
|
|
1295
|
+
it('returns isClean true when only liquid errors exist and isFullMode is true', () => {
|
|
1296
|
+
const apiValidationErrors = {
|
|
1297
|
+
liquidErrors: ['Unsupported tag: points_balance'],
|
|
1298
|
+
standardErrors: [],
|
|
1299
|
+
};
|
|
1300
|
+
|
|
1301
|
+
render(
|
|
1302
|
+
<TestComponent
|
|
1303
|
+
content=""
|
|
1304
|
+
options={{ apiValidationErrors, isFullMode: true }}
|
|
1305
|
+
/>
|
|
1306
|
+
);
|
|
1307
|
+
|
|
1308
|
+
// Before validation runs, isClean should be true because liquid errors are ignored in full mode
|
|
1309
|
+
expect(screen.getByTestId('is-clean')).toHaveTextContent('true');
|
|
1310
|
+
});
|
|
1311
|
+
|
|
1312
|
+
it('does not treat liquid errors as blocking when isFullMode is true', async () => {
|
|
1313
|
+
let validationState;
|
|
1314
|
+
const onStateChange = (state) => { validationState = state; };
|
|
1315
|
+
|
|
1316
|
+
const apiValidationErrors = {
|
|
1317
|
+
liquidErrors: ['Unsupported tag: points_balance'],
|
|
1318
|
+
standardErrors: [],
|
|
1319
|
+
};
|
|
1320
|
+
|
|
1321
|
+
render(
|
|
1322
|
+
<TestComponent
|
|
1323
|
+
content="<p>Valid</p>"
|
|
1324
|
+
options={{ apiValidationErrors, isFullMode: true }}
|
|
1325
|
+
onStateChange={onStateChange}
|
|
1326
|
+
/>
|
|
1327
|
+
);
|
|
1328
|
+
|
|
1329
|
+
await act(async () => {
|
|
1330
|
+
jest.advanceTimersByTime(500);
|
|
1331
|
+
await Promise.resolve();
|
|
1332
|
+
await Promise.resolve();
|
|
1333
|
+
await Promise.resolve();
|
|
1334
|
+
});
|
|
1335
|
+
|
|
1336
|
+
await waitFor(() => {
|
|
1337
|
+
expect(validationState).toBeDefined();
|
|
1338
|
+
});
|
|
1339
|
+
|
|
1340
|
+
expect(validationState.hasBlockingErrors).toBe(false);
|
|
1341
|
+
});
|
|
1342
|
+
|
|
1343
|
+
it('still treats standard API errors as blocking when isFullMode is true', async () => {
|
|
1344
|
+
let validationState;
|
|
1345
|
+
const onStateChange = (state) => { validationState = state; };
|
|
1346
|
+
|
|
1347
|
+
const apiValidationErrors = {
|
|
1348
|
+
liquidErrors: ['Liquid error'],
|
|
1349
|
+
standardErrors: ['Standard error'],
|
|
1350
|
+
};
|
|
1351
|
+
|
|
1352
|
+
render(
|
|
1353
|
+
<TestComponent
|
|
1354
|
+
content="<p>Valid</p>"
|
|
1355
|
+
options={{ apiValidationErrors, isFullMode: true }}
|
|
1356
|
+
onStateChange={onStateChange}
|
|
1357
|
+
/>
|
|
1358
|
+
);
|
|
1359
|
+
|
|
1360
|
+
await act(async () => {
|
|
1361
|
+
jest.advanceTimersByTime(500);
|
|
1362
|
+
await Promise.resolve();
|
|
1363
|
+
await Promise.resolve();
|
|
1364
|
+
await Promise.resolve();
|
|
1365
|
+
});
|
|
1366
|
+
|
|
1367
|
+
await waitFor(() => {
|
|
1368
|
+
expect(validationState).toBeDefined();
|
|
1369
|
+
});
|
|
1370
|
+
|
|
1371
|
+
expect(validationState.hasBlockingErrors).toBe(true);
|
|
1372
|
+
});
|
|
1373
|
+
});
|
|
1245
1374
|
});
|
|
@@ -77,6 +77,7 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
77
77
|
enableSanitization = true,
|
|
78
78
|
securityLevel = 'standard',
|
|
79
79
|
apiValidationErrors = null, // API validation errors from validateLiquidTemplateContent
|
|
80
|
+
isFullMode = false, // When true, skip liquid validation (standalone/full mode)
|
|
80
81
|
} = options;
|
|
81
82
|
|
|
82
83
|
// Validation state
|
|
@@ -137,7 +138,7 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
137
138
|
|
|
138
139
|
try {
|
|
139
140
|
// 1. HTML Validation
|
|
140
|
-
const htmlValidation = validateHTML(htmlContent, variant, formatValidatorMessage);
|
|
141
|
+
const htmlValidation = validateHTML(htmlContent, variant, formatValidatorMessage, { skipLiquidValidation: isFullMode });
|
|
141
142
|
|
|
142
143
|
// 2. CSS Validation (extract from HTML)
|
|
143
144
|
const cssValidation = extractAndValidateCSS(htmlContent, formatValidatorMessage);
|
|
@@ -206,7 +207,7 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
206
207
|
},
|
|
207
208
|
}));
|
|
208
209
|
}
|
|
209
|
-
}, [variant, enableSanitization, securityLevel, formatSanitizerMessage, formatValidatorMessage]);
|
|
210
|
+
}, [variant, enableSanitization, securityLevel, formatSanitizerMessage, formatValidatorMessage, isFullMode]);
|
|
210
211
|
|
|
211
212
|
/**
|
|
212
213
|
* Validates content with debouncing
|
|
@@ -339,7 +340,7 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
339
340
|
*/
|
|
340
341
|
const getAllIssues = useCallback(() => {
|
|
341
342
|
// API errors (liquid + standard) are blocking – they block Save/Update/Preview/Test
|
|
342
|
-
const apiLiquidErrors = (apiValidationErrors?.liquidErrors || []).map((errorMessage) => {
|
|
343
|
+
const apiLiquidErrors = (isFullMode ? [] : (apiValidationErrors?.liquidErrors || [])).map((errorMessage) => {
|
|
343
344
|
const extractedLine = extractLineNumberFromMessage(errorMessage);
|
|
344
345
|
return {
|
|
345
346
|
type: VALIDATION_SEVERITY.ERROR,
|
|
@@ -420,19 +421,20 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
420
421
|
|
|
421
422
|
// Ensure we always return an array
|
|
422
423
|
return Array.isArray(allIssues) ? allIssues : [];
|
|
423
|
-
}, [validationState, apiValidationErrors, extractLineNumberFromMessage, content]);
|
|
424
|
+
}, [validationState, apiValidationErrors, extractLineNumberFromMessage, content, isFullMode]);
|
|
424
425
|
|
|
425
426
|
/**
|
|
426
427
|
* Check if validation is clean (no errors or warnings)
|
|
427
428
|
* Includes API validation errors in the check
|
|
428
429
|
*/
|
|
429
430
|
const isClean = useCallback(() => {
|
|
430
|
-
const
|
|
431
|
+
const liquidErrorCount = isFullMode ? 0 : (apiValidationErrors?.liquidErrors?.length || 0);
|
|
432
|
+
const hasApiErrors = liquidErrorCount + (apiValidationErrors?.standardErrors?.length || 0) > 0;
|
|
431
433
|
return validationState.summary.totalErrors === 0
|
|
432
434
|
&& validationState.summary.totalWarnings === 0
|
|
433
435
|
&& !validationState.summary.hasSecurityIssues
|
|
434
436
|
&& !hasApiErrors;
|
|
435
|
-
}, [validationState.summary, apiValidationErrors]);
|
|
437
|
+
}, [validationState.summary, apiValidationErrors, isFullMode]);
|
|
436
438
|
|
|
437
439
|
// Effect to validate content when it changes
|
|
438
440
|
useEffect(() => {
|
|
@@ -448,11 +450,12 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
448
450
|
}
|
|
449
451
|
}, []);
|
|
450
452
|
|
|
451
|
-
const
|
|
453
|
+
const hasApiLiquidErrors = isFullMode ? false : (apiValidationErrors?.liquidErrors?.length || 0) > 0;
|
|
454
|
+
const hasApiErrors = hasApiLiquidErrors || (apiValidationErrors?.standardErrors?.length || 0) > 0;
|
|
452
455
|
|
|
453
456
|
const protocolTypes = ['JavaScript Protocol', 'Data URL', 'VBScript Protocol'];
|
|
454
|
-
// Client-side Liquid validation errors are blocking (genuine syntax errors)
|
|
455
|
-
const hasClientSideLiquidErrors = (validationState.htmlErrors || []).some((e) => e.source === ISSUE_SOURCES.LIQUID && e.severity === VALIDATION_SEVERITY.ERROR);
|
|
457
|
+
// Client-side Liquid validation errors are blocking (genuine syntax errors) - skip in full mode
|
|
458
|
+
const hasClientSideLiquidErrors = isFullMode ? false : (validationState.htmlErrors || []).some((e) => e.source === ISSUE_SOURCES.LIQUID && e.severity === VALIDATION_SEVERITY.ERROR);
|
|
456
459
|
const hasBlockingErrors = (validationState.sanitizationWarnings || []).some((w) => BLOCKING_ERROR_RULE_IDS.includes(w.rule)) || (validationState.securityIssues || []).some((s) => protocolTypes.includes(s?.type)) || hasApiErrors || hasClientSideLiquidErrors;
|
|
457
460
|
|
|
458
461
|
return {
|
|
@@ -76,7 +76,7 @@ const CUSTOM_VALIDATIONS = {
|
|
|
76
76
|
* @param {Function} formatMessage - Message formatter function for internationalization
|
|
77
77
|
* @returns {Object} Validation result with errors and warnings
|
|
78
78
|
*/
|
|
79
|
-
export const validateHTML = (html, variant = 'email', formatMessage = defaultMessageFormatter) => {
|
|
79
|
+
export const validateHTML = (html, variant = 'email', formatMessage = defaultMessageFormatter, options = {}) => {
|
|
80
80
|
if (!html || typeof html !== 'string') {
|
|
81
81
|
return {
|
|
82
82
|
isValid: true,
|
|
@@ -133,7 +133,9 @@ export const validateHTML = (html, variant = 'email', formatMessage = defaultMes
|
|
|
133
133
|
// Always run custom validations and Liquid validation, even if HTMLHint failed
|
|
134
134
|
// This ensures unsafe protocol detection and other critical validations still run
|
|
135
135
|
runCustomValidations(html, variant, results, formatMessage);
|
|
136
|
-
|
|
136
|
+
if (!options.skipLiquidValidation) {
|
|
137
|
+
runLiquidValidation(html, variant, results, formatMessage);
|
|
138
|
+
}
|
|
137
139
|
|
|
138
140
|
return results;
|
|
139
141
|
};
|
|
@@ -40,6 +40,11 @@ function BeePopupEditor(props) {
|
|
|
40
40
|
const savedCallback = useRef();
|
|
41
41
|
const beeInstanceRef = useRef(null);
|
|
42
42
|
const isInitializedRef = useRef(false);
|
|
43
|
+
const beeJsonRef = useRef(beeJson);
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
beeJsonRef.current = beeJson;
|
|
47
|
+
}, [beeJson]);
|
|
43
48
|
|
|
44
49
|
const [visibleTaglist, setVisibleTaglist] = useState(false);
|
|
45
50
|
const [selectedTag, setSelectedTag] = useState({});
|
|
@@ -111,8 +116,10 @@ function BeePopupEditor(props) {
|
|
|
111
116
|
window.BeePlugin.create(tokenData, beeConfig, (instance) => {
|
|
112
117
|
beePluginInstance = instance;
|
|
113
118
|
beeInstanceRef.current = instance;
|
|
114
|
-
//
|
|
115
|
-
|
|
119
|
+
// Use ref to get the latest beeJson — the closure captures the value at effect time,
|
|
120
|
+
// but beeJsonRef.current is always up-to-date (e.g. when template data loads async)
|
|
121
|
+
const latestBeeJson = beeJsonRef.current;
|
|
122
|
+
const parseJson = typeof latestBeeJson === 'string' ? JSON.parse(latestBeeJson) : latestBeeJson;
|
|
116
123
|
beePluginInstance.start(parseJson);
|
|
117
124
|
saveBeeInstance(beePluginInstance, device);
|
|
118
125
|
isInitializedRef.current = true;
|
|
@@ -1078,8 +1078,38 @@ export function SlideBoxContent(props) {
|
|
|
1078
1078
|
)}
|
|
1079
1079
|
|
|
1080
1080
|
{isCreateInApp && (
|
|
1081
|
-
|
|
1082
|
-
|
|
1081
|
+
(isFullMode && !commonUtil.hasNewEditorFlowInAppEnabled()) ||
|
|
1082
|
+
(!isFullMode && isLoyaltyModule) ||
|
|
1083
|
+
(!isFullMode && !isLoyaltyModule && !commonUtil.hasNewEditorFlowInAppEnabled()) ? (
|
|
1084
|
+
<InApp
|
|
1085
|
+
key="creatives-inapp-create"
|
|
1086
|
+
location={{ pathname: '/inapp/create', query, search: '' }}
|
|
1087
|
+
setIsLoadingContent={setIsLoadingContent}
|
|
1088
|
+
isGetFormData={isGetFormData}
|
|
1089
|
+
getFormData={getFormData}
|
|
1090
|
+
getDefaultTags={type}
|
|
1091
|
+
isFullMode={isFullMode}
|
|
1092
|
+
templateData={templateData}
|
|
1093
|
+
cap={cap}
|
|
1094
|
+
showTemplateName={showTemplateName}
|
|
1095
|
+
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
1096
|
+
onValidationFail={onValidationFail}
|
|
1097
|
+
forwardedTags={forwardedTags}
|
|
1098
|
+
selectedOfferDetails={selectedOfferDetails}
|
|
1099
|
+
onPreviewContentClicked={onPreviewContentClicked}
|
|
1100
|
+
onTestContentClicked={onTestContentClicked}
|
|
1101
|
+
eventContextTags={eventContextTags}
|
|
1102
|
+
onCreateComplete={onCreateComplete}
|
|
1103
|
+
handleClose={handleClose}
|
|
1104
|
+
moduleType={moduleType}
|
|
1105
|
+
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
1106
|
+
handleTestAndPreview={handleTestAndPreview}
|
|
1107
|
+
handleCloseTestAndPreview={handleCloseTestAndPreview}
|
|
1108
|
+
isTestAndPreviewMode={isTestAndPreviewMode}
|
|
1109
|
+
/>
|
|
1110
|
+
) : (
|
|
1111
|
+
<InAppWrapper
|
|
1112
|
+
key="creatives-inapp-wrapper"
|
|
1083
1113
|
date={new Date().getMilliseconds()}
|
|
1084
1114
|
setIsLoadingContent={setIsLoadingContent}
|
|
1085
1115
|
onInAppEditorTypeChange={onInAppEditorTypeChange}
|
|
@@ -1114,10 +1144,12 @@ export function SlideBoxContent(props) {
|
|
|
1114
1144
|
handleCloseTestAndPreview={handleCloseTestAndPreview}
|
|
1115
1145
|
isTestAndPreviewMode={isTestAndPreviewMode}
|
|
1116
1146
|
/>
|
|
1147
|
+
)
|
|
1117
1148
|
)}
|
|
1118
|
-
|
|
1149
|
+
|
|
1119
1150
|
{isEditInApp && (<InApp
|
|
1120
1151
|
isFullMode={isFullMode}
|
|
1152
|
+
isLoyaltyModule={isLoyaltyModule}
|
|
1121
1153
|
templateData={templateData}
|
|
1122
1154
|
getFormData={getFormData}
|
|
1123
1155
|
getDefaultTags={type}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { shallowWithIntl } from '../../../helpers/intl-enzym-test-helpers';
|
|
3
|
-
|
|
4
3
|
import { SlideBoxContent } from '../SlideBoxContent';
|
|
5
4
|
import mockdata from '../../mockdata';
|
|
6
5
|
import { templateDetailsImage, templateDetailsVideo, templateDetailsText, templateDetails_ } from '../../Viber/tests/mockData';
|
|
@@ -42,6 +41,15 @@ jest.mock('../../WebPush', () => ({
|
|
|
42
41
|
),
|
|
43
42
|
}));
|
|
44
43
|
|
|
44
|
+
jest.mock('v2Containers/InApp', () => () => <div data-test="inapp" />);
|
|
45
|
+
jest.mock('v2Containers/InAppWrapper', () => () => <div data-test="inapp-wrapper" />);
|
|
46
|
+
|
|
47
|
+
jest.mock('../../../utils/commonUtils', () => ({
|
|
48
|
+
hasNewEditorFlowInAppEnabled: jest.fn(),
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
import commonUtil from '../../../utils/commonUtils';
|
|
52
|
+
|
|
45
53
|
describe('Test SlideBoxContent container', () => {
|
|
46
54
|
const onCreateComplete = jest.fn();
|
|
47
55
|
let renderedComponent;
|
|
@@ -910,4 +918,64 @@ describe('Test SlideBoxContent container', () => {
|
|
|
910
918
|
expect(renderedComponent).toMatchSnapshot();
|
|
911
919
|
});
|
|
912
920
|
});
|
|
921
|
+
|
|
922
|
+
describe('InApp vs InAppWrapper rendering conditions', () => {
|
|
923
|
+
|
|
924
|
+
beforeEach(() => {
|
|
925
|
+
jest.clearAllMocks();
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
it('renders InAppWrapper when isFullMode=true and new editor disabled', () => {
|
|
929
|
+
commonUtil.hasNewEditorFlowInAppEnabled.mockReturnValue(false);
|
|
930
|
+
|
|
931
|
+
renderFunction(
|
|
932
|
+
'INAPP',
|
|
933
|
+
'createTemplate',
|
|
934
|
+
{ mode: 'create' },
|
|
935
|
+
{ isFullMode: true, isLoyaltyModule: false }
|
|
936
|
+
);
|
|
937
|
+
|
|
938
|
+
expect(renderedComponent).toMatchSnapshot();
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
it('renders InApp when isFullMode=false and loyalty module enabled', () => {
|
|
942
|
+
commonUtil.hasNewEditorFlowInAppEnabled.mockReturnValue(false);
|
|
943
|
+
|
|
944
|
+
renderFunction(
|
|
945
|
+
'INAPP',
|
|
946
|
+
'createTemplate',
|
|
947
|
+
{ mode: 'create' },
|
|
948
|
+
{ isFullMode: false, isLoyaltyModule: true }
|
|
949
|
+
);
|
|
950
|
+
|
|
951
|
+
expect(renderedComponent).toMatchSnapshot();
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
it('renders InApp when not full mode, not loyalty and new editor disabled', () => {
|
|
955
|
+
commonUtil.hasNewEditorFlowInAppEnabled.mockReturnValue(false);
|
|
956
|
+
|
|
957
|
+
renderFunction(
|
|
958
|
+
'INAPP',
|
|
959
|
+
'createTemplate',
|
|
960
|
+
{ mode: 'create' },
|
|
961
|
+
{ isFullMode: false, isLoyaltyModule: false }
|
|
962
|
+
);
|
|
963
|
+
|
|
964
|
+
expect(renderedComponent).toMatchSnapshot();
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
it('renders InAppWrapper when full mode and new editor enabled', () => {
|
|
968
|
+
commonUtil.hasNewEditorFlowInAppEnabled.mockReturnValue(true);
|
|
969
|
+
|
|
970
|
+
renderFunction(
|
|
971
|
+
'INAPP',
|
|
972
|
+
'createTemplate',
|
|
973
|
+
{ mode: 'create' },
|
|
974
|
+
{ isFullMode: true, isLoyaltyModule: false }
|
|
975
|
+
);
|
|
976
|
+
|
|
977
|
+
expect(renderedComponent).toMatchSnapshot();
|
|
978
|
+
});
|
|
979
|
+
|
|
980
|
+
});
|
|
913
981
|
});
|
|
@@ -202,6 +202,114 @@ exports[`Test SlideBoxContent container Email component isTestAndPreviewMode IIF
|
|
|
202
202
|
</SlideBoxContent__CreativesWrapper>
|
|
203
203
|
`;
|
|
204
204
|
|
|
205
|
+
exports[`Test SlideBoxContent container InApp vs InAppWrapper rendering conditions renders InApp when isFullMode=false and loyalty module enabled 1`] = `
|
|
206
|
+
<SlideBoxContent__CreativesWrapper>
|
|
207
|
+
<Component
|
|
208
|
+
getDefaultTags=""
|
|
209
|
+
isFullMode={false}
|
|
210
|
+
key="creatives-inapp-create"
|
|
211
|
+
location={
|
|
212
|
+
Object {
|
|
213
|
+
"pathname": "/inapp/create",
|
|
214
|
+
"query": Object {
|
|
215
|
+
"isEditFromCampaigns": undefined,
|
|
216
|
+
"module": "library",
|
|
217
|
+
"type": "embedded",
|
|
218
|
+
},
|
|
219
|
+
"search": "",
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
onCreateComplete={[MockFunction]}
|
|
223
|
+
templateData={
|
|
224
|
+
Object {
|
|
225
|
+
"mode": "create",
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/>
|
|
229
|
+
</SlideBoxContent__CreativesWrapper>
|
|
230
|
+
`;
|
|
231
|
+
|
|
232
|
+
exports[`Test SlideBoxContent container InApp vs InAppWrapper rendering conditions renders InApp when not full mode, not loyalty and new editor disabled 1`] = `
|
|
233
|
+
<SlideBoxContent__CreativesWrapper>
|
|
234
|
+
<Component
|
|
235
|
+
getDefaultTags=""
|
|
236
|
+
isFullMode={false}
|
|
237
|
+
key="creatives-inapp-create"
|
|
238
|
+
location={
|
|
239
|
+
Object {
|
|
240
|
+
"pathname": "/inapp/create",
|
|
241
|
+
"query": Object {
|
|
242
|
+
"isEditFromCampaigns": undefined,
|
|
243
|
+
"module": "library",
|
|
244
|
+
"type": "embedded",
|
|
245
|
+
},
|
|
246
|
+
"search": "",
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
onCreateComplete={[MockFunction]}
|
|
250
|
+
templateData={
|
|
251
|
+
Object {
|
|
252
|
+
"mode": "create",
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/>
|
|
256
|
+
</SlideBoxContent__CreativesWrapper>
|
|
257
|
+
`;
|
|
258
|
+
|
|
259
|
+
exports[`Test SlideBoxContent container InApp vs InAppWrapper rendering conditions renders InAppWrapper when full mode and new editor enabled 1`] = `
|
|
260
|
+
<SlideBoxContent__CreativesWrapper>
|
|
261
|
+
<Component
|
|
262
|
+
getDefaultTags=""
|
|
263
|
+
isFullMode={true}
|
|
264
|
+
key="creatives-inapp-create"
|
|
265
|
+
location={
|
|
266
|
+
Object {
|
|
267
|
+
"pathname": "/inapp/create",
|
|
268
|
+
"query": Object {
|
|
269
|
+
"isEditFromCampaigns": undefined,
|
|
270
|
+
"module": "default",
|
|
271
|
+
"type": false,
|
|
272
|
+
},
|
|
273
|
+
"search": "",
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
onCreateComplete={[MockFunction]}
|
|
277
|
+
templateData={
|
|
278
|
+
Object {
|
|
279
|
+
"mode": "create",
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/>
|
|
283
|
+
</SlideBoxContent__CreativesWrapper>
|
|
284
|
+
`;
|
|
285
|
+
|
|
286
|
+
exports[`Test SlideBoxContent container InApp vs InAppWrapper rendering conditions renders InAppWrapper when isFullMode=true and new editor disabled 1`] = `
|
|
287
|
+
<SlideBoxContent__CreativesWrapper>
|
|
288
|
+
<Component
|
|
289
|
+
getDefaultTags=""
|
|
290
|
+
isFullMode={true}
|
|
291
|
+
key="creatives-inapp-create"
|
|
292
|
+
location={
|
|
293
|
+
Object {
|
|
294
|
+
"pathname": "/inapp/create",
|
|
295
|
+
"query": Object {
|
|
296
|
+
"isEditFromCampaigns": undefined,
|
|
297
|
+
"module": "default",
|
|
298
|
+
"type": false,
|
|
299
|
+
},
|
|
300
|
+
"search": "",
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
onCreateComplete={[MockFunction]}
|
|
304
|
+
templateData={
|
|
305
|
+
Object {
|
|
306
|
+
"mode": "create",
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/>
|
|
310
|
+
</SlideBoxContent__CreativesWrapper>
|
|
311
|
+
`;
|
|
312
|
+
|
|
205
313
|
exports[`Test SlideBoxContent container Should handle isTestAndPreviewMode IIFE implementation correctly 1`] = `
|
|
206
314
|
<SlideBoxContent__CreativesWrapper>
|
|
207
315
|
<ForwardRef
|
|
@@ -1103,17 +1211,26 @@ exports[`Test SlideBoxContent container Should render correct component for what
|
|
|
1103
1211
|
|
|
1104
1212
|
exports[`Test SlideBoxContent container Should render correct component for whatsapp channel create mode 2`] = `
|
|
1105
1213
|
<SlideBoxContent__CreativesWrapper>
|
|
1106
|
-
<
|
|
1107
|
-
date={0}
|
|
1214
|
+
<Component
|
|
1108
1215
|
getDefaultTags=""
|
|
1109
|
-
key="creatives-inapp-
|
|
1216
|
+
key="creatives-inapp-create"
|
|
1217
|
+
location={
|
|
1218
|
+
Object {
|
|
1219
|
+
"pathname": "/inapp/create",
|
|
1220
|
+
"query": Object {
|
|
1221
|
+
"isEditFromCampaigns": undefined,
|
|
1222
|
+
"module": "library",
|
|
1223
|
+
"type": "embedded",
|
|
1224
|
+
},
|
|
1225
|
+
"search": "",
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1110
1228
|
onCreateComplete={[MockFunction]}
|
|
1111
1229
|
templateData={
|
|
1112
1230
|
Object {
|
|
1113
1231
|
"mode": "create",
|
|
1114
1232
|
}
|
|
1115
1233
|
}
|
|
1116
|
-
type=""
|
|
1117
1234
|
/>
|
|
1118
1235
|
</SlideBoxContent__CreativesWrapper>
|
|
1119
1236
|
`;
|