@capillarytech/creatives-library 8.0.114-alpha.2 → 8.0.114

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 (45) hide show
  1. package/package.json +1 -1
  2. package/utils/commonUtils.js +3 -353
  3. package/utils/tagValidations.js +5 -22
  4. package/utils/tests/commonUtil.test.js +169 -563
  5. package/utils/tests/tagValidations.test.js +3 -129
  6. package/v2Components/ErrorInfoNote/index.js +47 -114
  7. package/v2Components/ErrorInfoNote/messages.js +0 -25
  8. package/v2Components/ErrorInfoNote/style.scss +1 -14
  9. package/v2Components/FormBuilder/index.js +127 -203
  10. package/v2Components/FormBuilder/messages.js +1 -1
  11. package/v2Containers/Cap/reducer.js +4 -4
  12. package/v2Containers/Cap/sagas.js +3 -9
  13. package/v2Containers/Cap/tests/saga.test.js +0 -12
  14. package/v2Containers/CreativesContainer/SlideBoxContent.js +3 -26
  15. package/v2Containers/CreativesContainer/SlideBoxFooter.js +1 -3
  16. package/v2Containers/CreativesContainer/constants.js +1 -4
  17. package/v2Containers/CreativesContainer/index.js +19 -46
  18. package/v2Containers/CreativesContainer/messages.js +0 -4
  19. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +3 -21
  20. package/v2Containers/CreativesContainer/tests/index.test.js +0 -1
  21. package/v2Containers/Ebill/index.js +3 -3
  22. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +1 -1
  23. package/v2Containers/InApp/index.js +50 -125
  24. package/v2Containers/InApp/tests/index.test.js +1 -1
  25. package/v2Containers/InApp/tests/sagas.test.js +1 -1
  26. package/v2Containers/InApp/utils.js +0 -57
  27. package/v2Containers/MobilePush/Create/index.js +20 -24
  28. package/v2Containers/MobilePush/Edit/index.js +2 -6
  29. package/v2Containers/MobilepushWrapper/index.js +0 -2
  30. package/v2Containers/Sms/Create/index.js +0 -1
  31. package/v2Containers/Sms/Edit/index.js +0 -2
  32. package/v2Containers/SmsTrai/Edit/index.js +10 -49
  33. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +36 -112
  34. package/v2Containers/SmsTrai/Edit/tests/index.test.js +3 -1
  35. package/v2Containers/SmsWrapper/index.js +1 -5
  36. package/v2Containers/Templates/sagas.js +1 -1
  37. package/v2Containers/Whatsapp/constants.js +1 -1
  38. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +57476 -0
  39. package/v2Containers/Whatsapp/tests/index.test.js +88 -0
  40. package/v2Components/ErrorInfoNote/ErrorTypeRenderer.js +0 -127
  41. package/v2Components/ErrorInfoNote/ErrorTypeRenderer.test.js +0 -147
  42. package/v2Components/ErrorInfoNote/utils.js +0 -38
  43. package/v2Components/ErrorInfoNote/utils.test.js +0 -156
  44. package/v2Containers/InApp/tests/utils.test.js +0 -85
  45. package/v2Containers/InApp/utils.test.js +0 -70
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "8.0.114-alpha.2",
4
+ "version": "8.0.114",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -1,23 +1,9 @@
1
1
  import React from 'react';
2
2
  import { FormattedMessage } from 'react-intl';
3
3
  import get from 'lodash/get';
4
- import { convert } from "html-to-text";
5
- import { EMBEDDED } from "../v2Containers/Whatsapp/constants";
6
- import {
7
- EDIT,
8
- EMAIL,
9
- INAPP,
10
- PREVIEW,
11
- } from "../v2Containers/App/constants";
12
- import {
13
- MOBILE_PUSH,
14
- SMS,
15
- ANDROID,
16
- IOS,
17
- } from "../v2Containers/CreativesContainer/constants";
18
- import { GLOBAL_CONVERT_OPTIONS } from "../v2Components/FormBuilder/constants";
19
- import { checkSupport, extractNames } from "./tagValidations";
20
- import { SMS_TRAI_VAR } from '../v2Containers/SmsTrai/Edit/constants';
4
+ import { EMBEDDED } from '../v2Containers/Whatsapp/constants';
5
+ import { EDIT, PREVIEW } from '../v2Containers/App/constants';
6
+
21
7
  export const apiMessageFormatHandler = (id, fallback) => (
22
8
  <FormattedMessage id={id} defaultMessage={fallback} />
23
9
  );
