@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.
Files changed (65) hide show
  1. package/constants/unified.js +1 -0
  2. package/initialState.js +2 -0
  3. package/package.json +1 -1
  4. package/utils/common.js +8 -5
  5. package/utils/commonUtils.js +111 -2
  6. package/utils/tagValidations.js +222 -84
  7. package/utils/tests/commonUtil.test.js +118 -147
  8. package/utils/tests/tagValidations.test.js +358 -280
  9. package/v2Components/CapTagList/index.js +7 -2
  10. package/v2Components/CapTagListWithInput/index.js +4 -0
  11. package/v2Components/ErrorInfoNote/index.js +5 -2
  12. package/v2Components/FormBuilder/index.js +187 -74
  13. package/v2Components/FormBuilder/messages.js +12 -0
  14. package/v2Components/HtmlEditor/HTMLEditor.js +5 -0
  15. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
  16. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +15 -0
  17. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +2 -1
  18. package/v2Containers/Cap/mockData.js +14 -0
  19. package/v2Containers/Cap/reducer.js +55 -3
  20. package/v2Containers/Cap/tests/reducer.test.js +102 -0
  21. package/v2Containers/CreativesContainer/SlideBoxContent.js +20 -0
  22. package/v2Containers/CreativesContainer/SlideBoxFooter.js +40 -6
  23. package/v2Containers/CreativesContainer/constants.js +6 -0
  24. package/v2Containers/CreativesContainer/index.js +36 -5
  25. package/v2Containers/CreativesContainer/messages.js +12 -0
  26. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +339 -0
  27. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +18 -0
  28. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +37 -0
  29. package/v2Containers/Email/index.js +5 -1
  30. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +62 -10
  31. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +115 -12
  32. package/v2Containers/FTP/index.js +51 -2
  33. package/v2Containers/FTP/messages.js +4 -0
  34. package/v2Containers/InApp/index.js +96 -1
  35. package/v2Containers/InApp/tests/index.test.js +6 -17
  36. package/v2Containers/InappAdvance/index.js +103 -2
  37. package/v2Containers/Line/Container/Text/index.js +1 -0
  38. package/v2Containers/MobilePush/Create/index.js +37 -1
  39. package/v2Containers/MobilePush/Create/messages.js +4 -0
  40. package/v2Containers/MobilePush/Edit/index.js +37 -2
  41. package/v2Containers/MobilePush/Edit/messages.js +4 -0
  42. package/v2Containers/MobilePushNew/components/PlatformContentFields.js +36 -12
  43. package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +68 -27
  44. package/v2Containers/MobilePushNew/index.js +92 -5
  45. package/v2Containers/MobilePushNew/messages.js +8 -0
  46. package/v2Containers/MobilepushWrapper/index.js +7 -1
  47. package/v2Containers/Rcs/index.js +37 -12
  48. package/v2Containers/Sms/Create/index.js +3 -31
  49. package/v2Containers/Sms/Create/messages.js +0 -4
  50. package/v2Containers/Sms/Edit/index.js +3 -29
  51. package/v2Containers/Sms/commonMethods.js +6 -6
  52. package/v2Containers/SmsTrai/Edit/index.js +47 -6
  53. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +6 -6
  54. package/v2Containers/TagList/index.js +17 -1
  55. package/v2Containers/TagList/messages.js +4 -0
  56. package/v2Containers/TemplatesV2/index.js +43 -23
  57. package/v2Containers/Viber/index.js +1 -0
  58. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +3 -1
  59. package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +7 -0
  60. package/v2Containers/WebPush/Create/index.js +25 -6
  61. package/v2Containers/WebPush/Create/messages.js +8 -1
  62. package/v2Containers/WebPush/Create/utils/validation.js +20 -22
  63. package/v2Containers/WebPush/Create/utils/validation.test.js +52 -0
  64. package/v2Containers/Whatsapp/index.js +17 -9
  65. 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 (required and optional tag validation)
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, validationConfig, isFullMode) => {
20
+ export const validateTitle = (value, formatMessage, messages, restrictPersonalization) => {
22
21
  if (!value || value.trim() === '') {
23
22
  return formatMessage(messages.titleRequired);
24
23
  }
25
-
26
- if (validationConfig != null) {
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(validationResponse.isBraceError);
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(validationResponse.isBraceError);
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
- return <CapError>{formatMessage(globalMessages.unbalanacedCurlyBraces)}</CapError>;
2694
+ tagError = formatMessage(globalMessages.unbalanacedCurlyBraces);
2687
2695
  }
2688
- return null;
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
- return formatMessage(globalMessages.unbalanacedCurlyBraces);
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