@capillarytech/creatives-library 8.0.133-alpha.0 → 8.0.133
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.
- package/package.json +1 -1
- package/utils/createMobilePushPayload.js +24 -14
- package/utils/tests/createMobilePushPayload.test.js +273 -3
- package/utils/transformerUtils.js +11 -12
- package/v2Components/CapVideoUpload/index.js +4 -2
- package/v2Components/TestAndPreviewSlidebox/index.js +1 -1
- package/v2Containers/CreativesContainer/SlideBoxContent.js +1 -0
- package/v2Containers/CreativesContainer/index.js +2 -2
- package/v2Containers/MobilePushNew/index.js +403 -18
- package/v2Containers/Whatsapp/index.js +22 -12
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
FILMSTRIP_CAROUSEL,
|
|
9
9
|
ANDROID,
|
|
10
10
|
IOS,
|
|
11
|
+
TEXT,
|
|
11
12
|
} from "../v2Containers/MobilePushNew/constants";
|
|
12
13
|
import messages from '../v2Containers/MobilePushNew/messages';
|
|
13
14
|
|
|
@@ -153,7 +154,7 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
|
|
|
153
154
|
|
|
154
155
|
if (linkType === DEEP_LINK && deepLinkKeysValue && deepLinkKeysValue.length > 0) {
|
|
155
156
|
// Check if the URL already contains the keys
|
|
156
|
-
const urlHasKeys = deepLinkKeysValue.some((key) => deepLinkValue && deepLinkValue.includes(`${key}
|
|
157
|
+
const urlHasKeys = deepLinkKeysValue.some((key) => deepLinkValue && deepLinkValue.includes(`${key}=${key}`));
|
|
157
158
|
|
|
158
159
|
// Only append keys if they're not already in the URL
|
|
159
160
|
if (!urlHasKeys) {
|
|
@@ -170,19 +171,27 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
|
|
|
170
171
|
// Handle media types
|
|
171
172
|
const style = content?.mediaType || expandableDetails?.style;
|
|
172
173
|
|
|
174
|
+
// Determine the type field based on media type
|
|
175
|
+
let templateType = TEXT; // Default type for NONE or BIG_TEXT
|
|
176
|
+
|
|
173
177
|
// Handle BIG_PICTURE media type
|
|
174
178
|
if (style === BIG_PICTURE || style === IMAGE) {
|
|
175
179
|
platformContent.expandableDetails.style = BIG_PICTURE;
|
|
180
|
+
platformContent.expandableDetails.message = message;
|
|
176
181
|
platformContent.expandableDetails.image = imageSrc;
|
|
182
|
+
templateType = IMAGE;
|
|
177
183
|
} else if (style === VIDEO) { // Handle VIDEO media type
|
|
178
184
|
platformContent.expandableDetails.style = VIDEO;
|
|
185
|
+
platformContent.expandableDetails.message = message;
|
|
179
186
|
platformContent.expandableDetails.media = [{
|
|
180
187
|
url: mpushVideoSrcAndPreview.mpushVideoSrc || (content?.mediaList?.[0]?.url || ''),
|
|
181
188
|
text: content?.mediaList?.[0]?.text || '',
|
|
182
189
|
type: VIDEO,
|
|
183
190
|
}];
|
|
191
|
+
templateType = VIDEO;
|
|
184
192
|
} else if (style === GIF) { // Handle GIF media type
|
|
185
193
|
platformContent.expandableDetails.style = GIF;
|
|
194
|
+
platformContent.expandableDetails.message = message;
|
|
186
195
|
if (content?.mediaList?.[0]) {
|
|
187
196
|
// If mediaList exists, use it and preserve the original type
|
|
188
197
|
const { url = '', text = '', type = GIF } = content.mediaList[0];
|
|
@@ -192,15 +201,20 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
|
|
|
192
201
|
type: type.toLowerCase(),
|
|
193
202
|
}];
|
|
194
203
|
} else {
|
|
195
|
-
// If no mediaList but mpushVideoSrc exists
|
|
204
|
+
// If no mediaList but mpushVideoSrc exists
|
|
205
|
+
platformContent.expandableDetails.style = GIF;
|
|
206
|
+
platformContent.expandableDetails.message = message;
|
|
196
207
|
platformContent.expandableDetails.media = [{
|
|
197
208
|
url: mpushVideoSrcAndPreview.mpushVideoSrc,
|
|
198
209
|
text: '',
|
|
199
210
|
type: GIF, // Backend expects GIF type for GIFs
|
|
200
211
|
}];
|
|
201
212
|
}
|
|
213
|
+
templateType = GIF;
|
|
202
214
|
} else if ([CAROUSEL, MANUAL_CAROUSEL, AUTO_CAROUSEL, FILMSTRIP_CAROUSEL].includes(style)) { // Handle CAROUSEL media types
|
|
203
215
|
platformContent.expandableDetails.style = MANUAL_CAROUSEL;
|
|
216
|
+
platformContent.expandableDetails.message = message;
|
|
217
|
+
templateType = CAROUSEL;
|
|
204
218
|
|
|
205
219
|
// Handle carouselData
|
|
206
220
|
if (content?.carouselData?.length > 0) {
|
|
@@ -234,8 +248,8 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
|
|
|
234
248
|
}
|
|
235
249
|
|
|
236
250
|
// Handle mediaList
|
|
237
|
-
if (content?.mediaList && Array.isArray(content
|
|
238
|
-
platformContent.expandableDetails.media = content
|
|
251
|
+
if (content?.mediaList && Array.isArray(content?.mediaList) && content?.mediaList?.length > 0) {
|
|
252
|
+
platformContent.expandableDetails.media = content?.mediaList?.map((media) => {
|
|
239
253
|
const {
|
|
240
254
|
url,
|
|
241
255
|
text,
|
|
@@ -252,18 +266,14 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
|
|
|
252
266
|
} else { // Handle BIG_TEXT media type (default)
|
|
253
267
|
platformContent.expandableDetails.style = BIG_TEXT;
|
|
254
268
|
platformContent.expandableDetails.message = message;
|
|
269
|
+
templateType = TEXT;
|
|
255
270
|
}
|
|
256
271
|
|
|
272
|
+
// Set the type and deviceType fields
|
|
273
|
+
platformContent.type = templateType;
|
|
274
|
+
platformContent.deviceType = platform;
|
|
275
|
+
|
|
257
276
|
// Handle GIF media type
|
|
258
|
-
if (content?.mediaType === GIF) {
|
|
259
|
-
platformContent.expandableDetails = {
|
|
260
|
-
media: [{
|
|
261
|
-
url: mpushVideoSrcAndPreview?.mpushVideoSrc || (content?.mediaList?.[0]?.url || ''),
|
|
262
|
-
text: content?.mediaList?.[0]?.text || '',
|
|
263
|
-
type: GIF,
|
|
264
|
-
}],
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
277
|
|
|
268
278
|
// iOS-specific handling
|
|
269
279
|
if (platform === IOS) {
|
|
@@ -307,7 +317,7 @@ export function appendDeepLinkKeysToUrl(url, keys) {
|
|
|
307
317
|
const validKeys = keys.filter((key) => typeof key === 'string' && key?.length > 0);
|
|
308
318
|
if (validKeys?.length === 0) return url;
|
|
309
319
|
|
|
310
|
-
const keyParams = validKeys.map((key) => `${key}
|
|
320
|
+
const keyParams = validKeys.map((key) => `${key}=${key}`).join('&');
|
|
311
321
|
|
|
312
322
|
return `${url}${separator}${keyParams}`;
|
|
313
323
|
}
|
|
@@ -6,6 +6,51 @@ 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
|
+
|
|
9
54
|
// Helper function to call createMobilePushPayload with intl
|
|
10
55
|
const callWithIntl = (params) => createMobilePushPayload({ ...params, intl });
|
|
11
56
|
|
|
@@ -525,6 +570,126 @@ describe('createMobilePushPayload', () => {
|
|
|
525
570
|
});
|
|
526
571
|
expect(result.versions.base.ANDROID.cta).toBeUndefined();
|
|
527
572
|
});
|
|
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
|
+
});
|
|
528
693
|
});
|
|
529
694
|
|
|
530
695
|
// Custom Fields Handling Tests
|
|
@@ -893,7 +1058,7 @@ describe('createMobilePushPayload', () => {
|
|
|
893
1058
|
});
|
|
894
1059
|
|
|
895
1060
|
expect(result.versions.base.ANDROID.expandableDetails.carouselData[0].buttons[0].deepLinkValue)
|
|
896
|
-
.toBe('app://test?key1=
|
|
1061
|
+
.toBe('app://test?key1=key1&key2=key2');
|
|
897
1062
|
});
|
|
898
1063
|
|
|
899
1064
|
it('should handle single deep link key in carousel buttons', () => {
|
|
@@ -922,7 +1087,7 @@ describe('createMobilePushPayload', () => {
|
|
|
922
1087
|
});
|
|
923
1088
|
|
|
924
1089
|
expect(result.versions.base.ANDROID.expandableDetails.carouselData[0].buttons[0].deepLinkValue)
|
|
925
|
-
.toBe('app://test?singleKey=
|
|
1090
|
+
.toBe('app://test?singleKey=singleKey');
|
|
926
1091
|
});
|
|
927
1092
|
|
|
928
1093
|
it('should handle URL with existing query parameters', () => {
|
|
@@ -951,7 +1116,7 @@ describe('createMobilePushPayload', () => {
|
|
|
951
1116
|
});
|
|
952
1117
|
|
|
953
1118
|
expect(result.versions.base.ANDROID.expandableDetails.carouselData[0].buttons[0].deepLinkValue)
|
|
954
|
-
.toBe('app://test?param=value&key1=
|
|
1119
|
+
.toBe('app://test?param=value&key1=key1&key2=key2');
|
|
955
1120
|
});
|
|
956
1121
|
|
|
957
1122
|
it('should not modify URL when deepLinkKeys is missing', () => {
|
|
@@ -1050,5 +1215,110 @@ describe('createMobilePushPayload', () => {
|
|
|
1050
1215
|
expect(button.deepLinkValue).toBe('app://test');
|
|
1051
1216
|
});
|
|
1052
1217
|
});
|
|
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
|
+
});
|
|
1053
1323
|
});
|
|
1054
1324
|
});
|
|
@@ -126,7 +126,7 @@ const transformMpushPayload = (mpushData, options = {}) => {
|
|
|
126
126
|
type: androidContent?.type || TEXT,
|
|
127
127
|
deviceType: IOS,
|
|
128
128
|
title: mpushData?.messageSubject || "",
|
|
129
|
-
message: ""
|
|
129
|
+
message: "",
|
|
130
130
|
};
|
|
131
131
|
|
|
132
132
|
// Get base payload structure
|
|
@@ -137,41 +137,40 @@ const transformMpushPayload = (mpushData, options = {}) => {
|
|
|
137
137
|
channel: PUSH,
|
|
138
138
|
messageSubject: mpushData?.messageSubject || "",
|
|
139
139
|
androidContent: {
|
|
140
|
-
type: TEXT,
|
|
140
|
+
type: androidContent?.type || TEXT, // Use the type from content if available, fallback to TEXT
|
|
141
141
|
deviceType: ANDROID,
|
|
142
142
|
...androidContent,
|
|
143
143
|
cta: {
|
|
144
144
|
type: EXTERNAL_URL,
|
|
145
145
|
actionText: null,
|
|
146
146
|
templateCtaId: null,
|
|
147
|
-
...(androidContent?.cta || {})
|
|
147
|
+
...(androidContent?.cta || {}),
|
|
148
148
|
},
|
|
149
149
|
expandableDetails: {
|
|
150
150
|
style: BIG_TEXT,
|
|
151
|
-
...androidContent?.expandableDetails
|
|
151
|
+
...androidContent?.expandableDetails,
|
|
152
152
|
},
|
|
153
|
-
customProperties: androidContent?.custom || {}
|
|
153
|
+
customProperties: androidContent?.custom || {},
|
|
154
154
|
},
|
|
155
155
|
iosContent: {
|
|
156
|
-
type: TEXT,
|
|
156
|
+
type: iosContent?.type || TEXT, // Use the type from content if available, fallback to TEXT
|
|
157
157
|
deviceType: IOS,
|
|
158
158
|
...iosContent,
|
|
159
159
|
cta: {
|
|
160
160
|
type: EXTERNAL_URL,
|
|
161
161
|
actionText: null,
|
|
162
162
|
templateCtaId: null,
|
|
163
|
-
...(iosContent?.cta || {})
|
|
163
|
+
...(iosContent?.cta || {}),
|
|
164
164
|
},
|
|
165
165
|
expandableDetails: {
|
|
166
166
|
style: BIG_TEXT,
|
|
167
|
-
...iosContent?.expandableDetails
|
|
167
|
+
...iosContent?.expandableDetails,
|
|
168
168
|
},
|
|
169
|
-
customProperties: iosContent?.custom || {}
|
|
169
|
+
customProperties: iosContent?.custom || {},
|
|
170
170
|
},
|
|
171
|
-
accountId: mpushData?.accountId || 0
|
|
171
|
+
accountId: mpushData?.accountId || 0,
|
|
172
172
|
};
|
|
173
|
-
payload.centralCommsPayload.mpushDeliverySettings =
|
|
174
|
-
mobilePushDeliverySettings || {};
|
|
173
|
+
payload.centralCommsPayload.mpushDeliverySettings = mobilePushDeliverySettings || {};
|
|
175
174
|
|
|
176
175
|
return payload;
|
|
177
176
|
};
|
|
@@ -109,19 +109,21 @@ function CapVideoUpload(props) {
|
|
|
109
109
|
secure_file_path: metaVideoSrc = '',
|
|
110
110
|
file_name: metaVideoName = '',
|
|
111
111
|
preview_image_url: previewImgUrl = '',
|
|
112
|
+
video_file_path_preview: videoPreviewUrl = '',
|
|
112
113
|
} = {},
|
|
113
114
|
} = videoData[`uploadedAssetData${index}`] || {};
|
|
114
115
|
|
|
115
116
|
const metaVideoId = get(videoData, `uploadedAssetData${index}.videoIdResponse.fbVideo.id`, '');
|
|
116
117
|
const karixFileHandle = get(videoData, `uploadedAssetData${index}.metaInfo.karixFileHandle`, '');
|
|
118
|
+
const hapticFileHandle = get(videoData, `uploadedAssetData${index}.metaInfo.hapticFileHandle`, '');
|
|
117
119
|
|
|
118
120
|
if (metaVideoSrc && videoSrc === "") {
|
|
119
121
|
onVideoUploadUpdateAssestList(index, {
|
|
120
|
-
previewUrl: previewImgUrl,
|
|
122
|
+
previewUrl: videoPreviewUrl || previewImgUrl,
|
|
121
123
|
videoSrc: metaVideoSrc,
|
|
122
124
|
videoName: metaVideoName,
|
|
123
125
|
videoId: metaVideoId,
|
|
124
|
-
fileHandle: karixFileHandle,
|
|
126
|
+
fileHandle: hapticFileHandle || karixFileHandle,
|
|
125
127
|
videoDuration: null,
|
|
126
128
|
});
|
|
127
129
|
}
|
|
@@ -802,7 +802,7 @@ export class Creatives extends React.Component {
|
|
|
802
802
|
androidContent.expandableDetails = this.getMobilePushCarouselData({...androidContent?.expandableDetails});
|
|
803
803
|
}
|
|
804
804
|
templateData.androidContent = androidContent;
|
|
805
|
-
templateData.androidContent.type = get(channelTemplate, 'definition.mode', '')
|
|
805
|
+
templateData.androidContent.type = androidContent?.type || get(channelTemplate, 'definition.mode', '')?.toUpperCase() || constants.TEXT;
|
|
806
806
|
templateData.androidContent.deviceType = constants.ANDROID;
|
|
807
807
|
}
|
|
808
808
|
const iosContent = channel === constants.INAPP ? get(channelTemplate, 'versions.base.content.IOS') : get(channelTemplate, 'versions.base.IOS');
|
|
@@ -824,7 +824,7 @@ export class Creatives extends React.Component {
|
|
|
824
824
|
iosContent.expandableDetails = this.getMobilePushCarouselData({...iosContent?.expandableDetails});
|
|
825
825
|
}
|
|
826
826
|
templateData.iosContent = iosContent;
|
|
827
|
-
templateData.iosContent.type = get(channelTemplate, 'definition.mode')
|
|
827
|
+
templateData.iosContent.type = iosContent?.type || get(channelTemplate, 'definition.mode', '')?.toUpperCase() || 'TEXT';
|
|
828
828
|
templateData.iosContent.deviceType = constants.IOS;
|
|
829
829
|
}
|
|
830
830
|
templateData.messageSubject = channelTemplate?.name ? channelTemplate?.name : "messageSubject";
|
|
@@ -488,8 +488,6 @@ const MobilePushNew = ({
|
|
|
488
488
|
const accountObj = accountData || {};
|
|
489
489
|
const deepLinkObj = accountObj?.configs?.deeplink || "";
|
|
490
490
|
|
|
491
|
-
// Debug logging removed - issue identified and fixed
|
|
492
|
-
|
|
493
491
|
if (!isEmpty(accountObj)) {
|
|
494
492
|
const { configs = {} } = accountObj;
|
|
495
493
|
const isAndroidSupported = configs?.android === DEVICE_SUPPORTED;
|
|
@@ -498,9 +496,9 @@ const MobilePushNew = ({
|
|
|
498
496
|
// Parse deep link data - handle both object and array formats
|
|
499
497
|
const parsedDeepLinks = JSON.parse(deepLinkObj || "[]");
|
|
500
498
|
// Debug logging removed - issue identified and fixed
|
|
501
|
-
|
|
499
|
+
|
|
502
500
|
let keys = [];
|
|
503
|
-
|
|
501
|
+
|
|
504
502
|
if (Array.isArray(parsedDeepLinks)) {
|
|
505
503
|
// Handle array format
|
|
506
504
|
keys = parsedDeepLinks.map((link) => ({
|
|
@@ -518,9 +516,6 @@ const MobilePushNew = ({
|
|
|
518
516
|
keys: link?.keys,
|
|
519
517
|
}));
|
|
520
518
|
}
|
|
521
|
-
|
|
522
|
-
// Debug logging removed - issue identified and fixed
|
|
523
|
-
|
|
524
519
|
setActiveTab(isAndroidSupported ? ANDROID : IOS);
|
|
525
520
|
setDeepLink(keys);
|
|
526
521
|
} catch (error) {
|
|
@@ -528,7 +523,6 @@ const MobilePushNew = ({
|
|
|
528
523
|
setDeepLink([]);
|
|
529
524
|
}
|
|
530
525
|
} else {
|
|
531
|
-
// Debug logging removed - issue identified and fixed
|
|
532
526
|
setDeepLink([]);
|
|
533
527
|
}
|
|
534
528
|
}, [accountData?.configs?.deeplink, accountData?.configs?.android, accountData]);
|
|
@@ -539,15 +533,18 @@ const MobilePushNew = ({
|
|
|
539
533
|
if (params?.id) {
|
|
540
534
|
setSpin(true);
|
|
541
535
|
mobilePushActions.getTemplateDetails(params.id);
|
|
536
|
+
} else if (!isFullMode && templateData && !isEmpty(templateData)) {
|
|
537
|
+
// Library mode: set template data directly without API call
|
|
538
|
+
setSpin(true);
|
|
539
|
+
mobilePushActions.setTemplateDetails(templateData);
|
|
542
540
|
}
|
|
543
|
-
}, [params?.id, resetFormData, mobilePushActions]);
|
|
541
|
+
}, [params?.id, templateData, isFullMode, resetFormData, mobilePushActions]);
|
|
544
542
|
|
|
545
543
|
// Data population useEffect - ONLY for edit mode
|
|
546
544
|
useEffect(() => {
|
|
547
545
|
if (!isEditMode) {
|
|
548
546
|
return;
|
|
549
547
|
}
|
|
550
|
-
|
|
551
548
|
const { name = "", versions = {} } = editData?.templateDetails || {};
|
|
552
549
|
const editContent = versions?.base || {};
|
|
553
550
|
|
|
@@ -585,7 +582,7 @@ const MobilePushNew = ({
|
|
|
585
582
|
} = androidExpandableDetails || {};
|
|
586
583
|
|
|
587
584
|
// Determine media type based on all available information
|
|
588
|
-
let androidMediaType =
|
|
585
|
+
let androidMediaType = NONE;
|
|
589
586
|
let androidImageSrc = "";
|
|
590
587
|
let androidVideoSrc = "";
|
|
591
588
|
let androidVideoPreview = "";
|
|
@@ -965,23 +962,412 @@ const MobilePushNew = ({
|
|
|
965
962
|
return;
|
|
966
963
|
}
|
|
967
964
|
|
|
968
|
-
// Do NOT reset form state here; only populate data
|
|
969
|
-
// resetFormData();
|
|
970
|
-
|
|
971
965
|
// templateData is expected to have a similar structure as editData.templateDetails
|
|
972
966
|
const { name = "", versions = {} } = templateData || {};
|
|
973
967
|
const templateContent = versions?.base || {};
|
|
974
|
-
|
|
975
968
|
if (isEmpty(templateContent)) {
|
|
976
969
|
setSpin(false);
|
|
977
970
|
return;
|
|
978
971
|
}
|
|
979
972
|
|
|
980
|
-
//
|
|
973
|
+
// Prepare all state updates
|
|
974
|
+
const stateUpdates = [];
|
|
975
|
+
|
|
976
|
+
// Template name
|
|
977
|
+
stateUpdates.push(() => setTemplateName(name));
|
|
978
|
+
|
|
979
|
+
// Process Android content
|
|
980
|
+
const androidContentType = templateContent?.ANDROID;
|
|
981
|
+
if (!isEmpty(androidContentType)) {
|
|
982
|
+
const {
|
|
983
|
+
title: androidTitle = "",
|
|
984
|
+
message: androidMessage = "",
|
|
985
|
+
expandableDetails: androidExpandableDetails = {},
|
|
986
|
+
image: androidImage = "",
|
|
987
|
+
cta: androidMainCta = null,
|
|
988
|
+
type: androidType = "NONE", // Get the type from root level
|
|
989
|
+
} = androidContentType || {};
|
|
990
|
+
|
|
991
|
+
const {
|
|
992
|
+
style: androidStyle = "",
|
|
993
|
+
ctas: androidCtas = [],
|
|
994
|
+
image: androidExpandableImage = "",
|
|
995
|
+
media: androidMedia = [],
|
|
996
|
+
carouselData: androidCarouselData = [],
|
|
997
|
+
} = androidExpandableDetails || {};
|
|
998
|
+
|
|
999
|
+
// Determine media type based on all available information
|
|
1000
|
+
let androidMediaType = NONE;
|
|
1001
|
+
let androidImageSrc = "";
|
|
1002
|
+
let androidVideoSrc = "";
|
|
1003
|
+
let androidVideoPreview = "";
|
|
1004
|
+
|
|
1005
|
+
// First check expandableDetails.style
|
|
1006
|
+
if (androidStyle === BIG_PICTURE) {
|
|
1007
|
+
androidMediaType = IMAGE;
|
|
1008
|
+
androidImageSrc = androidExpandableImage || androidImage;
|
|
1009
|
+
} else if (androidStyle === MANUAL_CAROUSEL || androidStyle === AUTO_CAROUSEL || androidStyle === FILMSTRIP_CAROUSEL || androidStyle === CAROUSEL) {
|
|
1010
|
+
androidMediaType = CAROUSEL;
|
|
1011
|
+
} else if (androidStyle === BIG_TEXT) {
|
|
1012
|
+
androidMediaType = "NONE";
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// Then check media array for video/GIF
|
|
1016
|
+
if (androidMedia?.length > 0) {
|
|
1017
|
+
const mediaItem = androidMedia[0];
|
|
1018
|
+
const { type, url, videoPreviewUrl } = mediaItem || {};
|
|
1019
|
+
if (type === VIDEO) {
|
|
1020
|
+
// Check if it's actually a GIF
|
|
1021
|
+
if (url && url.toLowerCase().includes('.gif')) {
|
|
1022
|
+
androidMediaType = GIF;
|
|
1023
|
+
} else {
|
|
1024
|
+
androidMediaType = VIDEO;
|
|
1025
|
+
}
|
|
1026
|
+
androidVideoSrc = url;
|
|
1027
|
+
androidVideoPreview = videoPreviewUrl || url;
|
|
1028
|
+
} else if (type === GIF) {
|
|
1029
|
+
androidMediaType = GIF;
|
|
1030
|
+
androidVideoSrc = url;
|
|
1031
|
+
androidVideoPreview = url;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// Also check root level type
|
|
1036
|
+
if (androidType === VIDEO || androidType === GIF || androidType === CAROUSEL) {
|
|
1037
|
+
androidMediaType = androidType;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
// Handle CTA data
|
|
1041
|
+
const androidButtons = androidCtas || [];
|
|
1042
|
+
if (androidButtons.length > 0) {
|
|
1043
|
+
const ctaDataFromAndroid = androidButtons.map((button, index) => {
|
|
1044
|
+
// Use deep link keys from the button if available, otherwise try to extract from URL
|
|
1045
|
+
let deepLinkKeys = button?.deepLinkKeys || [];
|
|
1046
|
+
if (!deepLinkKeys.length && button?.type === DEEP_LINK && button?.actionLink) {
|
|
1047
|
+
try {
|
|
1048
|
+
const url = new URL(button?.actionLink);
|
|
1049
|
+
const extractedKeys = [];
|
|
1050
|
+
url.searchParams.forEach((value, key) => {
|
|
1051
|
+
if (value === key) { // Only extract keys where value equals key
|
|
1052
|
+
extractedKeys.push(key);
|
|
1053
|
+
}
|
|
1054
|
+
});
|
|
1055
|
+
if (extractedKeys?.length > 0) {
|
|
1056
|
+
deepLinkKeys = extractedKeys;
|
|
1057
|
+
}
|
|
1058
|
+
} catch (error) {
|
|
1059
|
+
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
return {
|
|
1064
|
+
text: button?.actionText || "",
|
|
1065
|
+
url: (() => {
|
|
1066
|
+
const deepLinkValue = button?.actionLink || "";
|
|
1067
|
+
if (deepLink?.length > 0 && deepLinkValue && button?.type === DEEP_LINK) {
|
|
1068
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
1069
|
+
const match = deepLink.find((link) => link.value === baseDeepLinkValue);
|
|
1070
|
+
if (match) return match.value;
|
|
1071
|
+
}
|
|
1072
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
1073
|
+
})(),
|
|
1074
|
+
urlType: button?.type || DEEP_LINK,
|
|
1075
|
+
deepLinkKeys,
|
|
1076
|
+
ctaType: index === 0 ? PRIMARY : SECONDARY,
|
|
1077
|
+
isSaved: true,
|
|
1078
|
+
index,
|
|
1079
|
+
};
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
stateUpdates.push(() => setCtaDataAndroid(ctaDataFromAndroid));
|
|
1083
|
+
|
|
1084
|
+
const hasPrimaryButton = androidButtons.some((button, index) => index === 0 && button?.actionText);
|
|
1085
|
+
const hasSecondaryButton = androidButtons.some((button, index) => index === 1 && button?.actionText);
|
|
1086
|
+
|
|
1087
|
+
if (hasPrimaryButton) {
|
|
1088
|
+
stateUpdates.push(() => setPrimaryButtonAndroid(true));
|
|
1089
|
+
}
|
|
1090
|
+
if (hasSecondaryButton) {
|
|
1091
|
+
stateUpdates.push(() => setSecondaryButtonAndroid(true));
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// Process Android content
|
|
1096
|
+
const androidContentData = {
|
|
1097
|
+
title: androidTitle,
|
|
1098
|
+
message: androidMessage,
|
|
1099
|
+
mediaType: androidMediaType,
|
|
1100
|
+
imageSrc: androidImageSrc,
|
|
1101
|
+
videoSrc: androidVideoSrc,
|
|
1102
|
+
videoPreview: androidVideoPreview,
|
|
1103
|
+
carouselData: androidCarouselData,
|
|
1104
|
+
// Handle root level CTA
|
|
1105
|
+
actionOnClick: !!androidMainCta || !!androidContentType?.cta,
|
|
1106
|
+
linkType: (androidMainCta?.type === EXTERNAL_URL ? EXTERNAL_LINK : DEEP_LINK) || (androidContentType?.cta?.type === EXTERNAL_URL ? EXTERNAL_LINK : DEEP_LINK),
|
|
1107
|
+
deepLinkValue: (() => {
|
|
1108
|
+
// Get the deep link value
|
|
1109
|
+
const deepLinkValue = androidMainCta?.type === DEEP_LINK ? androidMainCta?.actionLink : (androidContentType?.cta?.type === DEEP_LINK ? androidContentType?.cta?.actionLink : "");
|
|
1110
|
+
|
|
1111
|
+
// If we have deep links available, find the matching one
|
|
1112
|
+
if (deepLink?.length > 0 && deepLinkValue) {
|
|
1113
|
+
// Try to find exact match first
|
|
1114
|
+
const exactMatch = deepLink.find((link) => link.value === deepLinkValue);
|
|
1115
|
+
if (exactMatch) {
|
|
1116
|
+
return exactMatch.value;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// Try to find match without query params
|
|
1120
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
1121
|
+
const partialMatch = deepLink.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
1122
|
+
if (partialMatch) {
|
|
1123
|
+
return partialMatch.value;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
// If no match found, return the base URL without query parameters
|
|
1128
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
1129
|
+
})(),
|
|
1130
|
+
deepLinkKeysValue: (() => {
|
|
1131
|
+
// Extract deep link keys from the URL
|
|
1132
|
+
const deepLinkValue = androidMainCta?.type === DEEP_LINK ? androidMainCta?.actionLink : (androidContentType?.cta?.type === DEEP_LINK ? androidContentType?.cta?.actionLink : "");
|
|
1133
|
+
if (deepLinkValue) {
|
|
1134
|
+
try {
|
|
1135
|
+
const url = new URL(deepLinkValue);
|
|
1136
|
+
const extractedKeys = [];
|
|
1137
|
+
url.searchParams.forEach((value, key) => {
|
|
1138
|
+
if (value === key) { // Only extract keys where value equals key
|
|
1139
|
+
extractedKeys.push(key);
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1142
|
+
return extractedKeys;
|
|
1143
|
+
} catch (error) {
|
|
1144
|
+
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
1145
|
+
return [];
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
return [];
|
|
1149
|
+
})(),
|
|
1150
|
+
externalLinkValue: androidMainCta?.type === EXTERNAL_URL ? androidMainCta?.actionLink : (androidContentType?.cta?.type === EXTERNAL_URL ? androidContentType?.cta?.actionLink : ""),
|
|
1151
|
+
};
|
|
1152
|
+
|
|
1153
|
+
stateUpdates.push(() => setAndroidContent(androidContentData));
|
|
1154
|
+
|
|
1155
|
+
// Set media sources for upload state
|
|
1156
|
+
if (androidImageSrc) {
|
|
1157
|
+
stateUpdates.push(() => setUpdateMpushImageSrc(androidImageSrc, 0, IMAGE));
|
|
1158
|
+
}
|
|
1159
|
+
if (androidVideoSrc) {
|
|
1160
|
+
stateUpdates.push(() => setUpdateMpushVideoSrc(0, {
|
|
1161
|
+
videoSrc: androidVideoSrc,
|
|
1162
|
+
previewUrl: androidVideoPreview,
|
|
1163
|
+
}, true)); // isInitialization = true
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
// Process iOS content
|
|
1168
|
+
const iosContentType = templateContent?.IOS;
|
|
1169
|
+
if (!isEmpty(iosContentType)) {
|
|
1170
|
+
const {
|
|
1171
|
+
title: iosTitle = "",
|
|
1172
|
+
message: iosMessage = "",
|
|
1173
|
+
expandableDetails: iosExpandableDetails = {},
|
|
1174
|
+
image: iosImage = "",
|
|
1175
|
+
cta: iosMainCta = null,
|
|
1176
|
+
type: iosType = "NONE", // Get the type from root level
|
|
1177
|
+
mediaType: iosMediaTypeFromRoot = "NONE", // Also check mediaType from root
|
|
1178
|
+
} = iosContentType || {};
|
|
1179
|
+
|
|
1180
|
+
const {
|
|
1181
|
+
style: iosStyle = "",
|
|
1182
|
+
ctas: iosCtas = [],
|
|
1183
|
+
image: iosExpandableImage = "",
|
|
1184
|
+
media: iosMedia = [],
|
|
1185
|
+
carouselData: iosCarouselData = [],
|
|
1186
|
+
mediaType: iosMediaTypeFromStyle = "NONE", // Also check mediaType from style
|
|
1187
|
+
} = iosExpandableDetails || {};
|
|
1188
|
+
|
|
1189
|
+
// Determine media type based on all available information
|
|
1190
|
+
let iosMediaType = "NONE";
|
|
1191
|
+
let iosImageSrc = "";
|
|
1192
|
+
let iosVideoSrc = "";
|
|
1193
|
+
let iosVideoPreview = "";
|
|
1194
|
+
|
|
1195
|
+
// First check expandableDetails.style
|
|
1196
|
+
if (iosStyle === BIG_PICTURE) {
|
|
1197
|
+
iosMediaType = IMAGE;
|
|
1198
|
+
iosImageSrc = iosExpandableImage || iosImage;
|
|
1199
|
+
} else if (iosStyle === MANUAL_CAROUSEL || iosStyle === AUTO_CAROUSEL || iosStyle === FILMSTRIP_CAROUSEL) {
|
|
1200
|
+
iosMediaType = CAROUSEL;
|
|
1201
|
+
} else if (iosStyle === BIG_TEXT) {
|
|
1202
|
+
iosMediaType = "NONE";
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// Then check media array for video/GIF
|
|
1206
|
+
if (iosMedia?.length > 0) {
|
|
1207
|
+
const mediaItem = iosMedia[0];
|
|
1208
|
+
const { type, url, videoPreviewUrl } = mediaItem || {};
|
|
1209
|
+
if (type === VIDEO) {
|
|
1210
|
+
// Check if it's actually a GIF
|
|
1211
|
+
if (url && url.toLowerCase().includes('.gif')) {
|
|
1212
|
+
iosMediaType = GIF;
|
|
1213
|
+
} else {
|
|
1214
|
+
iosMediaType = VIDEO;
|
|
1215
|
+
}
|
|
1216
|
+
iosVideoSrc = url;
|
|
1217
|
+
iosVideoPreview = videoPreviewUrl || url;
|
|
1218
|
+
} else if (type === GIF) {
|
|
1219
|
+
iosMediaType = GIF;
|
|
1220
|
+
iosVideoSrc = url;
|
|
1221
|
+
iosVideoPreview = url;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
// Check all possible media type sources
|
|
1226
|
+
if (iosType === VIDEO || iosType === GIF || iosType === CAROUSEL) {
|
|
1227
|
+
iosMediaType = iosType;
|
|
1228
|
+
}
|
|
1229
|
+
if (iosMediaTypeFromRoot === VIDEO || iosMediaTypeFromRoot === GIF || iosMediaTypeFromRoot === CAROUSEL || iosMediaTypeFromRoot === IMAGE) {
|
|
1230
|
+
iosMediaType = iosMediaTypeFromRoot;
|
|
1231
|
+
}
|
|
1232
|
+
if (iosMediaTypeFromStyle === VIDEO || iosMediaTypeFromStyle === GIF || iosMediaTypeFromStyle === CAROUSEL || iosMediaTypeFromStyle === IMAGE) {
|
|
1233
|
+
iosMediaType = iosMediaTypeFromStyle;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// Handle iOS CTA data
|
|
1237
|
+
const iosButtons = iosCtas || [];
|
|
1238
|
+
if (iosButtons.length > 0) {
|
|
1239
|
+
const ctaDataFromIos = iosButtons.map((button, index) => {
|
|
1240
|
+
// Use deep link keys from the button if available, otherwise try to extract from URL
|
|
1241
|
+
let deepLinkKeys = button?.deepLinkKeys || [];
|
|
1242
|
+
if (!deepLinkKeys?.length && button?.type === DEEP_LINK && button?.actionLink) {
|
|
1243
|
+
try {
|
|
1244
|
+
const url = new URL(button?.actionLink);
|
|
1245
|
+
const extractedKeys = [];
|
|
1246
|
+
url.searchParams.forEach((value, key) => {
|
|
1247
|
+
if (value === key) { // Only extract keys where value equals key
|
|
1248
|
+
extractedKeys.push(key);
|
|
1249
|
+
}
|
|
1250
|
+
});
|
|
1251
|
+
if (extractedKeys?.length > 0) {
|
|
1252
|
+
deepLinkKeys = extractedKeys;
|
|
1253
|
+
}
|
|
1254
|
+
} catch (error) {
|
|
1255
|
+
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
return {
|
|
1260
|
+
text: button?.actionText || "",
|
|
1261
|
+
url: (() => {
|
|
1262
|
+
const deepLinkValue = button?.actionLink || "";
|
|
1263
|
+
if (deepLink?.length > 0 && deepLinkValue && button?.type === DEEP_LINK) {
|
|
1264
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
1265
|
+
const match = deepLink.find((link) => link.value === baseDeepLinkValue);
|
|
1266
|
+
if (match) return match.value;
|
|
1267
|
+
}
|
|
1268
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
1269
|
+
})(),
|
|
1270
|
+
urlType: button?.type || DEEP_LINK,
|
|
1271
|
+
deepLinkKeys,
|
|
1272
|
+
ctaType: index === 0 ? PRIMARY : SECONDARY,
|
|
1273
|
+
isSaved: true,
|
|
1274
|
+
index,
|
|
1275
|
+
};
|
|
1276
|
+
});
|
|
1277
|
+
|
|
1278
|
+
stateUpdates.push(() => setCtaDataIos(ctaDataFromIos));
|
|
1279
|
+
|
|
1280
|
+
const hasPrimaryButton = iosButtons.some((button, index) => index === 0 && button?.actionText);
|
|
1281
|
+
const hasSecondaryButton = iosButtons.some((button, index) => index === 1 && button?.actionText);
|
|
1282
|
+
|
|
1283
|
+
if (hasPrimaryButton) {
|
|
1284
|
+
stateUpdates.push(() => setPrimaryButtonIos(true));
|
|
1285
|
+
}
|
|
1286
|
+
if (hasSecondaryButton) {
|
|
1287
|
+
stateUpdates.push(() => setSecondaryButtonIos(true));
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
// Process iOS content
|
|
1292
|
+
const iosContentData = {
|
|
1293
|
+
title: iosTitle,
|
|
1294
|
+
message: iosMessage,
|
|
1295
|
+
mediaType: iosMediaType,
|
|
1296
|
+
imageSrc: iosImageSrc,
|
|
1297
|
+
videoSrc: iosVideoSrc,
|
|
1298
|
+
videoPreview: iosVideoPreview,
|
|
1299
|
+
carouselData: iosCarouselData,
|
|
1300
|
+
// Handle root level CTA
|
|
1301
|
+
actionOnClick: !!iosMainCta || !!iosContentType?.cta,
|
|
1302
|
+
linkType: (iosMainCta?.type === EXTERNAL_URL ? EXTERNAL_LINK : DEEP_LINK) || (iosContentType?.cta?.type === EXTERNAL_URL ? EXTERNAL_LINK : DEEP_LINK),
|
|
1303
|
+
deepLinkValue: (() => {
|
|
1304
|
+
// Get the deep link value
|
|
1305
|
+
const deepLinkValue = iosMainCta?.type === DEEP_LINK ? iosMainCta?.actionLink : (iosContentType?.cta?.type === DEEP_LINK ? iosContentType?.cta?.actionLink : "");
|
|
1306
|
+
|
|
1307
|
+
// If we have deep links available, find the matching one
|
|
1308
|
+
if (deepLink?.length > 0 && deepLinkValue) {
|
|
1309
|
+
// Try to find exact match first
|
|
1310
|
+
const exactMatch = deepLink.find((link) => link.value === deepLinkValue);
|
|
1311
|
+
if (exactMatch) {
|
|
1312
|
+
return exactMatch.value;
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
// Try to find match without query params
|
|
1316
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
1317
|
+
const partialMatch = deepLink.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
1318
|
+
if (partialMatch) {
|
|
1319
|
+
return partialMatch.value;
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
// If no match found, return the base URL without query parameters
|
|
1324
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
1325
|
+
})(),
|
|
1326
|
+
deepLinkKeysValue: (() => {
|
|
1327
|
+
// Extract deep link keys from the URL
|
|
1328
|
+
const deepLinkValue = iosMainCta?.type === DEEP_LINK ? iosMainCta?.actionLink : (iosContentType?.cta?.type === DEEP_LINK ? iosContentType?.cta?.actionLink : "");
|
|
1329
|
+
if (deepLinkValue) {
|
|
1330
|
+
try {
|
|
1331
|
+
const url = new URL(deepLinkValue);
|
|
1332
|
+
const extractedKeys = [];
|
|
1333
|
+
url.searchParams.forEach((value, key) => {
|
|
1334
|
+
if (value === key) { // Only extract keys where value equals key
|
|
1335
|
+
extractedKeys.push(key);
|
|
1336
|
+
}
|
|
1337
|
+
});
|
|
1338
|
+
return extractedKeys;
|
|
1339
|
+
} catch (error) {
|
|
1340
|
+
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
1341
|
+
return [];
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
return [];
|
|
1345
|
+
})(),
|
|
1346
|
+
externalLinkValue: iosMainCta?.type === EXTERNAL_URL ? iosMainCta?.actionLink : (iosContentType?.cta?.type === EXTERNAL_URL ? iosContentType?.cta?.actionLink : ""),
|
|
1347
|
+
};
|
|
1348
|
+
|
|
1349
|
+
stateUpdates.push(() => setIosContent(iosContentData));
|
|
1350
|
+
|
|
1351
|
+
// Set media sources for upload state
|
|
1352
|
+
if (iosImageSrc) {
|
|
1353
|
+
stateUpdates.push(() => setUpdateMpushImageSrc(iosImageSrc, 1, IMAGE));
|
|
1354
|
+
}
|
|
1355
|
+
if (iosVideoSrc) {
|
|
1356
|
+
stateUpdates.push(() => setUpdateMpushVideoSrc(1, {
|
|
1357
|
+
videoSrc: iosVideoSrc,
|
|
1358
|
+
previewUrl: iosVideoPreview,
|
|
1359
|
+
}, true)); // isInitialization = true
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
// Execute all state updates
|
|
1364
|
+
stateUpdates.forEach((update) => {
|
|
1365
|
+
update();
|
|
1366
|
+
});
|
|
981
1367
|
|
|
982
1368
|
// Turn off spinner after all data is populated
|
|
983
1369
|
setSpin(false);
|
|
984
|
-
}, [templateData, isFullMode]);
|
|
1370
|
+
}, [templateData, isFullMode, deepLink, setUpdateMpushImageSrc, setUpdateMpushVideoSrc]);
|
|
985
1371
|
|
|
986
1372
|
// Determine platform support from accountData
|
|
987
1373
|
const isAndroidSupported = accountData?.configs?.android === '1';
|
|
@@ -1617,7 +2003,6 @@ const MobilePushNew = ({
|
|
|
1617
2003
|
mode: isEditMode ? EDIT : CREATE,
|
|
1618
2004
|
imageAdded: definitionMode === IMAGE.toLowerCase(),
|
|
1619
2005
|
});
|
|
1620
|
-
|
|
1621
2006
|
// --- BEGIN: Library mode communication fix ---
|
|
1622
2007
|
if (!isFullMode) {
|
|
1623
2008
|
// In library mode, only communicate to parent/callback, do NOT call create/edit API
|
|
@@ -318,6 +318,7 @@ export const Whatsapp = (props) => {
|
|
|
318
318
|
videoUrl = '',
|
|
319
319
|
documentUrl = '',
|
|
320
320
|
karixFileHandle = '',
|
|
321
|
+
hapticFileHandle = '',
|
|
321
322
|
buttonType: btnType = WHATSAPP_BUTTON_TYPES.NONE,
|
|
322
323
|
buttons = [],
|
|
323
324
|
videoPreviewImg = '',
|
|
@@ -338,14 +339,23 @@ export const Whatsapp = (props) => {
|
|
|
338
339
|
});
|
|
339
340
|
setWhatsappDocSource(documentUrl);
|
|
340
341
|
setWhatsappDocParams(whatsappDocParams);
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
342
|
+
if (host === HOST_HAPTIC) {
|
|
343
|
+
updateAssetList(transformToVendorFormat({
|
|
344
|
+
...assetList,
|
|
345
|
+
previewUrl: videoPreviewImg,
|
|
346
|
+
videoSrc: videoUrl,
|
|
347
|
+
fileHandle: hapticFileHandle,
|
|
348
|
+
}, VENDOR_TYPES.HAPTIC));
|
|
349
|
+
} else {
|
|
350
|
+
updateAssetList({
|
|
351
|
+
...assetList,
|
|
352
|
+
previewUrl: videoPreviewImg,
|
|
353
|
+
videoSrc: videoUrl,
|
|
354
|
+
fileHandle: karixFileHandle,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
347
357
|
if (isHaptic) {
|
|
348
|
-
setHapticFileHandle(
|
|
358
|
+
setHapticFileHandle(hapticFileHandle);
|
|
349
359
|
} else {
|
|
350
360
|
setKarixFileHandle(karixFileHandle);
|
|
351
361
|
}
|
|
@@ -1125,8 +1135,8 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
|
|
|
1125
1135
|
};
|
|
1126
1136
|
|
|
1127
1137
|
// Handle vendor-specific updates
|
|
1128
|
-
const handleVideoUploadUpdate = (index, data
|
|
1129
|
-
if (host === HOST_HAPTIC
|
|
1138
|
+
const handleVideoUploadUpdate = (index, data) => {
|
|
1139
|
+
if (host === HOST_HAPTIC) {
|
|
1130
1140
|
// Transform back to HAPTIC format
|
|
1131
1141
|
const hapticData = transformToVendorFormat(data, VENDOR_TYPES.HAPTIC);
|
|
1132
1142
|
setUpdateWhatsappVideoSrc(index, hapticData);
|
|
@@ -1143,11 +1153,11 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
|
|
|
1143
1153
|
handleCarouselValueChange(parseInt(activeIndex, 10), [{fieldName: "videoSrc", value: videoSrc}, {fieldName: "videoPreviewImg", value: previewUrl}, {fieldName: "assetList", value: data}, {fieldName: "karixFileHandle", value: fileHandle}]);
|
|
1144
1154
|
} else {
|
|
1145
1155
|
setWhatsappVideoSrcAndPreview({
|
|
1146
|
-
whatsappVideoSrc: videoSrc,
|
|
1147
|
-
whatsappVideoPreviewImg: previewUrl,
|
|
1156
|
+
whatsappVideoSrc: host === HOST_HAPTIC ? data?.metaInfo?.secure_file_path : videoSrc,
|
|
1157
|
+
whatsappVideoPreviewImg: host === HOST_HAPTIC ? data?.previewUrl : previewUrl,
|
|
1148
1158
|
});
|
|
1149
1159
|
if (isHaptic) {
|
|
1150
|
-
setHapticFileHandle(fileHandle);
|
|
1160
|
+
setHapticFileHandle(data?.metaInfo?.hapticFileHandle || fileHandle);
|
|
1151
1161
|
} else {
|
|
1152
1162
|
setKarixFileHandle(fileHandle);
|
|
1153
1163
|
}
|