@@ -97,339 +83,3 @@ export const transformCustomFieldsData = (customFields) => {
97
83
  };
98
84
 
99
85
  export const isTagIncluded = (value) => value && value.includes('{{') && value.includes('}}');
100
-
101
-
102
- /**
103
- *
104
- * @param {*} channel
105
- * @param {*} formData
106
- * @returns
107
- */
108
- export const getChannelData = (channel, formData, baseLanguage) => {
109
- switch (channel?.toUpperCase()) {
110
- case EMAIL.toUpperCase():
111
- return convert(
112
- formData?.base?.[baseLanguage]?.["template-content"] || "",
113
- GLOBAL_CONVERT_OPTIONS
114
- );
115
-
116
- case SMS:
117
- return (
118
- `${formData?.base?.["sms-editor"]} ${formData?.["template-name"]}` || ""
119
- );
120
- case SMS_TRAI_VAR?.toUpperCase():
121
- return formData?.versions?.base?.["updated-sms-editor"].join(" ") || "";
122
- default:
123
- return JSON.stringify(formData);
124
- }
125
- };
126
-
127
- /**
128
- * Validates liquid template content for a given channel and options.
129
- * @param {string} content - The content to validate.
130
- * @param {string} channel - Channel type (e.g., EMAIL, SMS, MOBILE_PUSH).
131
- * @param {object} options - Validation options and callbacks.
132
- * @returns {Promise} Resolves to the validation result.
133
- */
134
- export const validateLiquidTemplateContent = async (
135
- content,
136
- options
137
- ) => {
138
- const {
139
- getLiquidTags,
140
- formatMessage,
141
- messages,
142
- onError = () => {},
143
- onSuccess = () => {},
144
- tagLookupMap,
145
- eventContextTags,
146
- isLiquidFlow,
147
- forwardedTags = {},
148
- tabType,
149
- skipTags = () => false,
150
- } = options;
151
- const emptyBodyError = formatMessage(messages?.emailBodyEmptyError);
152
- const somethingWrongMsg = formatMessage(messages?.somethingWentWrong);
153
- // Empty content check
154
-
155
- if (!content || content.trim() === "") {
156
- onError({
157
- standardErrors: [emptyBodyError],
158
- liquidErrors: [],
159
- tabType,
160
- });
161
- return false;
162
- }
163
-
164
- // Await getLiquidTags as a promise if it doesn't already return one
165
- const getLiquidTagsAsync = (inputContent) => new Promise((resolve) => {
166
- getLiquidTags(inputContent, (result) => {
167
- resolve(result);
168
- });
169
- });
170
-
171
- const {askAiraResponse: result, isError} = await getLiquidTagsAsync(content);
172
- const validString = /\S/.test(content);
173
-
174
- // Handle API errors or empty content
175
- if (result?.errors?.length > 0 || !validString || isError) {
176
- let standardErrors = [];
177
- if (!validString) {
178
- standardErrors = [emptyBodyError];
179
- }
180
- let liquidErrors;
181
- if (result && Array.isArray(result?.errors)) {
182
- liquidErrors = result?.errors?.map((error) => {
183
- const message = typeof error?.message === "string"
184
- ? error.message
185
- : somethingWrongMsg;
186
- return message;
187
- });
188
- } else {
189
- liquidErrors = [somethingWrongMsg];
190
- }
191
- onError({
192
- standardErrors,
193
- liquidErrors,
194
- tabType,
195
- });
196
- return false;
197
- }
198
- // Extract and validate tags
199
- const extractedLiquidTags = extractNames(result?.data || []);
200
- // Get supported tags
201
- const supportedLiquidTags = checkSupport(
202
- result,
203
- tagLookupMap,
204
- eventContextTags,
205
- isLiquidFlow,
206
- forwardedTags
207
- );
208
- // Find unsupported tags
209
- const unsupportedLiquidTags = extractedLiquidTags?.filter(
210
- (tag) => !supportedLiquidTags?.includes(tag) && !skipTags(tag)
211
- );
212
- // Handle unsupported tags
213
- if (unsupportedLiquidTags?.length > 0) {
214
- const errorMsg = formatMessage(messages.unsupportedTagsValidationError, {
215
- unsupportedTags: unsupportedLiquidTags.join(", "),
216
- });
217
- onError({
218
- standardErrors: [],
219
- liquidErrors: [errorMsg],
220
- tabType,
221
- });
222
- return false;
223
- }
224
- // All validations passed
225
- onSuccess(content, tabType);
226
- return true;
227
- };
228
-
229
- // Internal helper function to validate platform-specific content
230
- export const _validatePlatformSpecificContent = async (
231
- androidContent,
232
- iosContent,
233
- channel,
234
- options // Contains parent's onError and other options for validateLiquidTemplateContent
235
- ) => {
236
- const {
237
- singleTab,
238
- onError: parentOnError, // The onError callback from the calling function (e.g., validateMobilePushContent)
239
- ...commonVltcOptions // Other options like getLiquidTags, formatMessage, messages, currentTab, etc.
240
- } = options;
241
-
242
- let isAndroidValid = false;
243
- let isIosValid = false;
244
-
245
- // This aggregator is passed to validateLiquidTemplateContent.
246
- // It accumulates errors in the new structure and calls the parentOnError
247
- const internalOnErrorAggregator = ({
248
- standardErrors = [],
249
- liquidErrors = [],
250
- tabType: tabTypeFromVLTC,
251
- }) => {
252
-
253
- aggregatedErrors.standardErrors[tabTypeFromVLTC?.toUpperCase() ?? ''].push(
254
- ...standardErrors
255
- );
256
- aggregatedErrors.liquidErrors[tabTypeFromVLTC?.toUpperCase() ?? ''].push(
257
- ...liquidErrors
258
- );
259
- parentOnError(aggregatedErrors);
260
- };
261
-
262
- // Base options for calling validateLiquidTemplateContent
263
- const vltcCallOptions = {
264
- ...commonVltcOptions,
265
- onError: internalOnErrorAggregator,
266
- onSuccess: () => {},
267
- };
268
- // Initialize error structure with platform-specific categories
269
- const aggregatedErrors = {
270
- standardErrors: {
271
- [ANDROID]: [],
272
- [IOS]: [],
273
- generic: [],
274
- },
275
- liquidErrors: {
276
- [ANDROID]: [],
277
- [IOS]: [],
278
- generic: [],
279
- },
280
- };
281
-
282
- if (androidContent && (singleTab === ANDROID || !singleTab)) {
283
-
284
- isAndroidValid = await validateLiquidTemplateContent(
285
- androidContent,
286
- { ...vltcCallOptions, tabType: ANDROID }
287
- );
288
- }
289
-
290
- if (iosContent && (singleTab === IOS || !singleTab)) {
291
-
292
- isIosValid = await validateLiquidTemplateContent(
293
- iosContent,
294
- { ...vltcCallOptions, tabType: IOS }
295
- );
296
- }
297
- //if singleTab is android, then validate only android content and make ios valid by default
298
- if (singleTab === ANDROID) {
299
- isIosValid = true;
300
- }
301
- //if singleTab is ios, then validate only ios content and make android valid by default
302
- if (singleTab === IOS) {
303
- isAndroidValid = true;
304
- }
305
-
306
- return isAndroidValid && isIosValid; // Overall success
307
- };
308
-
309
- /**
310
- * Validate Mobile Push content for both Android and iOS tabs
311
- * @param {object} formData - Form data containing Android and iOS content
312
- * @param {object} options - Options for validation
313
- * @returns {Promise} - Promise that resolves when validation completes
314
- */
315
- export const validateMobilePushContent = async (formData, options) => {
316
- const {
317
- currentTab,
318
- onError, // This is the onError callback passed by the caller of validateMobilePushContent
319
- onSuccess, // This is the FINAL success callback for MobilePush
320
- ...restOptions // Options for validateLiquidTemplateContent (getLiquidTags, formatMessage, etc.)
321
- } = options;
322
- // Clear previous errors by calling the passed onError
323
- onError({ standardErrors: [], liquidErrors: [] });
324
-
325
- const androidContent = JSON.stringify(formData?.[0]);
326
- const iosContent = JSON.stringify(formData?.[1]);
327
-
328
- // Pass the original 'onError' from this function's arguments,
329
- // 'currentTab', and other relevant options to the helper.
330
- const overallSuccess = await _validatePlatformSpecificContent(
331
- androidContent,
332
- iosContent,
333
- MOBILE_PUSH,
334
- { ...restOptions, currentTab, onError }
335
- );
336
- const getContentToSubmit = () => {
337
- if (currentTab === 1 && androidContent) return [androidContent, ANDROID?.toLowerCase()];
338
- if (currentTab === 2 && iosContent) return [iosContent, IOS?.toLowerCase()];
339
- if (androidContent) return [androidContent, ANDROID?.toLowerCase()];
340
- if (iosContent) return [iosContent, IOS?.toLowerCase()];
341
- return ["", ""];
342
- };
343
-
344
- if (overallSuccess) {
345
- const [contentToSubmit, tabTypeToSubmit] = getContentToSubmit();
346
- // Call the FINAL onSuccess only ONCE here
347
- onSuccess(contentToSubmit, tabTypeToSubmit);
348
- return true;
349
- }
350
- return false;
351
- };
352
-
353
- // Helper function to extract content for a platform
354
- export const extractContent = (platformData) => {
355
- if (!platformData) return '';
356
- const { title, message, ctas } = platformData;
357
- return [
358
- title,
359
- message,
360
- ...((ctas?.map((cta) => cta?.text || cta?.actionLink)) || []),
361
- ].filter(Boolean).join(' ');
362
- };
363
-
364
- /**
365
- * Validate INAPP content for both Android and iOS
366
- * @param {object} formData - Form data containing Android and iOS content
367
- * @param {object} options - Options for validation
368
- * @returns {Promise} - Promise that resolves when validation completes
369
- */
370
- export const validateInAppContent = async (formData, options) => {
371
- const {
372
- onError, // This is the onError callback passed by the caller of validateInAppContent
373
- onSuccess, // FINAL success callback
374
- ...restOptions // Options for validateLiquidTemplateContent
375
- } = options;
376
-
377
- // Clear previous errors with new structure
378
- onError({
379
- standardErrors: {
380
- [ANDROID]: [],
381
- [IOS]: [],
382
- generic: [],
383
- },
384
- liquidErrors: {
385
- [ANDROID]: [],
386
- [IOS]: [],
387
- generic: [],
388
- },
389
- });
390
-
391
- let androidContent = "";
392
- let iosContent = "";
393
- let parseError = null;
394
-
395
- // Extract content
396
- try {
397
-
398
- const baseContent = formData?.versions?.base?.content;
399
- androidContent = extractContent(baseContent?.ANDROID);
400
- iosContent = extractContent(baseContent?.IOS);
401
- } catch (error) {
402
- parseError = error; // Capture parsing error
403
- }
404
-
405
- // Check if *any* content exists
406
- if (parseError) {
407
- onError((prevErrors) => ({
408
- ...prevErrors,
409
- standardErrors: {
410
- ...prevErrors.standardErrors,
411
- generic: [
412
- restOptions.formatMessage(restOptions.messages.somethingWentWrong),
413
- ],
414
- },
415
- }));
416
- return false;
417
- }
418
-
419
- // Pass the original 'onError' from this function's arguments
420
- // and other relevant options to the helper.
421
- const overallSuccess = await _validatePlatformSpecificContent(
422
- androidContent,
423
- iosContent,
424
- INAPP,
425
- { ...restOptions, onError }
426
- );
427
-
428
- if (overallSuccess) {
429
- // Call FINAL onSuccess ONCE
430
- onSuccess();
431
- return true;
432
- }
433
- // Errors already reported via the 'onError' callback passed to _validatePlatformSpecificContent
434
- return false;
435
- };
@@ -19,7 +19,6 @@ const SUBTAGS = 'subtags';
19
19
  * @param {Object} tagObject - The tagLookupMap.
