@capillarytech/creatives-library 8.0.132 → 8.0.133-alpha.1
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 +42 -39
- package/utils/tests/createMobilePushPayload.test.js +3 -3
- package/utils/transformerUtils.js +11 -12
- package/v2Components/CapMpushCTA/index.js +0 -11
- package/v2Containers/CreativesContainer/SlideBoxContent.js +1 -0
- package/v2Containers/CreativesContainer/index.js +2 -2
- package/v2Containers/MobilePushNew/components/MediaUploaders.js +7 -7
- package/v2Containers/MobilePushNew/components/PlatformContentFields.js +1 -3
- package/v2Containers/MobilePushNew/index.js +526 -49
- package/v2Containers/MobilePushNew/messages.js +1 -1
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
|
|
|
@@ -137,6 +138,7 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
|
|
|
137
138
|
linkType,
|
|
138
139
|
deepLinkValue,
|
|
139
140
|
externalLinkValue,
|
|
141
|
+
deepLinkKeysValue = [],
|
|
140
142
|
} = content || {};
|
|
141
143
|
|
|
142
144
|
const platformContent = {
|
|
@@ -148,28 +150,48 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
|
|
|
148
150
|
|
|
149
151
|
// Handle CTA
|
|
150
152
|
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
|
+
|
|
151
165
|
platformContent.cta = {
|
|
152
166
|
type: linkType === DEEP_LINK ? DEEP_LINK : EXTERNAL_URL,
|
|
153
|
-
actionLink: linkType === DEEP_LINK ?
|
|
167
|
+
actionLink: linkType === DEEP_LINK ? finalDeepLinkValue : externalLinkValue,
|
|
154
168
|
};
|
|
155
169
|
}
|
|
156
170
|
|
|
157
171
|
// Handle media types
|
|
158
172
|
const style = content?.mediaType || expandableDetails?.style;
|
|
159
173
|
|
|
174
|
+
// Determine the type field based on media type
|
|
175
|
+
let templateType = TEXT; // Default type for NONE or BIG_TEXT
|
|
176
|
+
|
|
160
177
|
// Handle BIG_PICTURE media type
|
|
161
178
|
if (style === BIG_PICTURE || style === IMAGE) {
|
|
162
179
|
platformContent.expandableDetails.style = BIG_PICTURE;
|
|
180
|
+
platformContent.expandableDetails.message = message;
|
|
163
181
|
platformContent.expandableDetails.image = imageSrc;
|
|
182
|
+
templateType = IMAGE;
|
|
164
183
|
} else if (style === VIDEO) { // Handle VIDEO media type
|
|
165
184
|
platformContent.expandableDetails.style = VIDEO;
|
|
185
|
+
platformContent.expandableDetails.message = message;
|
|
166
186
|
platformContent.expandableDetails.media = [{
|
|
167
187
|
url: mpushVideoSrcAndPreview.mpushVideoSrc || (content?.mediaList?.[0]?.url || ''),
|
|
168
188
|
text: content?.mediaList?.[0]?.text || '',
|
|
169
189
|
type: VIDEO,
|
|
170
190
|
}];
|
|
191
|
+
templateType = VIDEO;
|
|
171
192
|
} else if (style === GIF) { // Handle GIF media type
|
|
172
193
|
platformContent.expandableDetails.style = GIF;
|
|
194
|
+
platformContent.expandableDetails.message = message;
|
|
173
195
|
if (content?.mediaList?.[0]) {
|
|
174
196
|
// If mediaList exists, use it and preserve the original type
|
|
175
197
|
const { url = '', text = '', type = GIF } = content.mediaList[0];
|
|
@@ -179,15 +201,20 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
|
|
|
179
201
|
type: type.toLowerCase(),
|
|
180
202
|
}];
|
|
181
203
|
} else {
|
|
182
|
-
// If no mediaList but mpushVideoSrc exists
|
|
204
|
+
// If no mediaList but mpushVideoSrc exists
|
|
205
|
+
platformContent.expandableDetails.style = GIF;
|
|
206
|
+
platformContent.expandableDetails.message = message;
|
|
183
207
|
platformContent.expandableDetails.media = [{
|
|
184
208
|
url: mpushVideoSrcAndPreview.mpushVideoSrc,
|
|
185
209
|
text: '',
|
|
186
210
|
type: GIF, // Backend expects GIF type for GIFs
|
|
187
211
|
}];
|
|
188
212
|
}
|
|
213
|
+
templateType = GIF;
|
|
189
214
|
} else if ([CAROUSEL, MANUAL_CAROUSEL, AUTO_CAROUSEL, FILMSTRIP_CAROUSEL].includes(style)) { // Handle CAROUSEL media types
|
|
190
215
|
platformContent.expandableDetails.style = MANUAL_CAROUSEL;
|
|
216
|
+
platformContent.expandableDetails.message = message;
|
|
217
|
+
templateType = CAROUSEL;
|
|
191
218
|
|
|
192
219
|
// Handle carouselData
|
|
193
220
|
if (content?.carouselData?.length > 0) {
|
|
@@ -221,8 +248,8 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
|
|
|
221
248
|
}
|
|
222
249
|
|
|
223
250
|
// Handle mediaList
|
|
224
|
-
if (content?.mediaList && Array.isArray(content
|
|
225
|
-
platformContent.expandableDetails.media = content
|
|
251
|
+
if (content?.mediaList && Array.isArray(content?.mediaList) && content?.mediaList?.length > 0) {
|
|
252
|
+
platformContent.expandableDetails.media = content?.mediaList?.map((media) => {
|
|
226
253
|
const {
|
|
227
254
|
url,
|
|
228
255
|
text,
|
|
@@ -239,18 +266,14 @@ function buildPlatformContent(content, imageSrc, mpushVideoSrcAndPreview, platfo
|
|
|
239
266
|
} else { // Handle BIG_TEXT media type (default)
|
|
240
267
|
platformContent.expandableDetails.style = BIG_TEXT;
|
|
241
268
|
platformContent.expandableDetails.message = message;
|
|
269
|
+
templateType = TEXT;
|
|
242
270
|
}
|
|
243
271
|
|
|
272
|
+
// Set the type and deviceType fields
|
|
273
|
+
platformContent.type = templateType;
|
|
274
|
+
platformContent.deviceType = platform;
|
|
275
|
+
|
|
244
276
|
// 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
|
-
}
|
|
254
277
|
|
|
255
278
|
// iOS-specific handling
|
|
256
279
|
if (platform === IOS) {
|
|
@@ -273,31 +296,11 @@ function buildCustomFields(content) {
|
|
|
273
296
|
if (Array.isArray(custom)) {
|
|
274
297
|
customFields = [...custom];
|
|
275
298
|
} else if (custom && typeof custom === 'object') {
|
|
276
|
-
// If it's an object, map to array
|
|
277
|
-
customFields = Object.entries(custom)
|
|
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 }));
|
|
278
303
|
}
|
|
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
|
-
|
|
301
304
|
return customFields;
|
|
302
305
|
}
|
|
303
306
|
|
|
@@ -307,14 +310,14 @@ function buildCustomFields(content) {
|
|
|
307
310
|
* @param {Array} keys - Deep link keys
|
|
308
311
|
* @returns {string} URL with appended keys
|
|
309
312
|
*/
|
|
310
|
-
function appendDeepLinkKeysToUrl(url, keys) {
|
|
313
|
+
export function appendDeepLinkKeysToUrl(url, keys) {
|
|
311
314
|
if (!url || !keys || !Array.isArray(keys) || keys?.length === 0) return url;
|
|
312
315
|
|
|
313
316
|
const separator = url.includes('?') ? '&' : '?';
|
|
314
317
|
const validKeys = keys.filter((key) => typeof key === 'string' && key?.length > 0);
|
|
315
318
|
if (validKeys?.length === 0) return url;
|
|
316
319
|
|
|
317
|
-
const keyParams = validKeys.map((key) => `${key}
|
|
320
|
+
const keyParams = validKeys.map((key) => `${key}=${key}`).join('&');
|
|
318
321
|
|
|
319
322
|
return `${url}${separator}${keyParams}`;
|
|
320
323
|
}
|
|
@@ -893,7 +893,7 @@ describe('createMobilePushPayload', () => {
|
|
|
893
893
|
});
|
|
894
894
|
|
|
895
895
|
expect(result.versions.base.ANDROID.expandableDetails.carouselData[0].buttons[0].deepLinkValue)
|
|
896
|
-
.toBe('app://test?key1=
|
|
896
|
+
.toBe('app://test?key1=key1&key2=key2');
|
|
897
897
|
});
|
|
898
898
|
|
|
899
899
|
it('should handle single deep link key in carousel buttons', () => {
|
|
@@ -922,7 +922,7 @@ describe('createMobilePushPayload', () => {
|
|
|
922
922
|
});
|
|
923
923
|
|
|
924
924
|
expect(result.versions.base.ANDROID.expandableDetails.carouselData[0].buttons[0].deepLinkValue)
|
|
925
|
-
.toBe('app://test?singleKey=
|
|
925
|
+
.toBe('app://test?singleKey=singleKey');
|
|
926
926
|
});
|
|
927
927
|
|
|
928
928
|
it('should handle URL with existing query parameters', () => {
|
|
@@ -951,7 +951,7 @@ describe('createMobilePushPayload', () => {
|
|
|
951
951
|
});
|
|
952
952
|
|
|
953
953
|
expect(result.versions.base.ANDROID.expandableDetails.carouselData[0].buttons[0].deepLinkValue)
|
|
954
|
-
.toBe('app://test?param=value&key1=
|
|
954
|
+
.toBe('app://test?param=value&key1=key1&key2=key2');
|
|
955
955
|
});
|
|
956
956
|
|
|
957
957
|
it('should not modify URL when deepLinkKeys is missing', () => {
|
|
@@ -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
|
};
|
|
@@ -242,17 +242,6 @@ export const CapMpushCTA = (props) => {
|
|
|
242
242
|
{urlType === DEEP_LINK ? selectedDeepLink?.label : ''}
|
|
243
243
|
</CapColumn>
|
|
244
244
|
<CapColumn>
|
|
245
|
-
{urlType === DEEP_LINK && deepLinkKeysFromSelectionArray?.length > 0 && (ctaData[index]?.deepLinkKeys || selectedDeepLink?.keys) ? (
|
|
246
|
-
<CapLabel type="label2" className="inapp-saved-cta-deep-link-keys">
|
|
247
|
-
{(() => {
|
|
248
|
-
const keys = selectedDeepLink?.keys || ctaData[index]?.deepLinkKeys;
|
|
249
|
-
if (Array.isArray(keys)) {
|
|
250
|
-
return keys.join(', ');
|
|
251
|
-
}
|
|
252
|
-
return keys;
|
|
253
|
-
})()}
|
|
254
|
-
</CapLabel>
|
|
255
|
-
) : ''}
|
|
256
245
|
</CapColumn>
|
|
257
246
|
{(
|
|
258
247
|
<CapRow className="cta-action-grp">
|
|
@@ -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";
|
|
@@ -549,7 +549,7 @@ const MediaUploaders = ({
|
|
|
549
549
|
<FormattedMessage {...messages.actionDescription} />
|
|
550
550
|
</CapLabel>
|
|
551
551
|
</CapRow>
|
|
552
|
-
{button
|
|
552
|
+
{button?.actionOnClick && (
|
|
553
553
|
<CapRow style={{ display: "flex", justifyContent: "space-around" }}>
|
|
554
554
|
<CapColumn span={6}>
|
|
555
555
|
<CapHeading type="h4" className="buttons-heading">
|
|
@@ -563,7 +563,7 @@ const MediaUploaders = ({
|
|
|
563
563
|
selectPlaceholder={formatMessage(messages.selectDeepLink)}
|
|
564
564
|
/>
|
|
565
565
|
</CapColumn>
|
|
566
|
-
{button
|
|
566
|
+
{button?.linkType === DEEP_LINK && (
|
|
567
567
|
<CapColumn span={14}>
|
|
568
568
|
<CapHeading type="h4" className="buttons-heading">
|
|
569
569
|
{formatMessage(messages.deepLink)}
|
|
@@ -583,7 +583,7 @@ const MediaUploaders = ({
|
|
|
583
583
|
)}
|
|
584
584
|
</CapColumn>
|
|
585
585
|
)}
|
|
586
|
-
{button
|
|
586
|
+
{button?.linkType === EXTERNAL_LINK && (
|
|
587
587
|
<CapColumn span={14}>
|
|
588
588
|
<CapHeading type="h4" className="buttons-heading">
|
|
589
589
|
{formatMessage(messages.externalLink)}
|
|
@@ -592,7 +592,7 @@ const MediaUploaders = ({
|
|
|
592
592
|
id={`mobile-push-external-link-input-${activeTab}-${cardIndex}`}
|
|
593
593
|
onChange={(e) => handleCarouselExternalLinkChange(cardIndex, e.target.value)}
|
|
594
594
|
placeholder={formatMessage(messages.enterExternalLink)}
|
|
595
|
-
value={button
|
|
595
|
+
value={button?.externalLinkValue}
|
|
596
596
|
size="default"
|
|
597
597
|
isRequired
|
|
598
598
|
/>
|
|
@@ -605,8 +605,8 @@ const MediaUploaders = ({
|
|
|
605
605
|
)}
|
|
606
606
|
</CapRow>
|
|
607
607
|
)}
|
|
608
|
-
{button
|
|
609
|
-
const selectedDeepLink = deepLink?.find((link) => link?.value === button
|
|
608
|
+
{button?.linkType === DEEP_LINK && button?.deepLinkValue && button?.actionOnClick && (() => {
|
|
609
|
+
const selectedDeepLink = deepLink?.find((link) => link?.value === button?.deepLinkValue);
|
|
610
610
|
const deepLinkKeysFromSelection = selectedDeepLink?.keys;
|
|
611
611
|
let deepLinkKeysFromSelectionArray = [];
|
|
612
612
|
if (Array.isArray(deepLinkKeysFromSelection)) {
|
|
@@ -617,7 +617,7 @@ const MediaUploaders = ({
|
|
|
617
617
|
return deepLinkKeysFromSelectionArray?.length > 0;
|
|
618
618
|
})() && (
|
|
619
619
|
<CapRow style={{ marginTop: "10px", left: "6%", width: '115%'}}>
|
|
620
|
-
<CapColumn span={
|
|
620
|
+
<CapColumn span={14}>
|
|
621
621
|
<CapHeading type="h4" className="deep-link-keys-heading">
|
|
622
622
|
{formatMessage(messages.deepLinkKeys)}
|
|
623
623
|
</CapHeading>
|
|
@@ -58,8 +58,6 @@ const PlatformContentFields = ({
|
|
|
58
58
|
externalLinkValue,
|
|
59
59
|
} = linkProps;
|
|
60
60
|
|
|
61
|
-
// Debug logging removed - issue identified and fixed
|
|
62
|
-
|
|
63
61
|
// Get the selected deep link object to extract keys
|
|
64
62
|
const selectedDeepLink = deepLink?.find((link) => link?.value === deepLinkValue);
|
|
65
63
|
const deepLinkKeysFromSelection = selectedDeepLink?.keys;
|
|
@@ -289,7 +287,7 @@ const PlatformContentFields = ({
|
|
|
289
287
|
)}
|
|
290
288
|
{content?.actionOnClick && content?.linkType === DEEP_LINK && deepLinkValue && deepLinkKeysFromSelectionArray?.length > 0 && (
|
|
291
289
|
<CapRow style={{ marginTop: "10px", left: "6%", width: '115%'}}>
|
|
292
|
-
<CapColumn span={
|
|
290
|
+
<CapColumn span={14}>
|
|
293
291
|
<CapHeading type="h4" className="deep-link-keys-heading">
|
|
294
292
|
{formatMessage(messages.deepLinkKeys)}
|
|
295
293
|
</CapHeading>
|
|
@@ -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 = "";
|
|
@@ -629,13 +626,14 @@ const MobilePushNew = ({
|
|
|
629
626
|
const androidButtons = androidCtas || [];
|
|
630
627
|
if (androidButtons.length > 0) {
|
|
631
628
|
const ctaDataFromAndroid = androidButtons.map((button, index) => {
|
|
632
|
-
|
|
633
|
-
|
|
629
|
+
// Use deep link keys from the button if available, otherwise try to extract from URL
|
|
630
|
+
let deepLinkKeys = button?.deepLinkKeys || [];
|
|
631
|
+
if (!deepLinkKeys.length && button?.type === DEEP_LINK && button?.actionLink) {
|
|
634
632
|
try {
|
|
635
633
|
const url = new URL(button?.actionLink);
|
|
636
634
|
const extractedKeys = [];
|
|
637
635
|
url.searchParams.forEach((value, key) => {
|
|
638
|
-
if (value === key) {
|
|
636
|
+
if (value === key) { // Only extract keys where value equals key
|
|
639
637
|
extractedKeys.push(key);
|
|
640
638
|
}
|
|
641
639
|
});
|
|
@@ -649,7 +647,15 @@ const MobilePushNew = ({
|
|
|
649
647
|
|
|
650
648
|
return {
|
|
651
649
|
text: button?.actionText || "",
|
|
652
|
-
url:
|
|
650
|
+
url: (() => {
|
|
651
|
+
const deepLinkValue = button?.actionLink || "";
|
|
652
|
+
if (deepLink?.length > 0 && deepLinkValue && button?.type === DEEP_LINK) {
|
|
653
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
654
|
+
const match = deepLink.find((link) => link.value === baseDeepLinkValue);
|
|
655
|
+
if (match) return match.value;
|
|
656
|
+
}
|
|
657
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
658
|
+
})(),
|
|
653
659
|
urlType: button?.type || DEEP_LINK,
|
|
654
660
|
deepLinkKeys,
|
|
655
661
|
ctaType: index === 0 ? PRIMARY : SECONDARY,
|
|
@@ -688,7 +694,7 @@ const MobilePushNew = ({
|
|
|
688
694
|
const deepLinkValue = androidMainCta?.type === DEEP_LINK ? androidMainCta?.actionLink : (androidContentType?.cta?.type === DEEP_LINK ? androidContentType?.cta?.actionLink : "");
|
|
689
695
|
|
|
690
696
|
// If we have deep links available, find the matching one
|
|
691
|
-
if (deepLink?.length > 0) {
|
|
697
|
+
if (deepLink?.length > 0 && deepLinkValue) {
|
|
692
698
|
// Try to find exact match first
|
|
693
699
|
const exactMatch = deepLink.find((link) => link.value === deepLinkValue);
|
|
694
700
|
if (exactMatch) {
|
|
@@ -703,7 +709,8 @@ const MobilePushNew = ({
|
|
|
703
709
|
}
|
|
704
710
|
}
|
|
705
711
|
|
|
706
|
-
return
|
|
712
|
+
// If no match found, return the base URL without query parameters
|
|
713
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
707
714
|
})(),
|
|
708
715
|
deepLinkKeysValue: (() => {
|
|
709
716
|
// Extract deep link keys from the URL
|
|
@@ -815,13 +822,14 @@ const MobilePushNew = ({
|
|
|
815
822
|
const iosButtons = iosCtas || [];
|
|
816
823
|
if (iosButtons.length > 0) {
|
|
817
824
|
const ctaDataFromIos = iosButtons.map((button, index) => {
|
|
818
|
-
|
|
819
|
-
|
|
825
|
+
// Use deep link keys from the button if available, otherwise try to extract from URL
|
|
826
|
+
let deepLinkKeys = button?.deepLinkKeys || [];
|
|
827
|
+
if (!deepLinkKeys?.length && button?.type === DEEP_LINK && button?.actionLink) {
|
|
820
828
|
try {
|
|
821
829
|
const url = new URL(button?.actionLink);
|
|
822
830
|
const extractedKeys = [];
|
|
823
831
|
url.searchParams.forEach((value, key) => {
|
|
824
|
-
if (value === key) {
|
|
832
|
+
if (value === key) { // Only extract keys where value equals key
|
|
825
833
|
extractedKeys.push(key);
|
|
826
834
|
}
|
|
827
835
|
});
|
|
@@ -835,7 +843,15 @@ const MobilePushNew = ({
|
|
|
835
843
|
|
|
836
844
|
return {
|
|
837
845
|
text: button?.actionText || "",
|
|
838
|
-
url:
|
|
846
|
+
url: (() => {
|
|
847
|
+
const deepLinkValue = button?.actionLink || "";
|
|
848
|
+
if (deepLink?.length > 0 && deepLinkValue && button?.type === DEEP_LINK) {
|
|
849
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
850
|
+
const match = deepLink.find((link) => link.value === baseDeepLinkValue);
|
|
851
|
+
if (match) return match.value;
|
|
852
|
+
}
|
|
853
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
854
|
+
})(),
|
|
839
855
|
urlType: button?.type || DEEP_LINK,
|
|
840
856
|
deepLinkKeys,
|
|
841
857
|
ctaType: index === 0 ? PRIMARY : SECONDARY,
|
|
@@ -872,9 +888,9 @@ const MobilePushNew = ({
|
|
|
872
888
|
deepLinkValue: (() => {
|
|
873
889
|
// Get the deep link value
|
|
874
890
|
const deepLinkValue = iosMainCta?.type === DEEP_LINK ? iosMainCta?.actionLink : (iosContentType?.cta?.type === DEEP_LINK ? iosContentType?.cta?.actionLink : "");
|
|
875
|
-
|
|
891
|
+
|
|
876
892
|
// If we have deep links available, find the matching one
|
|
877
|
-
if (deepLink?.length > 0) {
|
|
893
|
+
if (deepLink?.length > 0 && deepLinkValue) {
|
|
878
894
|
// Try to find exact match first
|
|
879
895
|
const exactMatch = deepLink.find((link) => link.value === deepLinkValue);
|
|
880
896
|
if (exactMatch) {
|
|
@@ -889,7 +905,8 @@ const MobilePushNew = ({
|
|
|
889
905
|
}
|
|
890
906
|
}
|
|
891
907
|
|
|
892
|
-
return
|
|
908
|
+
// If no match found, return the base URL without query parameters
|
|
909
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
893
910
|
})(),
|
|
894
911
|
deepLinkKeysValue: (() => {
|
|
895
912
|
// Extract deep link keys from the URL
|
|
@@ -945,23 +962,412 @@ const MobilePushNew = ({
|
|
|
945
962
|
return;
|
|
946
963
|
}
|
|
947
964
|
|
|
948
|
-
// Do NOT reset form state here; only populate data
|
|
949
|
-
// resetFormData();
|
|
950
|
-
|
|
951
965
|
// templateData is expected to have a similar structure as editData.templateDetails
|
|
952
966
|
const { name = "", versions = {} } = templateData || {};
|
|
953
967
|
const templateContent = versions?.base || {};
|
|
954
|
-
|
|
955
968
|
if (isEmpty(templateContent)) {
|
|
956
969
|
setSpin(false);
|
|
957
970
|
return;
|
|
958
971
|
}
|
|
959
972
|
|
|
960
|
-
//
|
|
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
|
+
});
|
|
961
1367
|
|
|
962
1368
|
// Turn off spinner after all data is populated
|
|
963
1369
|
setSpin(false);
|
|
964
|
-
}, [templateData, isFullMode]);
|
|
1370
|
+
}, [templateData, isFullMode, deepLink, setUpdateMpushImageSrc, setUpdateMpushVideoSrc]);
|
|
965
1371
|
|
|
966
1372
|
// Determine platform support from accountData
|
|
967
1373
|
const isAndroidSupported = accountData?.configs?.android === '1';
|
|
@@ -1429,9 +1835,54 @@ const MobilePushNew = ({
|
|
|
1429
1835
|
setAndroidDeepLinkError(androidDeepLinkUrlError || "");
|
|
1430
1836
|
setIosDeepLinkError(iosDeepLinkUrlError || "");
|
|
1431
1837
|
|
|
1432
|
-
// Validate deep link keys
|
|
1433
|
-
const androidDeepLinkKeysErrorMsg =
|
|
1434
|
-
|
|
1838
|
+
// Validate deep link keys - only require keys if the selected deep link has keys defined
|
|
1839
|
+
const androidDeepLinkKeysErrorMsg = (() => {
|
|
1840
|
+
if (androidContent?.linkType === DEEP_LINK && androidContent?.deepLinkValue) {
|
|
1841
|
+
// Use the same matching logic as deep link value extraction
|
|
1842
|
+
let selectedDeepLink = null;
|
|
1843
|
+
|
|
1844
|
+
// Try to find exact match first
|
|
1845
|
+
selectedDeepLink = deepLink?.find((link) => link.value === androidContent?.deepLinkValue);
|
|
1846
|
+
|
|
1847
|
+
// If no exact match, try to find match without query params
|
|
1848
|
+
if (!selectedDeepLink && androidContent?.deepLinkValue) {
|
|
1849
|
+
const baseDeepLinkValue = androidContent?.deepLinkValue.split('?')[0];
|
|
1850
|
+
selectedDeepLink = deepLink?.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
const hasKeysDefined = selectedDeepLink?.keys && selectedDeepLink.keys.length > 0;
|
|
1854
|
+
|
|
1855
|
+
// Only require keys if the selected deep link has keys defined
|
|
1856
|
+
if (hasKeysDefined && (!Array.isArray(androidContent?.deepLinkKeysValue) || androidContent?.deepLinkKeysValue?.length === 0)) {
|
|
1857
|
+
return formatMessage(messages.deepLinkKeysRequired);
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
return "";
|
|
1861
|
+
})();
|
|
1862
|
+
|
|
1863
|
+
const iosDeepLinkKeysErrorMsg = (() => {
|
|
1864
|
+
if (iosContent?.linkType === DEEP_LINK && iosContent?.deepLinkValue) {
|
|
1865
|
+
// Use the same matching logic as deep link value extraction
|
|
1866
|
+
let selectedDeepLink = null;
|
|
1867
|
+
|
|
1868
|
+
// Try to find exact match first
|
|
1869
|
+
selectedDeepLink = deepLink?.find((link) => link.value === iosContent?.deepLinkValue);
|
|
1870
|
+
|
|
1871
|
+
// If no exact match, try to find match without query params
|
|
1872
|
+
if (!selectedDeepLink && iosContent?.deepLinkValue) {
|
|
1873
|
+
const baseDeepLinkValue = iosContent?.deepLinkValue.split('?')[0];
|
|
1874
|
+
selectedDeepLink = deepLink?.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
const hasKeysDefined = selectedDeepLink?.keys && selectedDeepLink.keys.length > 0;
|
|
1878
|
+
|
|
1879
|
+
// Only require keys if the selected deep link has keys defined
|
|
1880
|
+
if (hasKeysDefined && (!Array.isArray(iosContent?.deepLinkKeysValue) || iosContent?.deepLinkKeysValue?.length === 0)) {
|
|
1881
|
+
return formatMessage(messages.deepLinkKeysRequired);
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
return "";
|
|
1885
|
+
})();
|
|
1435
1886
|
|
|
1436
1887
|
setAndroidDeepLinkKeysError(androidDeepLinkKeysErrorMsg || "");
|
|
1437
1888
|
setIosDeepLinkKeysError(iosDeepLinkKeysErrorMsg || "");
|
|
@@ -1460,12 +1911,26 @@ const MobilePushNew = ({
|
|
|
1460
1911
|
if (savedCtas?.length > 0) {
|
|
1461
1912
|
processedAndroidContent.expandableDetails = {
|
|
1462
1913
|
...processedAndroidContent.expandableDetails,
|
|
1463
|
-
ctas: savedCtas.map((cta) =>
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1914
|
+
ctas: savedCtas.map((cta) => {
|
|
1915
|
+
let actionLink = cta?.url;
|
|
1916
|
+
|
|
1917
|
+
// Append deep link keys to URL if they exist
|
|
1918
|
+
if (cta?.urlType === DEEP_LINK && cta?.deepLinkKeys?.length > 0) {
|
|
1919
|
+
const deepLinkKeysArray = Array.isArray(cta?.deepLinkKeys) ? cta?.deepLinkKeys : [cta?.deepLinkKeys];
|
|
1920
|
+
const validKeys = deepLinkKeysArray.filter((key) => typeof key === 'string' && key?.length > 0);
|
|
1921
|
+
if (validKeys?.length > 0) {
|
|
1922
|
+
const separator = actionLink.includes('?') ? '&' : '?';
|
|
1923
|
+
const keyParams = validKeys.map((key) => `${key}={{${key}}}`).join('&');
|
|
1924
|
+
actionLink = `${actionLink}${separator}${keyParams}`;
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
return {
|
|
1929
|
+
actionText: cta?.text,
|
|
1930
|
+
type: cta?.urlType || DEEP_LINK,
|
|
1931
|
+
actionLink,
|
|
1932
|
+
};
|
|
1933
|
+
}),
|
|
1469
1934
|
};
|
|
1470
1935
|
}
|
|
1471
1936
|
}
|
|
@@ -1474,19 +1939,32 @@ const MobilePushNew = ({
|
|
|
1474
1939
|
if (savedCtas?.length > 0) {
|
|
1475
1940
|
processedIosContent.expandableDetails = {
|
|
1476
1941
|
...processedIosContent.expandableDetails,
|
|
1477
|
-
ctas: savedCtas.map((cta) =>
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1942
|
+
ctas: savedCtas.map((cta) => {
|
|
1943
|
+
let actionLink = cta?.url;
|
|
1944
|
+
|
|
1945
|
+
// Append deep link keys to URL if they exist
|
|
1946
|
+
if (cta?.urlType === DEEP_LINK && cta?.deepLinkKeys?.length > 0) {
|
|
1947
|
+
const deepLinkKeysArray = Array.isArray(cta?.deepLinkKeys) ? cta?.deepLinkKeys : [cta?.deepLinkKeys];
|
|
1948
|
+
const validKeys = deepLinkKeysArray.filter((key) => typeof key === 'string' && key?.length > 0);
|
|
1949
|
+
if (validKeys?.length > 0) {
|
|
1950
|
+
const separator = actionLink.includes('?') ? '&' : '?';
|
|
1951
|
+
const keyParams = validKeys.map((key) => `${key}={{${key}}}`).join('&');
|
|
1952
|
+
actionLink = `${actionLink}${separator}${keyParams}`;
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
return {
|
|
1957
|
+
actionText: cta?.text,
|
|
1958
|
+
type: cta?.urlType || DEEP_LINK,
|
|
1959
|
+
actionLink,
|
|
1960
|
+
};
|
|
1961
|
+
}),
|
|
1483
1962
|
};
|
|
1484
1963
|
}
|
|
1485
1964
|
}
|
|
1486
1965
|
|
|
1487
|
-
//
|
|
1488
|
-
const
|
|
1489
|
-
const payload = createPayload({
|
|
1966
|
+
// Create payload with enabled platform content and intl
|
|
1967
|
+
const payload = createMobilePushPayloadWithIntl({
|
|
1490
1968
|
templateName: finalTemplateName,
|
|
1491
1969
|
androidContent: isAndroidSupported ? processedAndroidContent : undefined,
|
|
1492
1970
|
iosContent: isIosSupported ? processedIosContent : undefined,
|
|
@@ -1525,7 +2003,6 @@ const MobilePushNew = ({
|
|
|
1525
2003
|
mode: isEditMode ? EDIT : CREATE,
|
|
1526
2004
|
imageAdded: definitionMode === IMAGE.toLowerCase(),
|
|
1527
2005
|
});
|
|
1528
|
-
|
|
1529
2006
|
// --- BEGIN: Library mode communication fix ---
|
|
1530
2007
|
if (!isFullMode) {
|
|
1531
2008
|
// In library mode, only communicate to parent/callback, do NOT call create/edit API
|
|
@@ -117,7 +117,7 @@ export default defineMessages({
|
|
|
117
117
|
},
|
|
118
118
|
deepLinkKeysPlaceholder: {
|
|
119
119
|
id: `${scope}.deepLinkKeysPlaceholder`,
|
|
120
|
-
defaultMessage: 'Please input {key}',
|
|
120
|
+
defaultMessage: 'Please input {key} here',
|
|
121
121
|
},
|
|
122
122
|
deepLinkKeysRequired: {
|
|
123
123
|
id: `${scope}.deepLinkKeysRequired`,
|