@capillarytech/creatives-library 8.0.133 → 8.0.134-alpha.0

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.
Binary file
package/index.js CHANGED
@@ -103,6 +103,12 @@ import Rcs from './v2Containers/Rcs';
103
103
  import rcsReducer from './v2Containers/Rcs/reducer';
104
104
  import rcsSaga from './v2Containers/Rcs/sagas';
105
105
 
106
+ // Utils
107
+ import {
108
+ convertMediaTagsToUrls,
109
+ convertUrlsToMediaTags,
110
+ } from './utils/transformTemplateConfig';
111
+
106
112
  export {default as Ebill} from './v2Containers/Ebill';
107
113
  export {default as EbillReducer} from './v2Containers/Ebill/reducer';
108
114
  export {default as EbillSaga} from './v2Containers/Ebill/sagas';
@@ -181,4 +187,6 @@ export { CapContainer,
181
187
  RcsContainer,
182
188
  ZaloContainer,
183
189
  InAppContainer,
190
+ convertMediaTagsToUrls,
191
+ convertUrlsToMediaTags,
184
192
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "8.0.133",
4
+ "version": "8.0.134-alpha.0",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
package/services/api.js CHANGED
@@ -329,6 +329,11 @@ export const getTemplateDetails = async ({id, channel}) => {
329
329
  return { ...compressedTemplatesData, response: decompressData};
330
330
  };
331
331
 
332
+ export const getMediaDetails = async ({ id }) => {
333
+ const url = `${API_ENDPOINT}/media/${id}`;
334
+ return request(url, getAPICallObject('GET'));
335
+ };
336
+
332
337
  export const getAllTemplates = async ({channel, queryParams = {}}) => {
333
338
  const url = getUrlWithQueryParams({
334
339
  url: `${API_ENDPOINT}/templates/v1/${channel}?`,
@@ -8,7 +8,6 @@ import {
8
8
  FILMSTRIP_CAROUSEL,
9
9
  ANDROID,
10
10
  IOS,
11
- TEXT,
12
11
  } from "../v2Containers/MobilePushNew/constants";
13
12
  import messages from '../v2Containers/MobilePushNew/messages';
14
13
 
@@ -138,7 +137,6 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
138
137
  linkType,
139
138
  deepLinkValue,
140
139
  externalLinkValue,
141
- deepLinkKeysValue = [],
142
140
  } = content || {};
143
141
 
144
142
  const platformContent = {
@@ -150,48 +148,28 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
150
148
 
151
149
  // Handle CTA
152
150
  if (actionOnClick) {
153
- let finalDeepLinkValue = deepLinkValue;
154
-
155
- if (linkType === DEEP_LINK && deepLinkKeysValue && deepLinkKeysValue.length > 0) {
156
- // Check if the URL already contains the keys
157
- const urlHasKeys = deepLinkKeysValue.some((key) => deepLinkValue && deepLinkValue.includes(`${key}=${key}`));
158
-
159
- // Only append keys if they're not already in the URL
160
- if (!urlHasKeys) {
161
- finalDeepLinkValue = appendDeepLinkKeysToUrl(deepLinkValue, deepLinkKeysValue);
162
- }
163
- }
164
-
165
151
  platformContent.cta = {
166
152
  type: linkType === DEEP_LINK ? DEEP_LINK : EXTERNAL_URL,
167
- actionLink: linkType === DEEP_LINK ? finalDeepLinkValue : externalLinkValue,
153
+ actionLink: linkType === DEEP_LINK ? deepLinkValue : externalLinkValue,
168
154
  };
169
155
  }
170
156
 
171
157
  // Handle media types
172
158
  const style = content?.mediaType || expandableDetails?.style;
173
159
 
174
- // Determine the type field based on media type
175
- let templateType = TEXT; // Default type for NONE or BIG_TEXT
176
-
177
160
  // Handle BIG_PICTURE media type
178
161
  if (style === BIG_PICTURE || style === IMAGE) {
179
162
  platformContent.expandableDetails.style = BIG_PICTURE;
180
- platformContent.expandableDetails.message = message;
181
163
  platformContent.expandableDetails.image = imageSrc;
182
- templateType = IMAGE;
183
164
  } else if (style === VIDEO) { // Handle VIDEO media type
184
165
  platformContent.expandableDetails.style = VIDEO;
185
- platformContent.expandableDetails.message = message;
186
166
  platformContent.expandableDetails.media = [{
187
167
  url: mpushVideoSrcAndPreview.mpushVideoSrc || (content?.mediaList?.[0]?.url || ''),
188
168
  text: content?.mediaList?.[0]?.text || '',
189
169
  type: VIDEO,
190
170
  }];
191
- templateType = VIDEO;
192
171
  } else if (style === GIF) { // Handle GIF media type
193
172
  platformContent.expandableDetails.style = GIF;
194
- platformContent.expandableDetails.message = message;
195
173
  if (content?.mediaList?.[0]) {
196
174
  // If mediaList exists, use it and preserve the original type
197
175
  const { url = '', text = '', type = GIF } = content.mediaList[0];
@@ -201,20 +179,15 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
201
179
  type: type.toLowerCase(),
202
180
  }];
203
181
  } else {
204
- // If no mediaList but mpushVideoSrc exists
205
- platformContent.expandableDetails.style = GIF;
206
- platformContent.expandableDetails.message = message;
182
+ // If no mediaList but mpushVideoSrc exists, convert to VIDEO
207
183
  platformContent.expandableDetails.media = [{
208
184
  url: mpushVideoSrcAndPreview.mpushVideoSrc,
209
185
  text: '',
210
186
  type: GIF, // Backend expects GIF type for GIFs
211
187
  }];
212
188
  }
213
- templateType = GIF;
214
189
  } else if ([CAROUSEL, MANUAL_CAROUSEL, AUTO_CAROUSEL, FILMSTRIP_CAROUSEL].includes(style)) { // Handle CAROUSEL media types
215
190
  platformContent.expandableDetails.style = MANUAL_CAROUSEL;
216
- platformContent.expandableDetails.message = message;
217
- templateType = CAROUSEL;
218
191
 
219
192
  // Handle carouselData
220
193
  if (content?.carouselData?.length > 0) {
@@ -248,8 +221,8 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
248
221
  }
249
222
 
250
223
  // Handle mediaList
251
- if (content?.mediaList && Array.isArray(content?.mediaList) && content?.mediaList?.length > 0) {
252
- platformContent.expandableDetails.media = content?.mediaList?.map((media) => {
224
+ if (content?.mediaList && Array.isArray(content.mediaList) && content.mediaList.length > 0) {
225
+ platformContent.expandableDetails.media = content.mediaList.map((media) => {
253
226
  const {
254
227
  url,
255
228
  text,
@@ -266,14 +239,18 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
266
239
  } else { // Handle BIG_TEXT media type (default)
267
240
  platformContent.expandableDetails.style = BIG_TEXT;
268
241
  platformContent.expandableDetails.message = message;
269
- templateType = TEXT;
270
242
  }
271
243
 
272
- // Set the type and deviceType fields
273
- platformContent.type = templateType;
274
- platformContent.deviceType = platform;
275
-
276
244
  // Handle GIF media type
245
+ if (content?.mediaType === GIF) {
246
+ platformContent.expandableDetails = {
247
+ media: [{
248
+ url: mpushVideoSrcAndPreview?.mpushVideoSrc || (content?.mediaList?.[0]?.url || ''),
249
+ text: content?.mediaList?.[0]?.text || '',
250
+ type: GIF,
251
+ }],
252
+ };
253
+ }
277
254
 
278
255
  // iOS-specific handling
279
256
  if (platform === IOS) {
@@ -296,11 +273,31 @@ function buildCustomFields(content) {
296
273
  if (Array.isArray(custom)) {
297
274
  customFields = [...custom];
298
275
  } else if (custom && typeof custom === 'object') {
299
- // If it's an object, map to array, excluding deepLinkKeys
300
- customFields = Object.entries(custom)
301
- .filter(([key]) => key !== 'deepLinkKeysValue' && key !== 'deepLinkValue' && key !== 'linkType')
302
- .map(([key, value]) => ({ key, value }));
276
+ // If it's an object, map to array
277
+ customFields = Object.entries(custom).map(([key, value]) => ({ key, value }));
303
278
  }
279
+ const { deepLinkKeysValue, deepLinkValue, linkType } = custom || {};
280
+ // Add deepLinkKeys to custom fields if it exists
281
+ if (deepLinkKeysValue && linkType === DEEP_LINK) {
282
+ if (Array.isArray(deepLinkKeysValue)) {
283
+ // Handle array of deep link keys
284
+ deepLinkKeysValue.forEach((key) => {
285
+ if (key) {
286
+ customFields.push({
287
+ key,
288
+ value: deepLinkValue,
289
+ });
290
+ }
291
+ });
292
+ } else {
293
+ // Handle single deep link key
294
+ customFields.push({
295
+ key: deepLinkKeysValue,
296
+ value: deepLinkValue,
297
+ });
298
+ }
299
+ }
300
+
304
301
  return customFields;
305
302
  }
306
303
 
@@ -310,14 +307,14 @@ function buildCustomFields(content) {
310
307
  * @param {Array} keys - Deep link keys
311
308
  * @returns {string} URL with appended keys
312
309
  */
313
- export function appendDeepLinkKeysToUrl(url, keys) {
310
+ function appendDeepLinkKeysToUrl(url, keys) {
314
311
  if (!url || !keys || !Array.isArray(keys) || keys?.length === 0) return url;
315
312
 
316
313
  const separator = url.includes('?') ? '&' : '?';
317
314
  const validKeys = keys.filter((key) => typeof key === 'string' && key?.length > 0);
318
315
  if (validKeys?.length === 0) return url;
319
316
 
320
- const keyParams = validKeys.map((key) => `${key}=${key}`).join('&');
317
+ const keyParams = validKeys.map((key) => `${key}={{${key}}}`).join('&');
321
318
 
322
319
  return `${url}${separator}${keyParams}`;
323
320
  }
@@ -6,51 +6,6 @@ import messages from '../../v2Containers/MobilePushNew/messages';
6
6
  const intlProvider = new IntlProvider({ locale: 'en', messages }, {});
7
7
  const { intl } = intlProvider.getChildContext();
8
8
 
9
- // Mock the buildCustomFields function to handle deep link keys as expected by tests
10
- jest.mock('../createMobilePushPayload', () => {
11
- const originalModule = jest.requireActual('../createMobilePushPayload');
12
-
13
- // Create a mock version that overrides the buildCustomFields behavior
14
- const mockCreateMobilePushPayload = (params) => {
15
- const result = originalModule.default(params);
16
-
17
- // Override the custom fields for Android if custom fields are present
18
- if (result.versions?.base?.ANDROID && params.androidContent?.custom) {
19
- const { custom } = params.androidContent;
20
- const { deepLinkKeysValue, deepLinkValue, linkType } = custom;
21
-
22
- let customFields = [];
23
-
24
- // Include all original custom fields
25
- if (Array.isArray(custom)) {
26
- customFields = [...custom];
27
- } else if (custom && typeof custom === 'object') {
28
- customFields = Object.entries(custom).map(([key, value]) => ({ key, value }));
29
- }
30
-
31
- // Add deep link key entries only when linkType is DEEP_LINK
32
- if (linkType === 'DEEP_LINK' && deepLinkValue && deepLinkKeysValue) {
33
- const keysArray = Array.isArray(deepLinkKeysValue) ? deepLinkKeysValue : [deepLinkKeysValue];
34
- keysArray.forEach((key) => {
35
- if (key && typeof key === 'string') {
36
- customFields.push({ key, value: deepLinkValue });
37
- }
38
- });
39
- }
40
-
41
- result.versions.base.ANDROID.custom = customFields;
42
- }
43
-
44
- return result;
45
- };
46
-
47
- return {
48
- __esModule: true,
49
- default: mockCreateMobilePushPayload,
50
- appendDeepLinkKeysToUrl: originalModule.appendDeepLinkKeysToUrl,
51
- };
52
- });
53
-
54
9
  // Helper function to call createMobilePushPayload with intl
55
10
  const callWithIntl = (params) => createMobilePushPayload({ ...params, intl });
56
11
 
@@ -570,126 +525,6 @@ describe('createMobilePushPayload', () => {
570
525
  });
571
526
  expect(result.versions.base.ANDROID.cta).toBeUndefined();
572
527
  });
573
-
574
- it('should handle deep link CTA with keys when URL does not contain keys', () => {
575
- const result = callWithIntl({
576
- templateName: 'Test',
577
- androidContent: {
578
- title: 'Title',
579
- message: 'Message',
580
- actionOnClick: true,
581
- linkType: 'DEEP_LINK',
582
- deepLinkValue: 'app://deep-link',
583
- deepLinkKeysValue: ['key1', 'key2'],
584
- },
585
- iosContent: { title: 'Title', message: 'Message' },
586
- accountData: mockAccountData,
587
- });
588
- expect(result.versions.base.ANDROID.cta).toEqual({
589
- type: 'DEEP_LINK',
590
- actionLink: 'app://deep-link?key1=key1&key2=key2',
591
- });
592
- });
593
-
594
- it('should handle deep link CTA with keys when URL already contains keys', () => {
595
- const result = callWithIntl({
596
- templateName: 'Test',
597
- androidContent: {
598
- title: 'Title',
599
- message: 'Message',
600
- actionOnClick: true,
601
- linkType: 'DEEP_LINK',
602
- deepLinkValue: 'app://deep-link?key1=key1&key2=key2',
603
- deepLinkKeysValue: ['key1', 'key2'],
604
- },
605
- iosContent: { title: 'Title', message: 'Message' },
606
- accountData: mockAccountData,
607
- });
608
- expect(result.versions.base.ANDROID.cta).toEqual({
609
- type: 'DEEP_LINK',
610
- actionLink: 'app://deep-link?key1=key1&key2=key2',
611
- });
612
- });
613
-
614
- it('should handle deep link CTA with keys when URL contains some keys but not all', () => {
615
- const result = callWithIntl({
616
- templateName: 'Test',
617
- androidContent: {
618
- title: 'Title',
619
- message: 'Message',
620
- actionOnClick: true,
621
- linkType: 'DEEP_LINK',
622
- deepLinkValue: 'app://deep-link?key1=key1',
623
- deepLinkKeysValue: ['key1', 'key2'],
624
- },
625
- iosContent: { title: 'Title', message: 'Message' },
626
- accountData: mockAccountData,
627
- });
628
- expect(result.versions.base.ANDROID.cta).toEqual({
629
- type: 'DEEP_LINK',
630
- actionLink: 'app://deep-link?key1=key1',
631
- });
632
- });
633
-
634
- it('should handle deep link CTA with empty deepLinkKeysValue', () => {
635
- const result = callWithIntl({
636
- templateName: 'Test',
637
- androidContent: {
638
- title: 'Title',
639
- message: 'Message',
640
- actionOnClick: true,
641
- linkType: 'DEEP_LINK',
642
- deepLinkValue: 'app://deep-link',
643
- deepLinkKeysValue: [],
644
- },
645
- iosContent: { title: 'Title', message: 'Message' },
646
- accountData: mockAccountData,
647
- });
648
- expect(result.versions.base.ANDROID.cta).toEqual({
649
- type: 'DEEP_LINK',
650
- actionLink: 'app://deep-link',
651
- });
652
- });
653
-
654
- it('should handle deep link CTA with null deepLinkKeysValue', () => {
655
- const result = callWithIntl({
656
- templateName: 'Test',
657
- androidContent: {
658
- title: 'Title',
659
- message: 'Message',
660
- actionOnClick: true,
661
- linkType: 'DEEP_LINK',
662
- deepLinkValue: 'app://deep-link',
663
- deepLinkKeysValue: null,
664
- },
665
- iosContent: { title: 'Title', message: 'Message' },
666
- accountData: mockAccountData,
667
- });
668
- expect(result.versions.base.ANDROID.cta).toEqual({
669
- type: 'DEEP_LINK',
670
- actionLink: 'app://deep-link',
671
- });
672
- });
673
-
674
- it('should handle deep link CTA with undefined deepLinkValue', () => {
675
- const result = callWithIntl({
676
- templateName: 'Test',
677
- androidContent: {
678
- title: 'Title',
679
- message: 'Message',
680
- actionOnClick: true,
681
- linkType: 'DEEP_LINK',
682
- deepLinkValue: undefined,
683
- deepLinkKeysValue: ['key1', 'key2'],
684
- },
685
- iosContent: { title: 'Title', message: 'Message' },
686
- accountData: mockAccountData,
687
- });
688
- expect(result.versions.base.ANDROID.cta).toEqual({
689
- type: 'DEEP_LINK',
690
- actionLink: undefined,
691
- });
692
- });
693
528
  });
694
529
 
695
530
  // Custom Fields Handling Tests
@@ -1058,7 +893,7 @@ describe('createMobilePushPayload', () => {
1058
893
  });
1059
894
 
1060
895
  expect(result.versions.base.ANDROID.expandableDetails.carouselData[0].buttons[0].deepLinkValue)
1061
- .toBe('app://test?key1=key1&key2=key2');
896
+ .toBe('app://test?key1={{key1}}&key2={{key2}}');
1062
897
  });
1063
898
 
1064
899
  it('should handle single deep link key in carousel buttons', () => {
@@ -1087,7 +922,7 @@ describe('createMobilePushPayload', () => {
1087
922
  });
1088
923
 
1089
924
  expect(result.versions.base.ANDROID.expandableDetails.carouselData[0].buttons[0].deepLinkValue)
1090
- .toBe('app://test?singleKey=singleKey');
925
+ .toBe('app://test?singleKey={{singleKey}}');
1091
926
  });
1092
927
 
1093
928
  it('should handle URL with existing query parameters', () => {
@@ -1116,7 +951,7 @@ describe('createMobilePushPayload', () => {
1116
951
  });
1117
952
 
1118
953
  expect(result.versions.base.ANDROID.expandableDetails.carouselData[0].buttons[0].deepLinkValue)
1119
- .toBe('app://test?param=value&key1=key1&key2=key2');
954
+ .toBe('app://test?param=value&key1={{key1}}&key2={{key2}}');
1120
955
  });
1121
956
 
1122
957
  it('should not modify URL when deepLinkKeys is missing', () => {
@@ -1215,110 +1050,5 @@ describe('createMobilePushPayload', () => {
1215
1050
  expect(button.deepLinkValue).toBe('app://test');
1216
1051
  });
1217
1052
  });
1218
-
1219
- it('should handle carousel with null buttons', () => {
1220
- const result = callWithIntl({
1221
- templateName: 'Test',
1222
- androidContent: {
1223
- title: 'Title',
1224
- message: 'Message',
1225
- mediaType: 'CAROUSEL',
1226
- carouselData: [
1227
- {
1228
- mediaType: 'image',
1229
- imageUrl: 'test.jpg',
1230
- buttons: null,
1231
- },
1232
- ],
1233
- },
1234
- iosContent: { title: 'Title', message: 'Message' },
1235
- accountData: mockAccountData,
1236
- });
1237
-
1238
- expect(result.versions.base.ANDROID.expandableDetails.carouselData[0].buttons).toEqual([]);
1239
- });
1240
-
1241
- it('should handle carousel with undefined buttons', () => {
1242
- const result = callWithIntl({
1243
- templateName: 'Test',
1244
- androidContent: {
1245
- title: 'Title',
1246
- message: 'Message',
1247
- mediaType: 'CAROUSEL',
1248
- carouselData: [
1249
- {
1250
- mediaType: 'image',
1251
- imageUrl: 'test.jpg',
1252
- buttons: undefined,
1253
- },
1254
- ],
1255
- },
1256
- iosContent: { title: 'Title', message: 'Message' },
1257
- accountData: mockAccountData,
1258
- });
1259
-
1260
- expect(result.versions.base.ANDROID.expandableDetails.carouselData[0].buttons).toEqual([]);
1261
- });
1262
-
1263
- it('should handle carousel with null card', () => {
1264
- const result = callWithIntl({
1265
- templateName: 'Test',
1266
- androidContent: {
1267
- title: 'Title',
1268
- message: 'Message',
1269
- mediaType: 'CAROUSEL',
1270
- carouselData: [null],
1271
- },
1272
- iosContent: { title: 'Title', message: 'Message' },
1273
- accountData: mockAccountData,
1274
- });
1275
-
1276
- expect(result.versions.base.ANDROID.expandableDetails.carouselData[0]).toEqual({
1277
- mediaType: 'image',
1278
- imageUrl: '',
1279
- videoSrc: '',
1280
- buttons: [],
1281
- });
1282
- });
1283
-
1284
- it('should handle carousel with undefined card', () => {
1285
- const result = callWithIntl({
1286
- templateName: 'Test',
1287
- androidContent: {
1288
- title: 'Title',
1289
- message: 'Message',
1290
- mediaType: 'CAROUSEL',
1291
- carouselData: [undefined],
1292
- },
1293
- iosContent: { title: 'Title', message: 'Message' },
1294
- accountData: mockAccountData,
1295
- });
1296
-
1297
- expect(result.versions.base.ANDROID.expandableDetails.carouselData[0]).toEqual({
1298
- mediaType: 'image',
1299
- imageUrl: '',
1300
- videoSrc: '',
1301
- buttons: [],
1302
- });
1303
- });
1304
-
1305
- it('should handle mediaList with null media items', () => {
1306
- const result = callWithIntl({
1307
- templateName: 'Test',
1308
- androidContent: {
1309
- title: 'Title',
1310
- message: 'Message',
1311
- mediaType: 'CAROUSEL',
1312
- mediaList: [null, undefined],
1313
- },
1314
- iosContent: { title: 'Title', message: 'Message' },
1315
- accountData: mockAccountData,
1316
- });
1317
-
1318
- expect(result.versions.base.ANDROID.expandableDetails.media).toEqual([
1319
- { url: undefined, text: '', type: undefined },
1320
- { url: undefined, text: '', type: undefined },
1321
- ]);
1322
- });
1323
1053
  });
1324
1054
  });