@capillarytech/creatives-library 7.17.193-alpha.5 → 7.17.193

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 (36) hide show
  1. package/config/app.js +2 -0
  2. package/containers/App/constants.js +1 -0
  3. package/initialState.js +3 -0
  4. package/package.json +1 -1
  5. package/services/api.js +13 -0
  6. package/services/tests/api.test.js +148 -0
  7. package/utils/common.js +7 -0
  8. package/utils/tagValidations.js +102 -1
  9. package/utils/tests/tagValidations.test.js +381 -2
  10. package/v2Components/ErrorInfoNote/index.js +94 -0
  11. package/v2Components/ErrorInfoNote/messages.js +34 -0
  12. package/v2Components/ErrorInfoNote/style.scss +73 -0
  13. package/v2Components/FormBuilder/_formBuilder.scss +4 -1
  14. package/v2Components/FormBuilder/index.js +166 -69
  15. package/v2Components/FormBuilder/messages.js +4 -0
  16. package/v2Containers/Cap/actions.js +8 -0
  17. package/v2Containers/Cap/constants.js +4 -0
  18. package/v2Containers/Cap/reducer.js +14 -0
  19. package/v2Containers/Cap/sagas.js +676 -2
  20. package/v2Containers/Cap/selectors.js +5 -0
  21. package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +1 -0
  22. package/v2Containers/Cap/tests/reducer.test.js +52 -0
  23. package/v2Containers/Cap/tests/saga.test.js +81 -1
  24. package/v2Containers/CreativesContainer/SlideBoxContent.js +4 -3
  25. package/v2Containers/CreativesContainer/SlideBoxFooter.js +27 -16
  26. package/v2Containers/CreativesContainer/index.js +29 -6
  27. package/v2Containers/CreativesContainer/index.scss +15 -1
  28. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +16 -0
  29. package/v2Containers/Email/index.js +2 -0
  30. package/v2Containers/EmailWrapper/index.js +3 -0
  31. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +3 -0
  32. package/v2Containers/MobilePush/Edit/constants.js +0 -2
  33. package/v2Containers/MobilePush/Edit/index.js +15 -68
  34. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +93 -0
  35. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +12 -0
  36. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +12 -0
