@capillarytech/creatives-library 8.0.136-beta.4 → 8.0.136
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 +1 -0
- package/utils/transformerUtils.js +0 -207
- package/v2Components/TemplatePreview/_templatePreview.scss +10 -1
- package/v2Containers/Line/Container/Image/index.js +3 -3
- package/v2Containers/Line/Container/Text/index.js +5 -5
- package/v2Containers/Line/Container/_lineCreate.scss +2 -0
- package/v2Containers/MobilePushNew/components/MediaUploaders.js +29 -4
- package/v2Containers/MobilePushNew/components/PlatformContentFields.js +21 -3
- package/v2Containers/MobilePushNew/constants.js +0 -1
- package/v2Containers/MobilePushNew/index.js +738 -182
- package/v2Containers/MobilePushNew/index.scss +48 -21
- package/v2Containers/Templates/index.js +33 -39
- package/v2Containers/Whatsapp/index.scss +6 -6
|
@@ -157,6 +157,9 @@ const MobilePushNew = ({
|
|
|
157
157
|
const prevUploadedAssetDataRef = useRef(null);
|
|
158
158
|
const prevVideoDataRef = useRef(null);
|
|
159
159
|
|
|
160
|
+
// Add ref to track current template name value
|
|
161
|
+
const templateNameRef = useRef("");
|
|
162
|
+
|
|
160
163
|
const videoData = useMemo(
|
|
161
164
|
() => {
|
|
162
165
|
const videoDataId = `vd_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
@@ -326,6 +329,7 @@ const MobilePushNew = ({
|
|
|
326
329
|
// Define resetFormData early to avoid initialization errors
|
|
327
330
|
const resetFormData = useCallback(() => {
|
|
328
331
|
setTemplateName("");
|
|
332
|
+
templateNameRef.current = "";
|
|
329
333
|
setAndroidContent({
|
|
330
334
|
title: "",
|
|
331
335
|
message: "",
|
|
@@ -559,7 +563,10 @@ const MobilePushNew = ({
|
|
|
559
563
|
const stateUpdates = [];
|
|
560
564
|
|
|
561
565
|
// Template name
|
|
562
|
-
stateUpdates.push(() =>
|
|
566
|
+
stateUpdates.push(() => {
|
|
567
|
+
setTemplateName(name);
|
|
568
|
+
templateNameRef.current = name;
|
|
569
|
+
});
|
|
563
570
|
|
|
564
571
|
// Process Android content
|
|
565
572
|
const androidContentType = editContent?.ANDROID;
|
|
@@ -630,18 +637,23 @@ const MobilePushNew = ({
|
|
|
630
637
|
let deepLinkKeys = button?.deepLinkKeys || [];
|
|
631
638
|
if (!deepLinkKeys.length && button?.type === DEEP_LINK && button?.actionLink) {
|
|
632
639
|
try {
|
|
633
|
-
|
|
634
|
-
const
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
640
|
+
// Extract query parameters from deep link URL using the same approach as main content
|
|
641
|
+
const deepLinkValue = button?.actionLink;
|
|
642
|
+
if (deepLinkValue && deepLinkValue.includes('?')) {
|
|
643
|
+
const queryString = deepLinkValue.split('?')[1];
|
|
644
|
+
const searchParams = new URLSearchParams(queryString);
|
|
645
|
+
const extractedKeys = [];
|
|
646
|
+
searchParams.forEach((value, key) => {
|
|
647
|
+
if (value === key) { // Only extract keys where value equals key
|
|
648
|
+
extractedKeys.push(key);
|
|
649
|
+
}
|
|
650
|
+
});
|
|
651
|
+
if (extractedKeys?.length > 0) {
|
|
652
|
+
deepLinkKeys = extractedKeys;
|
|
638
653
|
}
|
|
639
|
-
});
|
|
640
|
-
if (extractedKeys?.length > 0) {
|
|
641
|
-
deepLinkKeys = extractedKeys;
|
|
642
654
|
}
|
|
643
655
|
} catch (error) {
|
|
644
|
-
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
656
|
+
console.error("[MobilePushNew] Error extracting deep link keys from CTA button:", error);
|
|
645
657
|
}
|
|
646
658
|
}
|
|
647
659
|
|
|
@@ -677,6 +689,45 @@ const MobilePushNew = ({
|
|
|
677
689
|
}
|
|
678
690
|
}
|
|
679
691
|
|
|
692
|
+
// Determine actionOnClick and linkType for Android - prioritize CTA buttons for video, root level CTA for others, carousel data as fallback
|
|
693
|
+
const androidActionOnClick = (() => {
|
|
694
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
695
|
+
if (androidMediaType === VIDEO && androidButtons.length > 0) {
|
|
696
|
+
return true;
|
|
697
|
+
}
|
|
698
|
+
// If there's a root level CTA, use it
|
|
699
|
+
if (!!androidMainCta || !!androidContentType?.cta) {
|
|
700
|
+
return true;
|
|
701
|
+
}
|
|
702
|
+
// Otherwise, check carousel data
|
|
703
|
+
if (androidMediaType === CAROUSEL) {
|
|
704
|
+
const carouselLinkInfo = processCarouselDataForDeepLinks(androidCarouselData);
|
|
705
|
+
return carouselLinkInfo.deepLinkValue || carouselLinkInfo.externalLinkValue;
|
|
706
|
+
}
|
|
707
|
+
return false;
|
|
708
|
+
})();
|
|
709
|
+
|
|
710
|
+
const androidLinkType = (() => {
|
|
711
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
712
|
+
if (androidMediaType === VIDEO && androidButtons.length > 0) {
|
|
713
|
+
const firstButton = androidButtons[0];
|
|
714
|
+
return firstButton?.type === EXTERNAL_URL ? EXTERNAL_LINK : DEEP_LINK;
|
|
715
|
+
}
|
|
716
|
+
// If there's a root level CTA, use its type
|
|
717
|
+
if (androidMainCta?.type === EXTERNAL_URL || androidContentType?.cta?.type === EXTERNAL_URL) {
|
|
718
|
+
return EXTERNAL_LINK;
|
|
719
|
+
}
|
|
720
|
+
if (androidMainCta?.type === DEEP_LINK || androidContentType?.cta?.type === DEEP_LINK) {
|
|
721
|
+
return DEEP_LINK;
|
|
722
|
+
}
|
|
723
|
+
// Otherwise, check carousel data
|
|
724
|
+
if (androidMediaType === CAROUSEL) {
|
|
725
|
+
const carouselLinkInfo = processCarouselDataForDeepLinks(androidCarouselData);
|
|
726
|
+
return carouselLinkInfo.externalLinkValue ? EXTERNAL_LINK : DEEP_LINK;
|
|
727
|
+
}
|
|
728
|
+
return DEEP_LINK;
|
|
729
|
+
})();
|
|
730
|
+
|
|
680
731
|
// Process Android content
|
|
681
732
|
const androidContentData = {
|
|
682
733
|
title: androidTitle,
|
|
@@ -686,53 +737,145 @@ const MobilePushNew = ({
|
|
|
686
737
|
videoSrc: androidVideoSrc,
|
|
687
738
|
videoPreview: androidVideoPreview,
|
|
688
739
|
carouselData: androidCarouselData,
|
|
689
|
-
// Handle root level CTA
|
|
690
|
-
actionOnClick:
|
|
691
|
-
linkType:
|
|
740
|
+
// Handle root level CTA or carousel data
|
|
741
|
+
actionOnClick: androidActionOnClick,
|
|
742
|
+
linkType: androidLinkType,
|
|
692
743
|
deepLinkValue: (() => {
|
|
693
|
-
//
|
|
694
|
-
|
|
744
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
745
|
+
if (androidMediaType === VIDEO && androidButtons.length > 0) {
|
|
746
|
+
const firstButton = androidButtons[0];
|
|
747
|
+
if (firstButton?.type === DEEP_LINK && firstButton?.actionLink) {
|
|
748
|
+
const deepLinkValue = firstButton.actionLink;
|
|
749
|
+
|
|
750
|
+
// If we have deep links available, find the matching one
|
|
751
|
+
if (deepLink?.length > 0 && deepLinkValue) {
|
|
752
|
+
// Try to find exact match first
|
|
753
|
+
const exactMatch = deepLink.find((link) => link.value === deepLinkValue);
|
|
754
|
+
if (exactMatch) {
|
|
755
|
+
return exactMatch.value;
|
|
756
|
+
}
|
|
695
757
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
758
|
+
// Try to find match without query params
|
|
759
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
760
|
+
const partialMatch = deepLink.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
761
|
+
if (partialMatch) {
|
|
762
|
+
return partialMatch.value;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
703
765
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
const partialMatch = deepLink.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
707
|
-
if (partialMatch) {
|
|
708
|
-
return partialMatch.value;
|
|
766
|
+
// If no match found, return the base URL without query parameters
|
|
767
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
709
768
|
}
|
|
769
|
+
return "";
|
|
710
770
|
}
|
|
771
|
+
// If there's a root level CTA, use it
|
|
772
|
+
if (androidMainCta?.type === DEEP_LINK || androidContentType?.cta?.type === DEEP_LINK) {
|
|
773
|
+
const deepLinkValue = androidMainCta?.type === DEEP_LINK ? androidMainCta?.actionLink : androidContentType?.cta?.actionLink;
|
|
774
|
+
|
|
775
|
+
// If we have deep links available, find the matching one
|
|
776
|
+
if (deepLink?.length > 0 && deepLinkValue) {
|
|
777
|
+
// Try to find exact match first
|
|
778
|
+
const exactMatch = deepLink.find((link) => link.value === deepLinkValue);
|
|
779
|
+
if (exactMatch) {
|
|
780
|
+
return exactMatch.value;
|
|
781
|
+
}
|
|
711
782
|
|
|
712
|
-
|
|
713
|
-
|
|
783
|
+
// Try to find match without query params
|
|
784
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
785
|
+
const partialMatch = deepLink.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
786
|
+
if (partialMatch) {
|
|
787
|
+
return partialMatch.value;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// If no match found, return the base URL without query parameters
|
|
792
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
793
|
+
}
|
|
794
|
+
// Otherwise, check carousel data
|
|
795
|
+
if (androidMediaType === CAROUSEL) {
|
|
796
|
+
const carouselLinkInfo = processCarouselDataForDeepLinks(androidCarouselData);
|
|
797
|
+
return carouselLinkInfo.deepLinkValue;
|
|
798
|
+
}
|
|
799
|
+
return "";
|
|
714
800
|
})(),
|
|
715
801
|
deepLinkKeysValue: (() => {
|
|
716
|
-
//
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
const
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
802
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
803
|
+
if (androidMediaType === VIDEO && androidButtons.length > 0) {
|
|
804
|
+
const firstButton = androidButtons[0];
|
|
805
|
+
if (firstButton?.type === DEEP_LINK && firstButton?.actionLink) {
|
|
806
|
+
const deepLinkValue = firstButton.actionLink;
|
|
807
|
+
|
|
808
|
+
if (deepLinkValue && deepLinkValue.includes('?')) {
|
|
809
|
+
try {
|
|
810
|
+
// Extract query parameters from deep link URL
|
|
811
|
+
const queryString = deepLinkValue.split('?')[1];
|
|
812
|
+
const searchParams = new URLSearchParams(queryString);
|
|
813
|
+
const extractedKeys = [];
|
|
814
|
+
searchParams.forEach((value, key) => {
|
|
815
|
+
if (value === key) { // Only extract keys where value equals key
|
|
816
|
+
extractedKeys.push(key);
|
|
817
|
+
}
|
|
818
|
+
});
|
|
819
|
+
return extractedKeys;
|
|
820
|
+
} catch (error) {
|
|
821
|
+
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
822
|
+
return [];
|
|
725
823
|
}
|
|
726
|
-
}
|
|
727
|
-
return extractedKeys;
|
|
728
|
-
} catch (error) {
|
|
729
|
-
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
824
|
+
}
|
|
730
825
|
return [];
|
|
731
826
|
}
|
|
827
|
+
return [];
|
|
828
|
+
}
|
|
829
|
+
// If there's a root level CTA, extract keys from URL
|
|
830
|
+
if (androidMainCta?.type === DEEP_LINK || androidContentType?.cta?.type === DEEP_LINK) {
|
|
831
|
+
const deepLinkValue = androidMainCta?.type === DEEP_LINK ? androidMainCta?.actionLink : androidContentType?.cta?.actionLink;
|
|
832
|
+
|
|
833
|
+
if (deepLinkValue && deepLinkValue.includes('?')) {
|
|
834
|
+
try {
|
|
835
|
+
// Extract query parameters from deep link URL
|
|
836
|
+
const queryString = deepLinkValue.split('?')[1];
|
|
837
|
+
const searchParams = new URLSearchParams(queryString);
|
|
838
|
+
const extractedKeys = [];
|
|
839
|
+
searchParams.forEach((value, key) => {
|
|
840
|
+
if (value === key) { // Only extract keys where value equals key
|
|
841
|
+
extractedKeys.push(key);
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
return extractedKeys;
|
|
845
|
+
} catch (error) {
|
|
846
|
+
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
847
|
+
return [];
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
return [];
|
|
851
|
+
}
|
|
852
|
+
// Otherwise, check carousel data
|
|
853
|
+
if (androidMediaType === CAROUSEL) {
|
|
854
|
+
const carouselLinkInfo = processCarouselDataForDeepLinks(androidCarouselData);
|
|
855
|
+
return carouselLinkInfo.deepLinkKeysValue;
|
|
732
856
|
}
|
|
733
857
|
return [];
|
|
734
858
|
})(),
|
|
735
|
-
externalLinkValue:
|
|
859
|
+
externalLinkValue: (() => {
|
|
860
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
861
|
+
if (androidMediaType === VIDEO && androidButtons.length > 0) {
|
|
862
|
+
const firstButton = androidButtons[0];
|
|
863
|
+
if (firstButton?.type === EXTERNAL_URL) {
|
|
864
|
+
return firstButton?.actionLink || "";
|
|
865
|
+
}
|
|
866
|
+
return "";
|
|
867
|
+
}
|
|
868
|
+
// If there's a root level CTA, use it
|
|
869
|
+
if (androidMainCta?.type === EXTERNAL_URL || androidContentType?.cta?.type === EXTERNAL_URL) {
|
|
870
|
+
return androidMainCta?.type === EXTERNAL_URL ? androidMainCta?.actionLink : androidContentType?.cta?.actionLink;
|
|
871
|
+
}
|
|
872
|
+
// Otherwise, check carousel data
|
|
873
|
+
if (androidMediaType === CAROUSEL) {
|
|
874
|
+
const carouselLinkInfo = processCarouselDataForDeepLinks(androidCarouselData);
|
|
875
|
+
return carouselLinkInfo.externalLinkValue;
|
|
876
|
+
}
|
|
877
|
+
return "";
|
|
878
|
+
})(),
|
|
736
879
|
};
|
|
737
880
|
|
|
738
881
|
stateUpdates.push(() => setAndroidContent(androidContentData));
|
|
@@ -826,18 +969,23 @@ const MobilePushNew = ({
|
|
|
826
969
|
let deepLinkKeys = button?.deepLinkKeys || [];
|
|
827
970
|
if (!deepLinkKeys?.length && button?.type === DEEP_LINK && button?.actionLink) {
|
|
828
971
|
try {
|
|
829
|
-
|
|
830
|
-
const
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
972
|
+
// Extract query parameters from deep link URL using the same approach as main content
|
|
973
|
+
const deepLinkValue = button?.actionLink;
|
|
974
|
+
if (deepLinkValue && deepLinkValue.includes('?')) {
|
|
975
|
+
const queryString = deepLinkValue.split('?')[1];
|
|
976
|
+
const searchParams = new URLSearchParams(queryString);
|
|
977
|
+
const extractedKeys = [];
|
|
978
|
+
searchParams.forEach((value, key) => {
|
|
979
|
+
if (value === key) { // Only extract keys where value equals key
|
|
980
|
+
extractedKeys.push(key);
|
|
981
|
+
}
|
|
982
|
+
});
|
|
983
|
+
if (extractedKeys?.length > 0) {
|
|
984
|
+
deepLinkKeys = extractedKeys;
|
|
834
985
|
}
|
|
835
|
-
});
|
|
836
|
-
if (extractedKeys?.length > 0) {
|
|
837
|
-
deepLinkKeys = extractedKeys;
|
|
838
986
|
}
|
|
839
987
|
} catch (error) {
|
|
840
|
-
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
988
|
+
console.error("[MobilePushNew] Error extracting deep link keys from CTA button:", error);
|
|
841
989
|
}
|
|
842
990
|
}
|
|
843
991
|
|
|
@@ -873,6 +1021,45 @@ const MobilePushNew = ({
|
|
|
873
1021
|
}
|
|
874
1022
|
}
|
|
875
1023
|
|
|
1024
|
+
// Determine actionOnClick and linkType for iOS - prioritize CTA buttons for video, root level CTA for others, carousel data as fallback
|
|
1025
|
+
const iosActionOnClick = (() => {
|
|
1026
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
1027
|
+
if (iosMediaType === VIDEO && iosButtons.length > 0) {
|
|
1028
|
+
return true;
|
|
1029
|
+
}
|
|
1030
|
+
// If there's a root level CTA, use it
|
|
1031
|
+
if (!!iosMainCta || !!iosContentType?.cta) {
|
|
1032
|
+
return true;
|
|
1033
|
+
}
|
|
1034
|
+
// Otherwise, check carousel data
|
|
1035
|
+
if (iosMediaType === CAROUSEL) {
|
|
1036
|
+
const iosCarouselLinkInfo = processCarouselDataForDeepLinks(iosCarouselData);
|
|
1037
|
+
return iosCarouselLinkInfo.deepLinkValue || iosCarouselLinkInfo.externalLinkValue;
|
|
1038
|
+
}
|
|
1039
|
+
return false;
|
|
1040
|
+
})();
|
|
1041
|
+
|
|
1042
|
+
const iosLinkType = (() => {
|
|
1043
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
1044
|
+
if (iosMediaType === VIDEO && iosButtons.length > 0) {
|
|
1045
|
+
const firstButton = iosButtons[0];
|
|
1046
|
+
return firstButton?.type === EXTERNAL_URL ? EXTERNAL_LINK : DEEP_LINK;
|
|
1047
|
+
}
|
|
1048
|
+
// If there's a root level CTA, use its type
|
|
1049
|
+
if (iosMainCta?.type === EXTERNAL_URL || iosContentType?.cta?.type === EXTERNAL_URL) {
|
|
1050
|
+
return EXTERNAL_LINK;
|
|
1051
|
+
}
|
|
1052
|
+
if (iosMainCta?.type === DEEP_LINK || iosContentType?.cta?.type === DEEP_LINK) {
|
|
1053
|
+
return DEEP_LINK;
|
|
1054
|
+
}
|
|
1055
|
+
// Otherwise, check carousel data
|
|
1056
|
+
if (iosMediaType === CAROUSEL) {
|
|
1057
|
+
const iosCarouselLinkInfo = processCarouselDataForDeepLinks(iosCarouselData);
|
|
1058
|
+
return iosCarouselLinkInfo.externalLinkValue ? EXTERNAL_LINK : DEEP_LINK;
|
|
1059
|
+
}
|
|
1060
|
+
return DEEP_LINK;
|
|
1061
|
+
})();
|
|
1062
|
+
|
|
876
1063
|
// iOS content
|
|
877
1064
|
const iosContentData = {
|
|
878
1065
|
title: iosTitle,
|
|
@@ -882,53 +1069,83 @@ const MobilePushNew = ({
|
|
|
882
1069
|
videoSrc: iosVideoSrc,
|
|
883
1070
|
videoPreview: iosVideoPreview,
|
|
884
1071
|
carouselData: iosCarouselData,
|
|
885
|
-
// Handle root level CTA
|
|
886
|
-
actionOnClick:
|
|
887
|
-
linkType:
|
|
1072
|
+
// Handle root level CTA or carousel data
|
|
1073
|
+
actionOnClick: iosActionOnClick,
|
|
1074
|
+
linkType: iosLinkType,
|
|
888
1075
|
deepLinkValue: (() => {
|
|
889
|
-
//
|
|
890
|
-
|
|
1076
|
+
// If there's a root level CTA, use it
|
|
1077
|
+
if (iosMainCta?.type === DEEP_LINK || iosContentType?.cta?.type === DEEP_LINK) {
|
|
1078
|
+
const deepLinkValue = iosMainCta?.type === DEEP_LINK ? iosMainCta?.actionLink : iosContentType?.cta?.actionLink;
|
|
1079
|
+
|
|
1080
|
+
// If we have deep links available, find the matching one
|
|
1081
|
+
if (deepLink?.length > 0 && deepLinkValue) {
|
|
1082
|
+
// Try to find exact match first
|
|
1083
|
+
const exactMatch = deepLink.find((link) => link.value === deepLinkValue);
|
|
1084
|
+
if (exactMatch) {
|
|
1085
|
+
return exactMatch.value;
|
|
1086
|
+
}
|
|
891
1087
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
1088
|
+
// Try to find match without query params
|
|
1089
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
1090
|
+
const partialMatch = deepLink.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
1091
|
+
if (partialMatch) {
|
|
1092
|
+
return partialMatch.value;
|
|
1093
|
+
}
|
|
898
1094
|
}
|
|
899
1095
|
|
|
900
|
-
//
|
|
901
|
-
|
|
902
|
-
const partialMatch = deepLink.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
903
|
-
if (partialMatch) {
|
|
904
|
-
return partialMatch.value;
|
|
905
|
-
}
|
|
1096
|
+
// If no match found, return the base URL without query parameters
|
|
1097
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
906
1098
|
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1099
|
+
// Otherwise, check carousel data
|
|
1100
|
+
if (iosMediaType === CAROUSEL) {
|
|
1101
|
+
const iosCarouselLinkInfo = processCarouselDataForDeepLinks(iosCarouselData);
|
|
1102
|
+
return iosCarouselLinkInfo.deepLinkValue;
|
|
1103
|
+
}
|
|
1104
|
+
return "";
|
|
910
1105
|
})(),
|
|
911
1106
|
deepLinkKeysValue: (() => {
|
|
912
|
-
//
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1107
|
+
// If there's a root level CTA, extract keys from URL
|
|
1108
|
+
if (iosMainCta?.type === DEEP_LINK || iosContentType?.cta?.type === DEEP_LINK) {
|
|
1109
|
+
const deepLinkValue = iosMainCta?.type === DEEP_LINK ? iosMainCta?.actionLink : iosContentType?.cta?.actionLink;
|
|
1110
|
+
|
|
1111
|
+
if (deepLinkValue && deepLinkValue.includes('?')) {
|
|
1112
|
+
try {
|
|
1113
|
+
// Extract query parameters from deep link URL
|
|
1114
|
+
const queryString = deepLinkValue.split('?')[1];
|
|
1115
|
+
const searchParams = new URLSearchParams(queryString);
|
|
1116
|
+
const extractedKeys = [];
|
|
1117
|
+
searchParams.forEach((value, key) => {
|
|
1118
|
+
if (value === key) { // Only extract keys where value equals key
|
|
1119
|
+
extractedKeys.push(key);
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
return extractedKeys;
|
|
1123
|
+
} catch (error) {
|
|
1124
|
+
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
1125
|
+
return [];
|
|
1126
|
+
}
|
|
927
1127
|
}
|
|
1128
|
+
return [];
|
|
1129
|
+
}
|
|
1130
|
+
// Otherwise, check carousel data
|
|
1131
|
+
if (iosMediaType === CAROUSEL) {
|
|
1132
|
+
const iosCarouselLinkInfo = processCarouselDataForDeepLinks(iosCarouselData);
|
|
1133
|
+
return iosCarouselLinkInfo.deepLinkKeysValue;
|
|
928
1134
|
}
|
|
929
1135
|
return [];
|
|
930
1136
|
})(),
|
|
931
|
-
externalLinkValue:
|
|
1137
|
+
externalLinkValue: (() => {
|
|
1138
|
+
// If there's a root level CTA, use it
|
|
1139
|
+
if (iosMainCta?.type === EXTERNAL_URL || iosContentType?.cta?.type === EXTERNAL_URL) {
|
|
1140
|
+
return iosMainCta?.type === EXTERNAL_URL ? iosMainCta?.actionLink : iosContentType?.cta?.actionLink;
|
|
1141
|
+
}
|
|
1142
|
+
// Otherwise, check carousel data
|
|
1143
|
+
if (iosMediaType === CAROUSEL) {
|
|
1144
|
+
const iosCarouselLinkInfo = processCarouselDataForDeepLinks(iosCarouselData);
|
|
1145
|
+
return iosCarouselLinkInfo.externalLinkValue;
|
|
1146
|
+
}
|
|
1147
|
+
return "";
|
|
1148
|
+
})(),
|
|
932
1149
|
};
|
|
933
1150
|
|
|
934
1151
|
stateUpdates.push(() => setIosContent(iosContentData));
|
|
@@ -974,7 +1191,10 @@ const MobilePushNew = ({
|
|
|
974
1191
|
const stateUpdates = [];
|
|
975
1192
|
|
|
976
1193
|
// Template name
|
|
977
|
-
stateUpdates.push(() =>
|
|
1194
|
+
stateUpdates.push(() => {
|
|
1195
|
+
setTemplateName(name);
|
|
1196
|
+
templateNameRef.current = name;
|
|
1197
|
+
});
|
|
978
1198
|
|
|
979
1199
|
// Process Android content
|
|
980
1200
|
const androidContentType = templateContent?.ANDROID;
|
|
@@ -1045,18 +1265,23 @@ const MobilePushNew = ({
|
|
|
1045
1265
|
let deepLinkKeys = button?.deepLinkKeys || [];
|
|
1046
1266
|
if (!deepLinkKeys.length && button?.type === DEEP_LINK && button?.actionLink) {
|
|
1047
1267
|
try {
|
|
1048
|
-
|
|
1049
|
-
const
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1268
|
+
// Extract query parameters from deep link URL using the same approach as main content
|
|
1269
|
+
const deepLinkValue = button?.actionLink;
|
|
1270
|
+
if (deepLinkValue && deepLinkValue.includes('?')) {
|
|
1271
|
+
const queryString = deepLinkValue.split('?')[1];
|
|
1272
|
+
const searchParams = new URLSearchParams(queryString);
|
|
1273
|
+
const extractedKeys = [];
|
|
1274
|
+
searchParams.forEach((value, key) => {
|
|
1275
|
+
if (value === key) { // Only extract keys where value equals key
|
|
1276
|
+
extractedKeys.push(key);
|
|
1277
|
+
}
|
|
1278
|
+
});
|
|
1279
|
+
if (extractedKeys?.length > 0) {
|
|
1280
|
+
deepLinkKeys = extractedKeys;
|
|
1053
1281
|
}
|
|
1054
|
-
});
|
|
1055
|
-
if (extractedKeys?.length > 0) {
|
|
1056
|
-
deepLinkKeys = extractedKeys;
|
|
1057
1282
|
}
|
|
1058
1283
|
} catch (error) {
|
|
1059
|
-
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
1284
|
+
console.error("[MobilePushNew] Error extracting deep link keys from CTA button:", error);
|
|
1060
1285
|
}
|
|
1061
1286
|
}
|
|
1062
1287
|
|
|
@@ -1092,6 +1317,45 @@ const MobilePushNew = ({
|
|
|
1092
1317
|
}
|
|
1093
1318
|
}
|
|
1094
1319
|
|
|
1320
|
+
// Determine actionOnClick and linkType for Android - prioritize CTA buttons for video, root level CTA for others, carousel data as fallback
|
|
1321
|
+
const androidActionOnClick = (() => {
|
|
1322
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
1323
|
+
if (androidMediaType === VIDEO && androidButtons.length > 0) {
|
|
1324
|
+
return true;
|
|
1325
|
+
}
|
|
1326
|
+
// If there's a root level CTA, use it
|
|
1327
|
+
if (!!androidMainCta || !!androidContentType?.cta) {
|
|
1328
|
+
return true;
|
|
1329
|
+
}
|
|
1330
|
+
// Otherwise, check carousel data
|
|
1331
|
+
if (androidMediaType === CAROUSEL) {
|
|
1332
|
+
const carouselLinkInfo = processCarouselDataForDeepLinks(androidCarouselData);
|
|
1333
|
+
return carouselLinkInfo.deepLinkValue || carouselLinkInfo.externalLinkValue;
|
|
1334
|
+
}
|
|
1335
|
+
return false;
|
|
1336
|
+
})();
|
|
1337
|
+
|
|
1338
|
+
const androidLinkType = (() => {
|
|
1339
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
1340
|
+
if (androidMediaType === VIDEO && androidButtons.length > 0) {
|
|
1341
|
+
const firstButton = androidButtons[0];
|
|
1342
|
+
return firstButton?.type === EXTERNAL_URL ? EXTERNAL_LINK : DEEP_LINK;
|
|
1343
|
+
}
|
|
1344
|
+
// If there's a root level CTA, use its type
|
|
1345
|
+
if (androidMainCta?.type === EXTERNAL_URL || androidContentType?.cta?.type === EXTERNAL_URL) {
|
|
1346
|
+
return EXTERNAL_LINK;
|
|
1347
|
+
}
|
|
1348
|
+
if (androidMainCta?.type === DEEP_LINK || androidContentType?.cta?.type === DEEP_LINK) {
|
|
1349
|
+
return DEEP_LINK;
|
|
1350
|
+
}
|
|
1351
|
+
// Otherwise, check carousel data
|
|
1352
|
+
if (androidMediaType === CAROUSEL) {
|
|
1353
|
+
const carouselLinkInfo = processCarouselDataForDeepLinks(androidCarouselData);
|
|
1354
|
+
return carouselLinkInfo.externalLinkValue ? EXTERNAL_LINK : DEEP_LINK;
|
|
1355
|
+
}
|
|
1356
|
+
return DEEP_LINK;
|
|
1357
|
+
})();
|
|
1358
|
+
|
|
1095
1359
|
// Process Android content
|
|
1096
1360
|
const androidContentData = {
|
|
1097
1361
|
title: androidTitle,
|
|
@@ -1101,53 +1365,145 @@ const MobilePushNew = ({
|
|
|
1101
1365
|
videoSrc: androidVideoSrc,
|
|
1102
1366
|
videoPreview: androidVideoPreview,
|
|
1103
1367
|
carouselData: androidCarouselData,
|
|
1104
|
-
// Handle root level CTA
|
|
1105
|
-
actionOnClick:
|
|
1106
|
-
linkType:
|
|
1368
|
+
// Handle root level CTA or carousel data
|
|
1369
|
+
actionOnClick: androidActionOnClick,
|
|
1370
|
+
linkType: androidLinkType,
|
|
1107
1371
|
deepLinkValue: (() => {
|
|
1108
|
-
//
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1372
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
1373
|
+
if (androidMediaType === VIDEO && androidButtons.length > 0) {
|
|
1374
|
+
const firstButton = androidButtons[0];
|
|
1375
|
+
if (firstButton?.type === DEEP_LINK && firstButton?.actionLink) {
|
|
1376
|
+
const deepLinkValue = firstButton.actionLink;
|
|
1377
|
+
|
|
1378
|
+
// If we have deep links available, find the matching one
|
|
1379
|
+
if (deepLink?.length > 0 && deepLinkValue) {
|
|
1380
|
+
// Try to find exact match first
|
|
1381
|
+
const exactMatch = deepLink.find((link) => link.value === deepLinkValue);
|
|
1382
|
+
if (exactMatch) {
|
|
1383
|
+
return exactMatch.value;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
// Try to find match without query params
|
|
1387
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
1388
|
+
const partialMatch = deepLink.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
1389
|
+
if (partialMatch) {
|
|
1390
|
+
return partialMatch.value;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1118
1393
|
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
const partialMatch = deepLink.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
1122
|
-
if (partialMatch) {
|
|
1123
|
-
return partialMatch.value;
|
|
1394
|
+
// If no match found, return the base URL without query parameters
|
|
1395
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
1124
1396
|
}
|
|
1397
|
+
return "";
|
|
1125
1398
|
}
|
|
1399
|
+
// If there's a root level CTA, use it
|
|
1400
|
+
if (androidMainCta?.type === DEEP_LINK || androidContentType?.cta?.type === DEEP_LINK) {
|
|
1401
|
+
const deepLinkValue = androidMainCta?.type === DEEP_LINK ? androidMainCta?.actionLink : androidContentType?.cta?.actionLink;
|
|
1402
|
+
|
|
1403
|
+
// If we have deep links available, find the matching one
|
|
1404
|
+
if (deepLink?.length > 0 && deepLinkValue) {
|
|
1405
|
+
// Try to find exact match first
|
|
1406
|
+
const exactMatch = deepLink.find((link) => link.value === deepLinkValue);
|
|
1407
|
+
if (exactMatch) {
|
|
1408
|
+
return exactMatch.value;
|
|
1409
|
+
}
|
|
1126
1410
|
|
|
1127
|
-
|
|
1128
|
-
|
|
1411
|
+
// Try to find match without query params
|
|
1412
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
1413
|
+
const partialMatch = deepLink.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
1414
|
+
if (partialMatch) {
|
|
1415
|
+
return partialMatch.value;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
// If no match found, return the base URL without query parameters
|
|
1420
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
1421
|
+
}
|
|
1422
|
+
// Otherwise, check carousel data
|
|
1423
|
+
if (androidMediaType === CAROUSEL) {
|
|
1424
|
+
const carouselLinkInfo = processCarouselDataForDeepLinks(androidCarouselData);
|
|
1425
|
+
return carouselLinkInfo.deepLinkValue;
|
|
1426
|
+
}
|
|
1427
|
+
return "";
|
|
1129
1428
|
})(),
|
|
1130
1429
|
deepLinkKeysValue: (() => {
|
|
1131
|
-
//
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
const
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1430
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
1431
|
+
if (androidMediaType === VIDEO && androidButtons.length > 0) {
|
|
1432
|
+
const firstButton = androidButtons[0];
|
|
1433
|
+
if (firstButton?.type === DEEP_LINK && firstButton?.actionLink) {
|
|
1434
|
+
const deepLinkValue = firstButton.actionLink;
|
|
1435
|
+
|
|
1436
|
+
if (deepLinkValue && deepLinkValue.includes('?')) {
|
|
1437
|
+
try {
|
|
1438
|
+
// Extract query parameters from deep link URL
|
|
1439
|
+
const queryString = deepLinkValue.split('?')[1];
|
|
1440
|
+
const searchParams = new URLSearchParams(queryString);
|
|
1441
|
+
const extractedKeys = [];
|
|
1442
|
+
searchParams.forEach((value, key) => {
|
|
1443
|
+
if (value === key) { // Only extract keys where value equals key
|
|
1444
|
+
extractedKeys.push(key);
|
|
1445
|
+
}
|
|
1446
|
+
});
|
|
1447
|
+
return extractedKeys;
|
|
1448
|
+
} catch (error) {
|
|
1449
|
+
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
1450
|
+
return [];
|
|
1140
1451
|
}
|
|
1141
|
-
}
|
|
1142
|
-
return extractedKeys;
|
|
1143
|
-
} catch (error) {
|
|
1144
|
-
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
1452
|
+
}
|
|
1145
1453
|
return [];
|
|
1146
1454
|
}
|
|
1455
|
+
return [];
|
|
1456
|
+
}
|
|
1457
|
+
// If there's a root level CTA, extract keys from URL
|
|
1458
|
+
if (androidMainCta?.type === DEEP_LINK || androidContentType?.cta?.type === DEEP_LINK) {
|
|
1459
|
+
const deepLinkValue = androidMainCta?.type === DEEP_LINK ? androidMainCta?.actionLink : androidContentType?.cta?.actionLink;
|
|
1460
|
+
|
|
1461
|
+
if (deepLinkValue && deepLinkValue.includes('?')) {
|
|
1462
|
+
try {
|
|
1463
|
+
// Extract query parameters from deep link URL
|
|
1464
|
+
const queryString = deepLinkValue.split('?')[1];
|
|
1465
|
+
const searchParams = new URLSearchParams(queryString);
|
|
1466
|
+
const extractedKeys = [];
|
|
1467
|
+
searchParams.forEach((value, key) => {
|
|
1468
|
+
if (value === key) { // Only extract keys where value equals key
|
|
1469
|
+
extractedKeys.push(key);
|
|
1470
|
+
}
|
|
1471
|
+
});
|
|
1472
|
+
return extractedKeys;
|
|
1473
|
+
} catch (error) {
|
|
1474
|
+
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
1475
|
+
return [];
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
return [];
|
|
1479
|
+
}
|
|
1480
|
+
// Otherwise, check carousel data
|
|
1481
|
+
if (androidMediaType === CAROUSEL) {
|
|
1482
|
+
const carouselLinkInfo = processCarouselDataForDeepLinks(androidCarouselData);
|
|
1483
|
+
return carouselLinkInfo.deepLinkKeysValue;
|
|
1147
1484
|
}
|
|
1148
1485
|
return [];
|
|
1149
1486
|
})(),
|
|
1150
|
-
externalLinkValue:
|
|
1487
|
+
externalLinkValue: (() => {
|
|
1488
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
1489
|
+
if (androidMediaType === VIDEO && androidButtons.length > 0) {
|
|
1490
|
+
const firstButton = androidButtons[0];
|
|
1491
|
+
if (firstButton?.type === EXTERNAL_URL) {
|
|
1492
|
+
return firstButton?.actionLink || "";
|
|
1493
|
+
}
|
|
1494
|
+
return "";
|
|
1495
|
+
}
|
|
1496
|
+
// If there's a root level CTA, use it
|
|
1497
|
+
if (androidMainCta?.type === EXTERNAL_URL || androidContentType?.cta?.type === EXTERNAL_URL) {
|
|
1498
|
+
return androidMainCta?.type === EXTERNAL_URL ? androidMainCta?.actionLink : androidContentType?.cta?.actionLink;
|
|
1499
|
+
}
|
|
1500
|
+
// Otherwise, check carousel data
|
|
1501
|
+
if (androidMediaType === CAROUSEL) {
|
|
1502
|
+
const carouselLinkInfo = processCarouselDataForDeepLinks(androidCarouselData);
|
|
1503
|
+
return carouselLinkInfo.externalLinkValue;
|
|
1504
|
+
}
|
|
1505
|
+
return "";
|
|
1506
|
+
})(),
|
|
1151
1507
|
};
|
|
1152
1508
|
|
|
1153
1509
|
stateUpdates.push(() => setAndroidContent(androidContentData));
|
|
@@ -1241,18 +1597,23 @@ const MobilePushNew = ({
|
|
|
1241
1597
|
let deepLinkKeys = button?.deepLinkKeys || [];
|
|
1242
1598
|
if (!deepLinkKeys?.length && button?.type === DEEP_LINK && button?.actionLink) {
|
|
1243
1599
|
try {
|
|
1244
|
-
|
|
1245
|
-
const
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1600
|
+
// Extract query parameters from deep link URL using the same approach as main content
|
|
1601
|
+
const deepLinkValue = button?.actionLink;
|
|
1602
|
+
if (deepLinkValue && deepLinkValue.includes('?')) {
|
|
1603
|
+
const queryString = deepLinkValue.split('?')[1];
|
|
1604
|
+
const searchParams = new URLSearchParams(queryString);
|
|
1605
|
+
const extractedKeys = [];
|
|
1606
|
+
searchParams.forEach((value, key) => {
|
|
1607
|
+
if (value === key) { // Only extract keys where value equals key
|
|
1608
|
+
extractedKeys.push(key);
|
|
1609
|
+
}
|
|
1610
|
+
});
|
|
1611
|
+
if (extractedKeys?.length > 0) {
|
|
1612
|
+
deepLinkKeys = extractedKeys;
|
|
1249
1613
|
}
|
|
1250
|
-
});
|
|
1251
|
-
if (extractedKeys?.length > 0) {
|
|
1252
|
-
deepLinkKeys = extractedKeys;
|
|
1253
1614
|
}
|
|
1254
1615
|
} catch (error) {
|
|
1255
|
-
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
1616
|
+
console.error("[MobilePushNew] Error extracting deep link keys from CTA button:", error);
|
|
1256
1617
|
}
|
|
1257
1618
|
}
|
|
1258
1619
|
|
|
@@ -1288,6 +1649,45 @@ const MobilePushNew = ({
|
|
|
1288
1649
|
}
|
|
1289
1650
|
}
|
|
1290
1651
|
|
|
1652
|
+
// Determine actionOnClick and linkType for iOS - prioritize CTA buttons for video, root level CTA for others, carousel data as fallback
|
|
1653
|
+
const iosActionOnClick = (() => {
|
|
1654
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
1655
|
+
if (iosMediaType === VIDEO && iosButtons.length > 0) {
|
|
1656
|
+
return true;
|
|
1657
|
+
}
|
|
1658
|
+
// If there's a root level CTA, use it
|
|
1659
|
+
if (!!iosMainCta || !!iosContentType?.cta) {
|
|
1660
|
+
return true;
|
|
1661
|
+
}
|
|
1662
|
+
// Otherwise, check carousel data
|
|
1663
|
+
if (iosMediaType === CAROUSEL) {
|
|
1664
|
+
const iosCarouselLinkInfo = processCarouselDataForDeepLinks(iosCarouselData);
|
|
1665
|
+
return iosCarouselLinkInfo.deepLinkValue || iosCarouselLinkInfo.externalLinkValue;
|
|
1666
|
+
}
|
|
1667
|
+
return false;
|
|
1668
|
+
})();
|
|
1669
|
+
|
|
1670
|
+
const iosLinkType = (() => {
|
|
1671
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
1672
|
+
if (iosMediaType === VIDEO && iosButtons.length > 0) {
|
|
1673
|
+
const firstButton = iosButtons[0];
|
|
1674
|
+
return firstButton?.type === EXTERNAL_URL ? EXTERNAL_LINK : DEEP_LINK;
|
|
1675
|
+
}
|
|
1676
|
+
// If there's a root level CTA, use its type
|
|
1677
|
+
if (iosMainCta?.type === EXTERNAL_URL || iosContentType?.cta?.type === EXTERNAL_URL) {
|
|
1678
|
+
return EXTERNAL_LINK;
|
|
1679
|
+
}
|
|
1680
|
+
if (iosMainCta?.type === DEEP_LINK || iosContentType?.cta?.type === DEEP_LINK) {
|
|
1681
|
+
return DEEP_LINK;
|
|
1682
|
+
}
|
|
1683
|
+
// Otherwise, check carousel data
|
|
1684
|
+
if (iosMediaType === CAROUSEL) {
|
|
1685
|
+
const iosCarouselLinkInfo = processCarouselDataForDeepLinks(iosCarouselData);
|
|
1686
|
+
return iosCarouselLinkInfo.externalLinkValue ? EXTERNAL_LINK : DEEP_LINK;
|
|
1687
|
+
}
|
|
1688
|
+
return DEEP_LINK;
|
|
1689
|
+
})();
|
|
1690
|
+
|
|
1291
1691
|
// Process iOS content
|
|
1292
1692
|
const iosContentData = {
|
|
1293
1693
|
title: iosTitle,
|
|
@@ -1297,53 +1697,145 @@ const MobilePushNew = ({
|
|
|
1297
1697
|
videoSrc: iosVideoSrc,
|
|
1298
1698
|
videoPreview: iosVideoPreview,
|
|
1299
1699
|
carouselData: iosCarouselData,
|
|
1300
|
-
// Handle root level CTA
|
|
1301
|
-
actionOnClick:
|
|
1302
|
-
linkType:
|
|
1700
|
+
// Handle root level CTA or carousel data
|
|
1701
|
+
actionOnClick: iosActionOnClick,
|
|
1702
|
+
linkType: iosLinkType,
|
|
1303
1703
|
deepLinkValue: (() => {
|
|
1304
|
-
//
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1704
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
1705
|
+
if (iosMediaType === VIDEO && iosButtons.length > 0) {
|
|
1706
|
+
const firstButton = iosButtons[0];
|
|
1707
|
+
if (firstButton?.type === DEEP_LINK && firstButton?.actionLink) {
|
|
1708
|
+
const deepLinkValue = firstButton.actionLink;
|
|
1709
|
+
|
|
1710
|
+
// If we have deep links available, find the matching one
|
|
1711
|
+
if (deepLink?.length > 0 && deepLinkValue) {
|
|
1712
|
+
// Try to find exact match first
|
|
1713
|
+
const exactMatch = deepLink.find((link) => link.value === deepLinkValue);
|
|
1714
|
+
if (exactMatch) {
|
|
1715
|
+
return exactMatch.value;
|
|
1716
|
+
}
|
|
1314
1717
|
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1718
|
+
// Try to find match without query params
|
|
1719
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
1720
|
+
const partialMatch = deepLink.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
1721
|
+
if (partialMatch) {
|
|
1722
|
+
return partialMatch.value;
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
// If no match found, return the base URL without query parameters
|
|
1727
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
1320
1728
|
}
|
|
1729
|
+
return "";
|
|
1321
1730
|
}
|
|
1731
|
+
// If there's a root level CTA, use it
|
|
1732
|
+
if (iosMainCta?.type === DEEP_LINK || iosContentType?.cta?.type === DEEP_LINK) {
|
|
1733
|
+
const deepLinkValue = iosMainCta?.type === DEEP_LINK ? iosMainCta?.actionLink : iosContentType?.cta?.actionLink;
|
|
1734
|
+
|
|
1735
|
+
// If we have deep links available, find the matching one
|
|
1736
|
+
if (deepLink?.length > 0 && deepLinkValue) {
|
|
1737
|
+
// Try to find exact match first
|
|
1738
|
+
const exactMatch = deepLink.find((link) => link.value === deepLinkValue);
|
|
1739
|
+
if (exactMatch) {
|
|
1740
|
+
return exactMatch.value;
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
// Try to find match without query params
|
|
1744
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
1745
|
+
const partialMatch = deepLink.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
1746
|
+
if (partialMatch) {
|
|
1747
|
+
return partialMatch.value;
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1322
1750
|
|
|
1323
|
-
|
|
1324
|
-
|
|
1751
|
+
// If no match found, return the base URL without query parameters
|
|
1752
|
+
return deepLinkValue ? deepLinkValue.split('?')[0] : "";
|
|
1753
|
+
}
|
|
1754
|
+
// Otherwise, check carousel data
|
|
1755
|
+
if (iosMediaType === CAROUSEL) {
|
|
1756
|
+
const iosCarouselLinkInfo = processCarouselDataForDeepLinks(iosCarouselData);
|
|
1757
|
+
return iosCarouselLinkInfo.deepLinkValue;
|
|
1758
|
+
}
|
|
1759
|
+
return "";
|
|
1325
1760
|
})(),
|
|
1326
1761
|
deepLinkKeysValue: (() => {
|
|
1327
|
-
//
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
const
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1762
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
1763
|
+
if (iosMediaType === VIDEO && iosButtons.length > 0) {
|
|
1764
|
+
const firstButton = iosButtons[0];
|
|
1765
|
+
if (firstButton?.type === DEEP_LINK && firstButton?.actionLink) {
|
|
1766
|
+
const deepLinkValue = firstButton.actionLink;
|
|
1767
|
+
|
|
1768
|
+
if (deepLinkValue && deepLinkValue.includes('?')) {
|
|
1769
|
+
try {
|
|
1770
|
+
// Extract query parameters from deep link URL
|
|
1771
|
+
const queryString = deepLinkValue.split('?')[1];
|
|
1772
|
+
const searchParams = new URLSearchParams(queryString);
|
|
1773
|
+
const extractedKeys = [];
|
|
1774
|
+
searchParams.forEach((value, key) => {
|
|
1775
|
+
if (value === key) { // Only extract keys where value equals key
|
|
1776
|
+
extractedKeys.push(key);
|
|
1777
|
+
}
|
|
1778
|
+
});
|
|
1779
|
+
return extractedKeys;
|
|
1780
|
+
} catch (error) {
|
|
1781
|
+
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
1782
|
+
return [];
|
|
1336
1783
|
}
|
|
1337
|
-
}
|
|
1338
|
-
return extractedKeys;
|
|
1339
|
-
} catch (error) {
|
|
1340
|
-
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
1784
|
+
}
|
|
1341
1785
|
return [];
|
|
1342
1786
|
}
|
|
1787
|
+
return [];
|
|
1788
|
+
}
|
|
1789
|
+
// If there's a root level CTA, extract keys from URL
|
|
1790
|
+
if (iosMainCta?.type === DEEP_LINK || iosContentType?.cta?.type === DEEP_LINK) {
|
|
1791
|
+
const deepLinkValue = iosMainCta?.type === DEEP_LINK ? iosMainCta?.actionLink : iosContentType?.cta?.actionLink;
|
|
1792
|
+
|
|
1793
|
+
if (deepLinkValue && deepLinkValue.includes('?')) {
|
|
1794
|
+
try {
|
|
1795
|
+
// Extract query parameters from deep link URL
|
|
1796
|
+
const queryString = deepLinkValue.split('?')[1];
|
|
1797
|
+
const searchParams = new URLSearchParams(queryString);
|
|
1798
|
+
const extractedKeys = [];
|
|
1799
|
+
searchParams.forEach((value, key) => {
|
|
1800
|
+
if (value === key) { // Only extract keys where value equals key
|
|
1801
|
+
extractedKeys.push(key);
|
|
1802
|
+
}
|
|
1803
|
+
});
|
|
1804
|
+
return extractedKeys;
|
|
1805
|
+
} catch (error) {
|
|
1806
|
+
console.error("[MobilePushNew] Error extracting deep link keys:", error);
|
|
1807
|
+
return [];
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
return [];
|
|
1811
|
+
}
|
|
1812
|
+
// Otherwise, check carousel data
|
|
1813
|
+
if (iosMediaType === CAROUSEL) {
|
|
1814
|
+
const iosCarouselLinkInfo = processCarouselDataForDeepLinks(iosCarouselData);
|
|
1815
|
+
return iosCarouselLinkInfo.deepLinkKeysValue;
|
|
1343
1816
|
}
|
|
1344
1817
|
return [];
|
|
1345
1818
|
})(),
|
|
1346
|
-
externalLinkValue:
|
|
1819
|
+
externalLinkValue: (() => {
|
|
1820
|
+
// For video templates, prioritize CTA buttons over root level CTA
|
|
1821
|
+
if (iosMediaType === VIDEO && iosButtons.length > 0) {
|
|
1822
|
+
const firstButton = iosButtons[0];
|
|
1823
|
+
if (firstButton?.type === EXTERNAL_URL) {
|
|
1824
|
+
return firstButton?.actionLink || "";
|
|
1825
|
+
}
|
|
1826
|
+
return "";
|
|
1827
|
+
}
|
|
1828
|
+
// If there's a root level CTA, use it
|
|
1829
|
+
if (iosMainCta?.type === EXTERNAL_URL || iosContentType?.cta?.type === EXTERNAL_URL) {
|
|
1830
|
+
return iosMainCta?.type === EXTERNAL_URL ? iosMainCta?.actionLink : iosContentType?.cta?.actionLink;
|
|
1831
|
+
}
|
|
1832
|
+
// Otherwise, check carousel data
|
|
1833
|
+
if (iosMediaType === CAROUSEL) {
|
|
1834
|
+
const iosCarouselLinkInfo = processCarouselDataForDeepLinks(iosCarouselData);
|
|
1835
|
+
return iosCarouselLinkInfo.externalLinkValue;
|
|
1836
|
+
}
|
|
1837
|
+
return "";
|
|
1838
|
+
})(),
|
|
1347
1839
|
};
|
|
1348
1840
|
|
|
1349
1841
|
stateUpdates.push(() => setIosContent(iosContentData));
|
|
@@ -1802,7 +2294,9 @@ const MobilePushNew = ({
|
|
|
1802
2294
|
return;
|
|
1803
2295
|
}
|
|
1804
2296
|
// Only require templateName in full mode
|
|
1805
|
-
|
|
2297
|
+
// Use ref to get the latest template name value for validation
|
|
2298
|
+
const currentTemplateName = templateNameRef.current || templateName;
|
|
2299
|
+
if (isFullMode && !currentTemplateName?.trim()) {
|
|
1806
2300
|
CapNotification.error({
|
|
1807
2301
|
message: formatMessage(messages.emptyTemplateErrorMessage),
|
|
1808
2302
|
});
|
|
@@ -1810,7 +2304,8 @@ const MobilePushNew = ({
|
|
|
1810
2304
|
}
|
|
1811
2305
|
|
|
1812
2306
|
// In library mode, set templateName programmatically if empty
|
|
1813
|
-
|
|
2307
|
+
// Use ref to get the latest template name value to avoid closure issues
|
|
2308
|
+
let finalTemplateName = templateNameRef.current || templateName;
|
|
1814
2309
|
if (!isFullMode && (!finalTemplateName || !finalTemplateName.trim())) {
|
|
1815
2310
|
if (androidContent?.title && androidContent.title.trim()) {
|
|
1816
2311
|
finalTemplateName = androidContent.title.trim();
|
|
@@ -1840,10 +2335,10 @@ const MobilePushNew = ({
|
|
|
1840
2335
|
if (androidContent?.linkType === DEEP_LINK && androidContent?.deepLinkValue) {
|
|
1841
2336
|
// Use the same matching logic as deep link value extraction
|
|
1842
2337
|
let selectedDeepLink = null;
|
|
1843
|
-
|
|
2338
|
+
|
|
1844
2339
|
// Try to find exact match first
|
|
1845
2340
|
selectedDeepLink = deepLink?.find((link) => link.value === androidContent?.deepLinkValue);
|
|
1846
|
-
|
|
2341
|
+
|
|
1847
2342
|
// If no exact match, try to find match without query params
|
|
1848
2343
|
if (!selectedDeepLink && androidContent?.deepLinkValue) {
|
|
1849
2344
|
const baseDeepLinkValue = androidContent?.deepLinkValue.split('?')[0];
|
|
@@ -1873,7 +2368,7 @@ const MobilePushNew = ({
|
|
|
1873
2368
|
const baseDeepLinkValue = iosContent?.deepLinkValue.split('?')[0];
|
|
1874
2369
|
selectedDeepLink = deepLink?.find((link) => link.value === baseDeepLinkValue || link.value.split('?')[0] === baseDeepLinkValue);
|
|
1875
2370
|
}
|
|
1876
|
-
|
|
2371
|
+
|
|
1877
2372
|
const hasKeysDefined = selectedDeepLink?.keys && selectedDeepLink.keys.length > 0;
|
|
1878
2373
|
|
|
1879
2374
|
// Only require keys if the selected deep link has keys defined
|
|
@@ -1941,7 +2436,7 @@ const MobilePushNew = ({
|
|
|
1941
2436
|
...processedIosContent.expandableDetails,
|
|
1942
2437
|
ctas: savedCtas.map((cta) => {
|
|
1943
2438
|
let actionLink = cta?.url;
|
|
1944
|
-
|
|
2439
|
+
|
|
1945
2440
|
// Append deep link keys to URL if they exist
|
|
1946
2441
|
if (cta?.urlType === DEEP_LINK && cta?.deepLinkKeys?.length > 0) {
|
|
1947
2442
|
const deepLinkKeysArray = Array.isArray(cta?.deepLinkKeys) ? cta?.deepLinkKeys : [cta?.deepLinkKeys];
|
|
@@ -2126,7 +2621,6 @@ const MobilePushNew = ({
|
|
|
2126
2621
|
}, [
|
|
2127
2622
|
templateNameError,
|
|
2128
2623
|
formatMessage,
|
|
2129
|
-
templateName,
|
|
2130
2624
|
androidContent,
|
|
2131
2625
|
iosContent,
|
|
2132
2626
|
imageSrc,
|
|
@@ -2183,6 +2677,8 @@ const MobilePushNew = ({
|
|
|
2183
2677
|
(ev) => {
|
|
2184
2678
|
const { value } = ev.target;
|
|
2185
2679
|
setTemplateName(value);
|
|
2680
|
+
// Update ref to always have the latest value
|
|
2681
|
+
templateNameRef.current = value;
|
|
2186
2682
|
const isInvalid = !value || value.trim() === "";
|
|
2187
2683
|
setTemplateNameError(isInvalid);
|
|
2188
2684
|
if (value && onEnterTemplateName) {
|
|
@@ -2443,6 +2939,66 @@ const MobilePushNew = ({
|
|
|
2443
2939
|
};
|
|
2444
2940
|
}, [handleSave]);
|
|
2445
2941
|
|
|
2942
|
+
// Function to process carousel data and extract deep link information
|
|
2943
|
+
const processCarouselDataForDeepLinks = useCallback((carouselData = []) => {
|
|
2944
|
+
if (!carouselData || carouselData?.length === 0) {
|
|
2945
|
+
return { deepLinkValue: "", deepLinkKeysValue: [], externalLinkValue: "" };
|
|
2946
|
+
}
|
|
2947
|
+
|
|
2948
|
+
// Find the first carousel card with actionOnClick enabled
|
|
2949
|
+
const activeCard = carouselData.find((card) => card?.buttons
|
|
2950
|
+
&& card?.buttons?.length > 0
|
|
2951
|
+
&& card?.buttons[0]?.actionOnClick);
|
|
2952
|
+
|
|
2953
|
+
if (!activeCard || !activeCard?.buttons || activeCard?.buttons?.length === 0) {
|
|
2954
|
+
return { deepLinkValue: "", deepLinkKeysValue: [], externalLinkValue: "" };
|
|
2955
|
+
}
|
|
2956
|
+
|
|
2957
|
+
const button = activeCard?.buttons[0];
|
|
2958
|
+
|
|
2959
|
+
if (button?.linkType === DEEP_LINK) {
|
|
2960
|
+
const deepLinkValue = button?.deepLinkValue || "";
|
|
2961
|
+
const deepLinkKeys = button.deepLinkKeys || [];
|
|
2962
|
+
|
|
2963
|
+
// Find matching deep link from available options
|
|
2964
|
+
let finalDeepLinkValue = deepLinkValue;
|
|
2965
|
+
if (deepLink?.length > 0 && deepLinkValue) {
|
|
2966
|
+
// Try to find exact match first
|
|
2967
|
+
const exactMatch = deepLink.find((link) => link.value === deepLinkValue);
|
|
2968
|
+
if (exactMatch) {
|
|
2969
|
+
finalDeepLinkValue = exactMatch.value;
|
|
2970
|
+
} else {
|
|
2971
|
+
// Try to find match without query params
|
|
2972
|
+
const baseDeepLinkValue = deepLinkValue.split('?')[0];
|
|
2973
|
+
const partialMatch = deepLink.find((link) => link.value === baseDeepLinkValue
|
|
2974
|
+
|| link.value.split('?')[0] === baseDeepLinkValue);
|
|
2975
|
+
if (partialMatch) {
|
|
2976
|
+
// Return the selected deep link option from dropdown, like other media types
|
|
2977
|
+
finalDeepLinkValue = partialMatch.value;
|
|
2978
|
+
} else {
|
|
2979
|
+
// If no match found, return the original value (this handles custom deep links)
|
|
2980
|
+
finalDeepLinkValue = deepLinkValue;
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
|
|
2985
|
+
return {
|
|
2986
|
+
deepLinkValue: finalDeepLinkValue,
|
|
2987
|
+
deepLinkKeysValue: deepLinkKeys,
|
|
2988
|
+
externalLinkValue: "",
|
|
2989
|
+
};
|
|
2990
|
+
} if (button?.linkType === EXTERNAL_LINK) {
|
|
2991
|
+
return {
|
|
2992
|
+
deepLinkValue: "",
|
|
2993
|
+
deepLinkKeysValue: [],
|
|
2994
|
+
externalLinkValue: button.externalLinkValue || "",
|
|
2995
|
+
};
|
|
2996
|
+
}
|
|
2997
|
+
|
|
2998
|
+
return { deepLinkValue: "", deepLinkKeysValue: [], externalLinkValue: "" };
|
|
2999
|
+
}, [deepLink]);
|
|
3000
|
+
|
|
3001
|
+
|
|
2446
3002
|
return (
|
|
2447
3003
|
<CapSpin
|
|
2448
3004
|
spinning={spin || editData?.editTemplateInProgress || fetchingLiquidValidation || getTemplateDetailsInProgress}
|