20
20
  */
21
21
  export const checkSupport = (response = {}, tagObject = {}, eventContextTags = [], isLiquidFlow = false, forwardedTags = {}) => {
22
-
23
22
  const supportedList = [];
24
23
  // Verifies the presence of the tag in the 'Add Labels' section.
25
24
  // Incase of journey event context the tags won't be available in the tagObject(tagLookupMap).
@@ -74,7 +73,6 @@ export const checkSupport = (response = {}, tagObject = {}, eventContextTags = [
74
73
 
75
74
  }
76
75
 
77
-
78
76
  return supportedList;
79
77
  };
80
78
 
@@ -117,20 +115,6 @@ export function extractNames(data) {
117
115
  return names;
118
116
  }
119
117
 
120
- // Helper to check if a tag is inside a {% ... %} block
121
- export const isInsideLiquidBlock = (content, tagIndex) => {
122
- const blockRegex = /{%(.*?)%}/gs;
123
- let match;
124
- for (match = blockRegex.exec(content); match !== null; match = blockRegex.exec(content)) {
125
- const blockStart = match.index;
126
- const blockEnd = blockStart + match[0].length;
127
- if (tagIndex >= blockStart && tagIndex < blockEnd) {
128
- return true;
129
- }
130
- }
131
- return false;
132
- };
133
-
134
118
  /**
135
119
  * Validates the tags based on the provided parameters.
136
120
  * @param {Object} params - The parameters for tag validation.
@@ -146,6 +130,7 @@ export const validateTags = ({
146
130
  const tags = tagsParam;
147
131
  const injectedTags = transformInjectedTags(injectedTagsParams);
148
132
  let currentModule = location?.query?.module ? location?.query?.module : DEFAULT;
133
+
149
134
  if (tagModule) {
150
135
  currentModule = tagModule;
151
136
  }
@@ -175,7 +160,6 @@ export const validateTags = ({
175
160
  let match = regex.exec(content);
176
161
  while (match !== null) {
177
162
  const tagValue = match[0].substring(indexOfEnd(match[0], '{{'), match[0].indexOf('}}'));
178
- const tagIndex = match?.index;
179
163
  match = regex.exec(content);
180
164
  let ifSupported = false;
181
165
  lodashForEach(tags, (tag) => {
@@ -186,10 +170,10 @@ export const validateTags = ({
186
170
  const ifSkipped = skipTags(tagValue);
187
171
  if (ifSkipped) {
188
172
  ifSupported = true;
189
- const isUnsubscribeSkipped = tagValue.indexOf("unsubscribe") !== -1;
173
+ let isUnsubscribeSkipped = tagValue.indexOf("unsubscribe") != -1 ;
190
174
  if (isUnsubscribeSkipped) {
191
175
  const missingTagIndex = response.missingTags.indexOf("unsubscribe");
192
- if (missingTagIndex !== -1) {
176
+ if(missingTagIndex != -1) { //skip regex tags for mandatory tags also
193
177
  response.missingTags.splice(missingTagIndex, 1);
194
178
  }
195
179
  }
@@ -201,12 +185,11 @@ export const validateTags = ({
201
185
  }
202
186
  });
203
187
  ifSupported = ifSupported || checkIfSupportedTag(tagValue, injectedTags);
204
- // Only add to unsupportedTags if not inside a {% ... %} block and does not contain a dot
205
- if (!ifSupported && !isInsideLiquidBlock(content, tagIndex) && tagValue?.indexOf('.') === -1) {
188
+ if (!ifSupported) {
206
189
  response.unsupportedTags.push(tagValue);
207
190
  response.valid = false;
208
191
  }
209
- if (response.unsupportedTags.length === 0 && response.missingTags.length === 0) {
192
+ if (response.unsupportedTags.length == 0 && response.missingTags.length == 0 ) {
210
193
  response.valid = true;
211
194
  }
212
195
  }