package/config/app.js CHANGED
@@ -6,6 +6,7 @@ const config = {
6
6
  api_endpoint: '/arya/api/v1/creatives',
7
7
  campaigns_api_endpoint: '/iris/v2/campaigns',
8
8
  campaigns_api_org_endpoint: '/iris/v2/org/campaign',
9
+ liquid_endpoint:'/iris/v2/liquid',
9
10
  auth_endpoint: '/arya/api/v1/auth',
10
11
  arya_endpoint: '/arya/api/v1',
11
12
  login_url: '/auth/login',
@@ -25,6 +26,7 @@ const config = {
25
26
  exports_api_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1/export/data',
26
27
  login_url: '/auth/login',
27
28
  dashboard_url: '/sms',
29
+ liquid_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/iris/v2/template',
28
30
  dashboard_url_v2: '/v2',
29
31
  },
30
32
  testing: {
@@ -9,6 +9,7 @@ export const HOSPITALITY_BASED_SCOPE = 'HOSPITALITY_BASED_SCOPE';
9
9
  export const REGISTRATION_CUSTOM_FIELD = 'Registration custom fields';
10
10
  export const GIFT_CARDS = 'GIFT_CARDS';
11
11
  export const PROMO_ENGINE = 'PROMO_ENGINE';
12
+ export const LIQUID_SUPPORT = 'ENABLE_LIQUID_SUPPORT';
12
13
  export const CUSTOM_TAG = 'CustomTagMessage';
13
14
  export const CUSTOMER_EXTENDED_FIELD = 'Customer extended fields';
14
15
  export const EXTENDED_TAG = 'ExtendedTagMessage';
package/initialState.js CHANGED
@@ -14,7 +14,10 @@ export default {
14
14
  metaEntities: {
15
15
  tags: [],
16
16
  layouts: [],
17
+ tagMap: {},
17
18
  },
19
+ liquidTags: [],
20
+ fetchingLiquidTags: false,
18
21
  fetchingSchema: true,
19
22
  fetchingSchemaError: '',
20
23
  // isLoggedIn,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "7.17.193-alpha.5",
4
+ "version": "7.17.193",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
package/services/api.js CHANGED
@@ -14,6 +14,7 @@ let API_ENDPOINT = config.development.api_endpoint;
14
14
  let EXPORT_API_ENDPOINT = config.development.exports_api_endpoint;
15
15
  let CAMPAIGNS_API_ENDPOINT = config.development.campaigns_api_endpoint;
16
16
  let CAMPAIGNS_API_ORG_ENDPOINT = config.development.campaigns_api_org_endpoint;
17
+ let LIQUID_API_ENDPOINT = config.development.liquid_endpoint;
17
18
 
18
19
  let API_AUTH_ENDPOINT = config.development.auth_endpoint;
19
20
  let ARYA_ENDPOINT = config.development.arya_endpoint;
@@ -26,6 +27,7 @@ if (process.env.NODE_ENV === 'production') {
26
27
  ARYA_ENDPOINT = config.production.arya_endpoint;
27
28
  SUBSCRIPTION_API_ENDPOINT = config.production.subscription_api_endpoint;
28
29
  EXPORT_API_ENDPOINT = config.production.exports_api_endpoint;
30
+ LIQUID_API_ENDPOINT = config.production.liquid_endpoint;
29
31
  }
30
32
  let requestCallerName = '';
31
33
  const isProd = process.env.NODE_ENV === 'production';
@@ -444,6 +446,12 @@ export const getLocizMessage = async (locale) => {
444
446
  return response;
445
447
  };
446
448
 
449
+ export const askAiraForLiquid = async ({templateContent, errorMessage}) => {
450
+ const url = `${ARYA_ENDPOINT}/ask-aira-service/creatives_ai/liquidValidation`;
451
+ const response = await request(url, getAPICallObject('POST', { temperature:0.8, templateContent , parserError:errorMessage}));
452
+ return response;
453
+ };
454
+
447
455
  export const getUnsubscribeUrl = () => {
448
456
  const body = {
449
457
  orgUnitId: -1,
@@ -549,4 +557,9 @@ export const getNavigationConfigApi = async () => {
549
557
  return await request(url, getAPICallObject('GET'));
550
558
  };
551
559
 
560
+ export const getLiquidTags = (content) => {
561
+ const url = `${LIQUID_API_ENDPOINT}/extractTags`;
562
+ return request(url, getAPICallObject("POST", { content }, false, true));
563
+ };
564
+
552
565
  export {request, getAPICallObject};
@@ -9,6 +9,8 @@ import {
9
9
  getAllTemplates,
10
10
  getTemplateDetails,
11
11
  getTemplateInfoById,
12
+ askAiraForLiquid,
13
+ getLiquidTags,
12
14
  } from '../api';
13
15
  import { mockData } from './mockData';
14
16
  const sampleFile = require('../../assets/line.png');
@@ -291,3 +293,149 @@ describe('getTemplateInfoById -- Test with valid responses', () => {
291
293
  });
292
294
  });
293
295
  });
296
+
297
+ describe('askAiraForLiquid -- Test with various responses', () => {
298
+ beforeEach(() => {
299
+ global.fetch = jest.fn(); // Mocking global fetch function
300
+ });
301
+
302
+ afterEach(() => {
303
+ jest.restoreAllMocks(); // Restore all mocks after each test
304
+ });
305
+
306
+ it('Should return correct response when syntax errors are present', async () => {
307
+ global.fetch.mockReturnValue(
308
+ Promise.resolve({
309
+ status: 200,
310
+ json: () =>
311
+ Promise.resolve({
312
+ status: 200,
313
+ response: 'Error description here',
314
+ }),
315
+ })
316
+ );
317
+
318
+ const templateContent = 'Invalid Liquid Template';
319
+ const errorMessage = 'Parser error message';
320
+ const response = await askAiraForLiquid({ templateContent, errorMessage });
321
+
322
+ expect(response).toEqual({
323
+ status: 200,
324
+ response: 'Error description here',
325
+ });
326
+ });
327
+
328
+ it('Should return empty string when no syntax errors are present', async () => {
329
+ global.fetch.mockReturnValue(
330
+ Promise.resolve({
331
+ status: 200,
332
+ json: () =>
333
+ Promise.resolve({
334
+ status: 200,
335
+ response: '',
336
+ }),
337
+ })
338
+ );
339
+
340
+ const templateContent = 'Valid Liquid Template';
341
+ const errorMessage = '';
342
+ const response = await askAiraForLiquid({ templateContent, errorMessage });
343
+
344
+ expect(response).toEqual({
345
+ status: 200,
346
+ response: '',
347
+ });
348
+ });
349
+
350
+ it('Should handle server errors gracefully', async () => {
351
+ global.fetch.mockReturnValue(
352
+ Promise.resolve({
353
+ status: 500,
354
+ json: () =>
355
+ Promise.resolve({
356
+ status: 500,
357
+ error: 'Internal Server Error',
358
+ }),
359
+ })
360
+ );
361
+
362
+ const templateContent = 'Any Template';
363
+ const errorMessage = 'Any Error Message';
364
+ const response = await askAiraForLiquid({ templateContent, errorMessage });
365
+
366
+ expect(response).toEqual({
367
+ status: 500,
368
+ error: 'Internal Server Error',
369
+ });
370
+ });
371
+ });
372
+
373
+ describe('getLiquidTags -- Test with various responses', () => {
374
+ beforeEach(() => {
375
+ global.fetch = jest.fn(); // Mocking global fetch function
376
+ });
377
+
378
+ afterEach(() => {
379
+ jest.restoreAllMocks(); // Restore all mocks after each test
380
+ });
381
+
382
+ it('Should return correct tags when content has Liquid syntax', async () => {
383
+ const mockResponse = {
384
+ status: 200,
385
+ json: () =>
386
+ Promise.resolve({
387
+ status: 200,
388
+ response: ['tag1', 'tag2'],
389
+ }),
390
+ };
391
+ global.fetch.mockReturnValue(Promise.resolve(mockResponse));
392
+
393
+ const content = 'Some Liquid content with tags';
394
+ const response = await getLiquidTags(content);
395
+
396
+ expect(response).toEqual({
397
+ status: 200,
398
+ response: ['tag1', 'tag2'],
399
+ });
400
+ });
401
+
402
+ it('Should return empty array when content has no Liquid tags', async () => {
403
+ const mockResponse = {
404
+ status: 200,
405
+ json: () =>
406
+ Promise.resolve({
407
+ status: 200,
408
+ response: [],
409
+ }),
410
+ };
411
+ global.fetch.mockReturnValue(Promise.resolve(mockResponse));
412
+
413
+ const content = 'Plain content without Liquid tags';
414
+ const response = await getLiquidTags(content);
415
+
416
+ expect(response).toEqual({
417
+ status: 200,
418
+ response: [],
419
+ });
420
+ });
421
+
422
+ it('Should handle server errors gracefully', async () => {
423
+ const mockResponse = {
424
+ status: 500,
425
+ json: () =>
426
+ Promise.resolve({
427
+ status: 500,
428
+ error: 'Internal Server Error',
429
+ }),
430
+ };
431
+ global.fetch.mockReturnValue(Promise.resolve(mockResponse));
432
+
433
+ const content = 'Any content';
434
+ const response = await getLiquidTags(content);
435
+
436
+ expect(response).toEqual({
437
+ status: 500,
438
+ error: 'Internal Server Error',
439
+ });
440
+ });
441
+ });
package/utils/common.js CHANGED
@@ -21,6 +21,7 @@ import {
21
21
  EMAIL_UNSUBSCRIBE_TAG_MANDATORY,
22
22
  BADGES_ISSUE,
23
23
  ENABLE_WECHAT,
24
+ LIQUID_SUPPORT,
24
25
  } from '../containers/App/constants';
25
26
  import { apiMessageFormatHandler } from './commonUtils';
26
27
 
@@ -88,6 +89,12 @@ export const hasPromoFeature = Auth.hasFeatureAccess.bind(
88
89
  PROMO_ENGINE,
89
90
  );
90
91
 
92
+ export const hasLiquidSupportFeature = Auth.hasFeatureAccess.bind(
93
+ null,
94
+ LIQUID_SUPPORT,
95
+ );
96
+
97
+
91
98
  export const hasGiftVoucherFeature = Auth.hasFeatureAccess.bind(
92
99
  null,
93
100
  GIFT_CARDS,
@@ -12,6 +12,85 @@ import lodashCloneDeep from 'lodash/cloneDeep';
12
12
  const DEFAULT = 'default';
13
13
  const SUBTAGS = 'subtags';
14
14
 
15
+ /**
16
+ * Checks if the response supports the given tag object.
17
+ * @param {Object} response - The response object.
18
+ * @param {Object} tagObject - The tag object to check.
19
+ */
20
+ export const checkSupport = (response = {}, tagObject = {}) => {
21
+ const supportedList = [];
22
+
23
+ const checkNameInTagObject = (name) => {
24
+ if (tagObject?.[name]) {
25
+ return true;
26
+ }
27
+ return false;
28
+ };
29
+
30
+ const checkSubtags = (parentTag, childName) => {
31
+ let updatedChildName = childName;
32
+ if (childName?.includes('.')) {
33
+ updatedChildName = '.' + childName?.split('.')[1];
34
+ }
35
+
36
+ if (tagObject?.[parentTag]) {
37
+ const subTags = tagObject?.[parentTag]?.definition?.subtags;
38
+ if (subTags?.includes(updatedChildName)) {
39
+ return true;
40
+ }
41
+ }
42
+ return false;
43
+ };
44
+
45
+ const processChildren = (parentTag = "", children = []) => {
46
+ for (const child of children) {
47
+ if (checkSubtags(parentTag, child?.name)) {
48
+ supportedList.push(child?.name);
49
+ }
50
+ if (child?.children && child?.children?.length > 0) {
51
+ processChildren(child?.name, child?.children);
52
+ }
53
+ }
54
+ };
55
+
56
+ for (const item of response?.data || []) {
57
+ if (checkNameInTagObject(item?.name)) {
58
+ supportedList.push(item?.name);
59
+ }
60
+ if (item?.children && item?.children?.length > 0) {
61
+ processChildren(item?.name, item?.children);
62
+ }
63
+ }
64
+ return supportedList;
65
+ };
66
+
67
+ /**
68
+ * Extracts the names from the given data.
69
+ * @param {Array} data - The data to extract names from.
70
+ * @returns {Array} - The extracted names.
71
+ */
72
+ export function extractNames(data) {
73
+ let names = [];
74
+
75
+ function traverse(node) {
76
+ if (node?.name) {
77
+ names.push(node?.name);
78
+ }
79
+
80
+ if (node?.children && node?.children?.length > 0) {
81
+ node?.children?.forEach(child => traverse(child));
82
+ }
83
+ }
84
+
85
+ data?.forEach(item => traverse(item));
86
+
87
+ return names;
88
+ }
89
+
90
+ /**
91
+ * Validates the tags based on the provided parameters.
92
+ * @param {Object} params - The parameters for tag validation.
93
+ */
15
94
  export const validateTags = ({
16
95
  content,
17
96
  tagsParam,
@@ -21,7 +100,8 @@ export const validateTags = ({
21
100
  }) => {
22
101
  const tags = tagsParam;
23
102
  const injectedTags = transformInjectedTags(injectedTagsParams);
24
- let currentModule = location.query.module ? location.query.module : DEFAULT;
103
+ let currentModule = location?.query?.module ? location?.query?.module : DEFAULT;
104
+
25
105
  if (tagModule) {
26
106
  currentModule = tagModule;
27
107
  }
@@ -86,6 +166,12 @@ export const validateTags = ({
86
166
  return response;
87
167
  }
88
168
 
169
+ /**
170
+ * Checks if the given tag is supported based on the injected tags.
171
+ * @param {string} checkingTag - The tag to check.
172
+ * @param {Array} injectedTags - The injected tags.
173
+ * @returns {boolean} - True if the tag is supported, false otherwise.
174
+ */
89
175
  export const checkIfSupportedTag = (checkingTag, injectedTags) => {
90
176
  let result = false;
91
177
  lodashForEach(injectedTags, (tag, key) => {
@@ -156,4 +242,19 @@ export const validateIfTagClosed = (value) => {
156
242
 
157
243
  return (l1 == l2 && l2 == l3 && l1 == l3);
158
244
 
245
+ };
246
+
247
+ //replaces encoded string with their respective characters
248
+ export const preprocessHtml = (content) => {
249
+
250
+ const replacements = {
251
+ "'": "'",
252
+ """: '"',
253
+ "&": "&",
254
+ "&lt;": "<",
255
+ "&gt;": ">",
256
+ "\n": "", // Handling newlines by replacing them with an empty string
257
+ };
258
+
259
+ return content.replace(/&#39;|&quot;|&amp;|&lt;|&gt;|\n/g, match => replacements[match]);
159
260
  };