@capillarytech/creatives-library 8.0.287-alpha.3 → 8.0.288
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/initialState.js +2 -0
- package/package.json +1 -1
- package/utils/common.js +8 -5
- package/utils/commonUtils.js +111 -2
- package/utils/tagValidations.js +222 -84
- package/utils/tests/commonUtil.test.js +118 -147
- package/utils/tests/tagValidations.test.js +358 -280
- package/v2Components/CapTagList/index.js +7 -2
- package/v2Components/CapTagListWithInput/index.js +4 -0
- package/v2Components/ErrorInfoNote/index.js +5 -2
- package/v2Components/FormBuilder/index.js +187 -74
- package/v2Components/FormBuilder/messages.js +12 -0
- package/v2Components/HtmlEditor/HTMLEditor.js +5 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +15 -0
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +2 -1
- package/v2Containers/Cap/mockData.js +14 -0
- package/v2Containers/Cap/reducer.js +55 -3
- package/v2Containers/Cap/tests/reducer.test.js +102 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +20 -0
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +40 -6
- package/v2Containers/CreativesContainer/constants.js +6 -0
- package/v2Containers/CreativesContainer/index.js +36 -5
- package/v2Containers/CreativesContainer/messages.js +12 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +339 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +18 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +37 -0
- package/v2Containers/Email/index.js +5 -1
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +62 -10
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +115 -12
- package/v2Containers/FTP/index.js +51 -2
- package/v2Containers/FTP/messages.js +4 -0
- package/v2Containers/InApp/index.js +96 -1
- package/v2Containers/InApp/tests/index.test.js +6 -17
- package/v2Containers/InappAdvance/index.js +103 -2
- package/v2Containers/Line/Container/Text/index.js +1 -0
- package/v2Containers/MobilePush/Create/index.js +37 -1
- package/v2Containers/MobilePush/Create/messages.js +4 -0
- package/v2Containers/MobilePush/Edit/index.js +37 -2
- package/v2Containers/MobilePush/Edit/messages.js +4 -0
- package/v2Containers/MobilePushNew/components/PlatformContentFields.js +36 -12
- package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +68 -27
- package/v2Containers/MobilePushNew/index.js +92 -5
- package/v2Containers/MobilePushNew/messages.js +8 -0
- package/v2Containers/MobilepushWrapper/index.js +7 -1
- package/v2Containers/Rcs/index.js +37 -12
- package/v2Containers/Sms/Create/index.js +3 -31
- package/v2Containers/Sms/Create/messages.js +0 -4
- package/v2Containers/Sms/Edit/index.js +3 -29
- package/v2Containers/Sms/commonMethods.js +6 -6
- package/v2Containers/SmsTrai/Edit/index.js +47 -6
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +6 -6
- package/v2Containers/TagList/index.js +17 -1
- package/v2Containers/TagList/messages.js +4 -0
- package/v2Containers/TemplatesV2/index.js +43 -23
- package/v2Containers/Viber/index.js +1 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +3 -1
- package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +7 -0
- package/v2Containers/WebPush/Create/index.js +25 -6
- package/v2Containers/WebPush/Create/messages.js +8 -1
- package/v2Containers/WebPush/Create/utils/validation.js +20 -22
- package/v2Containers/WebPush/Create/utils/validation.test.js +52 -0
- package/v2Containers/Whatsapp/index.js +17 -9
- package/v2Containers/Zalo/index.js +11 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isValidHttpUrl } from './urlValidation';
|
|
2
2
|
import { validateTags } from '../../../../utils/tagValidations';
|
|
3
3
|
import globalMessages from '../../../Cap/messages';
|
|
4
|
+
import { hasPersonalizationTags } from '../../../../utils/commonUtils';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Validates template name (checks if empty)
|
|
@@ -10,31 +11,19 @@ import globalMessages from '../../../Cap/messages';
|
|
|
10
11
|
export const validateTemplateName = (value) => !value || value.trim() === '';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
|
-
* Validates notification title
|
|
14
|
+
* Validates notification title
|
|
14
15
|
* @param {string} value - The title value
|
|
15
16
|
* @param {Function} formatMessage - i18n format message function
|
|
16
17
|
* @param {Object} messages - Message definitions
|
|
17
|
-
* @param {Object} [validationConfig] - Optional config for tag validation
|
|
18
|
-
* @param {boolean} [isFullMode] - Optional; when set with validationConfig, runs tag validation
|
|
19
18
|
* @returns {string} Error message if invalid, empty string if valid
|
|
20
19
|
*/
|
|
21
|
-
export const validateTitle = (value, formatMessage, messages,
|
|
20
|
+
export const validateTitle = (value, formatMessage, messages, restrictPersonalization) => {
|
|
22
21
|
if (!value || value.trim() === '') {
|
|
23
22
|
return formatMessage(messages.titleRequired);
|
|
24
23
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const validationResponse = validateTags({
|
|
28
|
-
content: value,
|
|
29
|
-
...validationConfig,
|
|
30
|
-
isFullMode,
|
|
31
|
-
}) || {};
|
|
32
|
-
|
|
33
|
-
if (validationResponse?.isBraceError) {
|
|
34
|
-
return formatMessage(globalMessages.unbalanacedCurlyBraces);
|
|
35
|
-
}
|
|
24
|
+
if (restrictPersonalization && hasPersonalizationTags(value)) {
|
|
25
|
+
return formatMessage(messages.personalizationTokensErrorMessage);
|
|
36
26
|
}
|
|
37
|
-
|
|
38
27
|
return '';
|
|
39
28
|
};
|
|
40
29
|
|
|
@@ -49,11 +38,11 @@ export const validateUrl = (value, formatMessage, messages) => {
|
|
|
49
38
|
if (!value || value.trim() === '') {
|
|
50
39
|
return formatMessage(messages.urlRequired);
|
|
51
40
|
}
|
|
52
|
-
|
|
41
|
+
|
|
53
42
|
if (!isValidHttpUrl(value)) {
|
|
54
43
|
return formatMessage(messages.urlInvalid);
|
|
55
44
|
}
|
|
56
|
-
|
|
45
|
+
|
|
57
46
|
return '';
|
|
58
47
|
};
|
|
59
48
|
|
|
@@ -65,21 +54,30 @@ export const validateUrl = (value, formatMessage, messages) => {
|
|
|
65
54
|
* @param {Object} validationConfig - Configuration for tag validation
|
|
66
55
|
* @returns {string} Error message if invalid, empty string if valid
|
|
67
56
|
*/
|
|
68
|
-
export const validateMessageContent = (value, formatMessage, messages, validationConfig, isFullMode) => {
|
|
57
|
+
export const validateMessageContent = (value, formatMessage, messages, validationConfig, isFullMode, restrictPersonalization) => {
|
|
69
58
|
if (!value || value.trim() === '') {
|
|
70
59
|
return formatMessage(messages.messageRequired);
|
|
71
60
|
}
|
|
72
|
-
|
|
61
|
+
|
|
73
62
|
const validationResponse = validateTags({
|
|
74
63
|
content: value,
|
|
75
64
|
...validationConfig,
|
|
76
65
|
isFullMode,
|
|
77
66
|
}) || {};
|
|
78
67
|
|
|
68
|
+
if (validationResponse?.unsupportedTags?.length) {
|
|
69
|
+
return formatMessage(globalMessages.unsupportedTagsValidationError, {
|
|
70
|
+
unsupportedTags: validationResponse.unsupportedTags.join(', '),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
79
74
|
if (validationResponse?.isBraceError) {
|
|
80
75
|
return formatMessage(globalMessages.unbalanacedCurlyBraces);
|
|
81
76
|
}
|
|
82
|
-
|
|
77
|
+
|
|
78
|
+
if (restrictPersonalization && hasPersonalizationTags(value)) {
|
|
79
|
+
return formatMessage(messages.personalizationTokensErrorMessage);
|
|
80
|
+
}
|
|
81
|
+
|
|
83
82
|
return '';
|
|
84
83
|
};
|
|
85
|
-
|
|
@@ -44,6 +44,9 @@ describe('validation', () => {
|
|
|
44
44
|
messageRequired: {
|
|
45
45
|
defaultMessage: 'Message is required',
|
|
46
46
|
},
|
|
47
|
+
personalizationTokensErrorMessage: {
|
|
48
|
+
defaultMessage: 'Personalization tags are not supported for anonymous customers',
|
|
49
|
+
},
|
|
47
50
|
};
|
|
48
51
|
|
|
49
52
|
beforeEach(() => {
|
|
@@ -113,6 +116,17 @@ describe('validation', () => {
|
|
|
113
116
|
const result = validateTitle(' Valid Title ', mockFormatMessage, mockMessages);
|
|
114
117
|
expect(result).toBe('');
|
|
115
118
|
});
|
|
119
|
+
|
|
120
|
+
it('should return personalization error when restrictPersonalization is true and title has personalization tags', () => {
|
|
121
|
+
const result = validateTitle(
|
|
122
|
+
'Hello {{name}}',
|
|
123
|
+
mockFormatMessage,
|
|
124
|
+
mockMessages,
|
|
125
|
+
true
|
|
126
|
+
);
|
|
127
|
+
expect(result).toBe('Personalization tags are not supported for anonymous customers');
|
|
128
|
+
expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.personalizationTokensErrorMessage);
|
|
129
|
+
});
|
|
116
130
|
});
|
|
117
131
|
|
|
118
132
|
describe('validateUrl', () => {
|
|
@@ -169,8 +183,10 @@ describe('validation', () => {
|
|
|
169
183
|
describe('validateMessageContent', () => {
|
|
170
184
|
const mockValidationConfig = {
|
|
171
185
|
tagsParam: [],
|
|
186
|
+
injectedTagsParams: [],
|
|
172
187
|
location: {},
|
|
173
188
|
tagModule: '',
|
|
189
|
+
eventContextTags: [],
|
|
174
190
|
};
|
|
175
191
|
|
|
176
192
|
beforeEach(() => {
|
|
@@ -209,6 +225,17 @@ describe('validation', () => {
|
|
|
209
225
|
});
|
|
210
226
|
});
|
|
211
227
|
|
|
228
|
+
it('should return error message for unsupported tags', () => {
|
|
229
|
+
validateTags.mockReturnValue({
|
|
230
|
+
unsupportedTags: ['tag1', 'tag2'],
|
|
231
|
+
});
|
|
232
|
+
const result = validateMessageContent('Message with {tag1} and {tag2}', mockFormatMessage, mockMessages, mockValidationConfig);
|
|
233
|
+
expect(result).toBe('Unsupported tags: tag1, tag2');
|
|
234
|
+
expect(mockFormatMessage).toHaveBeenCalledWith(globalMessages.unsupportedTagsValidationError, {
|
|
235
|
+
unsupportedTags: 'tag1, tag2',
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
212
239
|
it('should return error message for unbalanced curly braces', () => {
|
|
213
240
|
validateTags.mockReturnValue({
|
|
214
241
|
isBraceError: true,
|
|
@@ -218,11 +245,22 @@ describe('validation', () => {
|
|
|
218
245
|
expect(mockFormatMessage).toHaveBeenCalledWith(globalMessages.unbalanacedCurlyBraces);
|
|
219
246
|
});
|
|
220
247
|
|
|
248
|
+
it('should return error message for both unsupported tags and brace error (unsupported tags takes precedence)', () => {
|
|
249
|
+
validateTags.mockReturnValue({
|
|
250
|
+
unsupportedTags: ['tag1'],
|
|
251
|
+
isBraceError: true,
|
|
252
|
+
});
|
|
253
|
+
const result = validateMessageContent('Message with {tag1}', mockFormatMessage, mockMessages, mockValidationConfig);
|
|
254
|
+
expect(result).toBe('Unsupported tags: tag1');
|
|
255
|
+
});
|
|
256
|
+
|
|
221
257
|
it('should pass validation config to validateTags', () => {
|
|
222
258
|
const customConfig = {
|
|
223
259
|
tagsParam: [{ id: 1, name: 'Tag1' }],
|
|
260
|
+
injectedTagsParams: [{ id: 2, name: 'Tag2' }],
|
|
224
261
|
location: { query: { type: 'test' } },
|
|
225
262
|
tagModule: 'custom',
|
|
263
|
+
eventContextTags: [{ id: 3, name: 'Tag3' }],
|
|
226
264
|
};
|
|
227
265
|
validateTags.mockReturnValue({});
|
|
228
266
|
validateMessageContent('Valid message', mockFormatMessage, mockMessages, customConfig);
|
|
@@ -254,6 +292,20 @@ describe('validation', () => {
|
|
|
254
292
|
...mockValidationConfig,
|
|
255
293
|
});
|
|
256
294
|
});
|
|
295
|
+
|
|
296
|
+
it('should return personalization error when restrictPersonalization is true and message has personalization tags', () => {
|
|
297
|
+
validateTags.mockReturnValue({});
|
|
298
|
+
const result = validateMessageContent(
|
|
299
|
+
'Hello {{name}}',
|
|
300
|
+
mockFormatMessage,
|
|
301
|
+
mockMessages,
|
|
302
|
+
mockValidationConfig,
|
|
303
|
+
true,
|
|
304
|
+
true
|
|
305
|
+
);
|
|
306
|
+
expect(result).toBe('Personalization tags are not supported for anonymous customers');
|
|
307
|
+
expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.personalizationTokensErrorMessage);
|
|
308
|
+
});
|
|
257
309
|
});
|
|
258
310
|
});
|
|
259
311
|
|
|
@@ -637,21 +637,22 @@ export const Whatsapp = (props) => {
|
|
|
637
637
|
validateTags({
|
|
638
638
|
content: contentData.join(""),
|
|
639
639
|
tagsParam: tags,
|
|
640
|
+
injectedTagsParams: injectedTags,
|
|
640
641
|
location,
|
|
641
642
|
tagModule: getDefaultTags,
|
|
643
|
+
eventContextTags,
|
|
642
644
|
isFullMode,
|
|
643
645
|
}) || {};
|
|
646
|
+
const unsupportedTagsLengthCheck =
|
|
647
|
+
validationResponse?.unsupportedTags?.length > 0;
|
|
644
648
|
if (type === HEADER_TEXT) {
|
|
645
649
|
headerTagValidationResponse = validationResponse;
|
|
646
|
-
updateIsHeaderTagValidationError(
|
|
650
|
+
updateIsHeaderTagValidationError(unsupportedTagsLengthCheck);
|
|
647
651
|
} else if (type === CAROUSEL_TEXT) {
|
|
648
|
-
return [
|
|
649
|
-
{ fieldName: "carouselTagValidationErrMessage", value: validationResponse.isBraceError ? validationResponse : {} },
|
|
650
|
-
{ fieldName: "carouselTagValidationErr", value: validationResponse.isBraceError },
|
|
651
|
-
];
|
|
652
|
+
return [{fieldName: "carouselTagValidationErrMessage", value: validationResponse}, {fieldName: "carouselTagValidationErr", value: unsupportedTagsLengthCheck}];
|
|
652
653
|
} else {
|
|
653
654
|
tagValidationResponse = validationResponse;
|
|
654
|
-
updateIsTagValidationError(
|
|
655
|
+
updateIsTagValidationError(unsupportedTagsLengthCheck);
|
|
655
656
|
}
|
|
656
657
|
}
|
|
657
658
|
};
|
|
@@ -2681,11 +2682,18 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
|
|
|
2681
2682
|
} else {
|
|
2682
2683
|
validationResponse = tagValidationResponse;
|
|
2683
2684
|
}
|
|
2684
|
-
const { isBraceError } = validationResponse
|
|
2685
|
+
const { unsupportedTags = [], isBraceError } = validationResponse;
|
|
2686
|
+
|
|
2687
|
+
let tagError = "";
|
|
2688
|
+
if (unsupportedTags.length > 0) {
|
|
2689
|
+
tagError = formatMessage(globalMessages.unsupportedTagsValidationError, {
|
|
2690
|
+
unsupportedTags,
|
|
2691
|
+
});
|
|
2692
|
+
}
|
|
2685
2693
|
if (isBraceError) {
|
|
2686
|
-
|
|
2694
|
+
tagError = formatMessage(globalMessages.unbalanacedCurlyBraces);
|
|
2687
2695
|
}
|
|
2688
|
-
return
|
|
2696
|
+
return <CapError>{tagError}</CapError>;
|
|
2689
2697
|
};
|
|
2690
2698
|
|
|
2691
2699
|
const editModeContent = () => (
|
|
@@ -270,15 +270,23 @@ export const Zalo = (props) => {
|
|
|
270
270
|
validateTags({
|
|
271
271
|
content: message,
|
|
272
272
|
tagsParam: tags,
|
|
273
|
+
injectedTagsParams: injectedTags,
|
|
273
274
|
location,
|
|
274
275
|
tagModule: getDefaultTags,
|
|
276
|
+
eventContextTags,
|
|
275
277
|
isFullMode,
|
|
276
278
|
}) || {};
|
|
277
|
-
const { isBraceError } = tagValidationResponse;
|
|
279
|
+
const { unsupportedTags = [], isBraceError } = tagValidationResponse;
|
|
280
|
+
let tagError = '';
|
|
281
|
+
if (unsupportedTags.length > 0) {
|
|
282
|
+
tagError = formatMessage(globalMessages.unsupportedTagsValidationError, {
|
|
283
|
+
unsupportedTags,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
278
286
|
if (isBraceError) {
|
|
279
|
-
|
|
287
|
+
tagError = formatMessage(globalMessages.unbalanacedCurlyBraces);
|
|
280
288
|
}
|
|
281
|
-
return
|
|
289
|
+
return tagError;
|
|
282
290
|
};
|
|
283
291
|
|
|
284
292
|
//this function is used for checking errror validation in this it validate tags error and length error
|