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