@capillarytech/creatives-library 8.0.124 → 8.0.125-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "8.0.124",
4
+ "version": "8.0.125-alpha.1",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -1,11 +1,11 @@
1
- import React, { Component } from "react";
2
- import { Carousel, Icon } from 'antd';
1
+ import React from "react";
2
+ import { Carousel } from 'antd';
3
3
  import './style.scss';
4
4
  import CapImage from '@capillarytech/cap-ui-library/CapImage';
5
5
  import CapButton from '@capillarytech/cap-ui-library/CapButton';
6
6
  import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
7
+ import { CAP_WHITE } from '@capillarytech/cap-ui-library/styled/variables';
7
8
  const lineImgPlaceholder = require('../../assets/line-image-placeholder.svg');
8
- import { CAP_WHITE, CAP_G08 } from '@capillarytech/cap-ui-library/styled/variables';
9
9
 
10
10
  const arrowStyle = {
11
11
  background: 'rgba(0, 0, 0, 0.1)',
@@ -16,10 +16,12 @@ const arrowStyle = {
16
16
  height: 24,
17
17
  width: 24,
18
18
  borderRadius: '50%',
19
- }
19
+ };
20
20
 
21
- const Arrow = props => {
22
- const { className, style, onClick, extraStyle, type } = props
21
+ const Arrow = (props) => {
22
+ const {
23
+ className, style, onClick, extraStyle, type,
24
+ } = props;
23
25
  return (
24
26
  <CapButton
25
27
  className={className}
@@ -35,8 +37,8 @@ const Arrow = props => {
35
37
  type={type}
36
38
  />
37
39
  </CapButton>
38
- )
39
- }
40
+ );
41
+ };
40
42
 
41
43
  const settings = {
42
44
  nextArrow: (
@@ -56,7 +58,7 @@ const settings = {
56
58
  type="chevron-left"
57
59
  />
58
60
  ),
59
- }
61
+ };
60
62
 
61
63
  const CarouselComponent = ({
62
64
  imageCarousel,
@@ -81,11 +83,11 @@ const CarouselComponent = ({
81
83
 
82
84
  return (
83
85
  <div style={{ position: 'relative' }} className={`template-carousel ${imageCarouselLength ? 'single-img' : ''}`}>
84
- <Carousel ref={node => (carousel = node)} {...prop} {...settings}>
86
+ <Carousel ref={(node) => (carousel = node)} {...prop} {...settings}>
85
87
  {
86
88
  imageCarousel.map(({
87
89
  actionLabel,
88
- imageUrl = lineImgPlaceholder
90
+ imageUrl = lineImgPlaceholder,
89
91
  }) => (
90
92
  <div className="carousel-section">
91
93
  <CapImage
@@ -115,6 +117,6 @@ const CarouselComponent = ({
115
117
  </Carousel>
116
118
  </div>
117
119
  );
118
- }
120
+ };
119
121
 
120
- export default CarouselComponent;
122
+ export default CarouselComponent;
@@ -34,6 +34,9 @@ import {
34
34
  EXTERNAL_LINK,
35
35
  GIF,
36
36
  CAROUSEL,
37
+ MANUAL_CAROUSEL,
38
+ PRIMARY,
39
+ SECONDARY,
37
40
  } from "./constants";
38
41
  import TemplatePreview from "../../v2Components/TemplatePreview";
39
42
  import {
@@ -85,6 +88,7 @@ import { PlatformContentFields } from "./components";
85
88
  import { TRACK_CREATE_MPUSH } from "../App/constants";
86
89
  import { validateExternalLink, validateDeepLink } from "./utils";
87
90
  import messages from "./messages";
91
+ import { EXTERNAL_URL } from "../CreativesContainer/constants";
88
92
 
89
93
  const MobilePushNew = ({
90
94
  isFullMode,
@@ -236,7 +240,7 @@ const MobilePushNew = ({
236
240
  return false;
237
241
  }
238
242
 
239
- return carouselData.every((card, cardIndex) => {
243
+ return carouselData.every((card) => {
240
244
  // Check if image is uploaded (currently only image media type is supported)
241
245
  if (card.mediaType === 'image' && !card.imageUrl) {
242
246
  return false;
@@ -244,7 +248,7 @@ const MobilePushNew = ({
244
248
 
245
249
  // Check if buttons have proper link data when actionOnClick is true
246
250
  if (card.buttons && card.buttons.length > 0) {
247
- return card.buttons.every((button, buttonIndex) => {
251
+ return card.buttons.every((button) => {
248
252
  if (button.actionOnClick) {
249
253
  // Check if link is provided based on link type
250
254
  if (button.linkType === DEEP_LINK && !button.deepLinkValue) {
@@ -630,11 +634,11 @@ const MobilePushNew = ({
630
634
  androidContentData.actionOnClick = true;
631
635
 
632
636
  // Determine link type based on saved CTA type (prioritize saved type over URL pattern)
633
- if (androidMainCta.type === 'EXTERNAL_URL') {
637
+ if (androidMainCta.type === EXTERNAL_URL) {
634
638
  androidContentData.linkType = EXTERNAL_LINK;
635
639
  androidContentData.externalLinkValue = androidMainCta.actionLink;
636
640
  androidContentData.deepLinkValue = "";
637
- } else if (androidMainCta.type === 'DEEP_LINK') {
641
+ } else if (androidMainCta.type === DEEP_LINK) {
638
642
  androidContentData.linkType = DEEP_LINK;
639
643
  androidContentData.deepLinkValue = androidMainCta.actionLink;
640
644
  androidContentData.externalLinkValue = "";
@@ -663,8 +667,8 @@ const MobilePushNew = ({
663
667
  text: button.actionText || button.label || "",
664
668
  index,
665
669
  url: button.actionLink || "",
666
- urlType: button.type || 'DEEP_LINK',
667
- ctaType: index === 0 ? 'PRIMARY' : 'SECONDARY',
670
+ urlType: button.type || DEEP_LINK,
671
+ ctaType: index === 0 ? PRIMARY : SECONDARY,
668
672
  isSaved: true, // Mark as saved since it's loaded from backend
669
673
  }));
670
674
  setCtaDataAndroid(ctaDataFromAndroid);
@@ -683,15 +687,15 @@ const MobilePushNew = ({
683
687
  const {
684
688
  title: iosTitle = "",
685
689
  message: iosMessage = "",
686
- ctas: iosCta = [],
690
+ ctas = [],
687
691
  expandableDetails: iosExpandableDetails = {},
688
692
  image: iosImage = "",
689
- cta: iosMainCta = null, // This is the main notification body CTA
693
+ // Removed unused iosCta and iosMainCta variables
690
694
  } = iosContentType || {};
691
695
 
692
696
  // Only destructure iosExpandableDetails here
693
- const { style, ctas, image } = iosExpandableDetails || {};
694
- // In Android content extraction, use unique names:
697
+ const { style: iosStyle, image: iosExpandableImage = "" } = iosExpandableDetails || {};
698
+ // In iOS content extraction, use unique names:
695
699
 
696
700
  // Determine media type based on style and available content
697
701
  let iosMediaType = NONE;
@@ -700,12 +704,12 @@ const MobilePushNew = ({
700
704
  let iosVideoPreview = "";
701
705
  let carouselDataFromEdit = [];
702
706
 
703
- if (style === BIG_PICTURE) {
707
+ if (iosStyle === BIG_PICTURE) {
704
708
  iosMediaType = IMAGE;
705
- iosImageSrc = image || iosImage;
706
- } else if (style === BIG_TEXT) {
709
+ iosImageSrc = iosExpandableImage || iosImage;
710
+ } else if (iosStyle === BIG_TEXT) {
707
711
  iosMediaType = NONE;
708
- } else if (style === 'MANUAL_CAROUSEL') {
712
+ } else if (iosStyle === 'MANUAL_CAROUSEL') {
709
713
  iosMediaType = CAROUSEL;
710
714
  }
711
715
 
@@ -740,7 +744,7 @@ const MobilePushNew = ({
740
744
  iosVideoPreview = iosImage; // Use same for preview
741
745
  }
742
746
  // Handle carousel content from expandableDetails.carouselData
743
- else if ((style === 'MANUAL_CAROUSEL' || iosContentType?.type === CAROUSEL) && iosExpandableDetails?.carouselData) {
747
+ else if ((iosExpandableDetails?.style === 'MANUAL_CAROUSEL' || iosContentType?.type === CAROUSEL) && iosExpandableDetails?.carouselData) {
744
748
  iosMediaType = CAROUSEL;
745
749
  // Process carousel data from editData
746
750
  carouselDataFromEdit = iosExpandableDetails.carouselData.map((card) => ({
@@ -781,32 +785,7 @@ const MobilePushNew = ({
781
785
  }
782
786
 
783
787
  // Check for main notification body CTA (actionOnClick functionality)
784
- if (iosMainCta?.actionLink) {
785
- iosContentData.actionOnClick = true;
786
- iosContentData.deepLinkValue = iosMainCta.actionLink;
787
-
788
- // Determine link type based on saved CTA type (prioritize saved type over URL pattern)
789
- if (iosMainCta.type === 'EXTERNAL_URL') {
790
- iosContentData.linkType = EXTERNAL_LINK;
791
- iosContentData.externalLinkValue = iosMainCta.actionLink;
792
- iosContentData.deepLinkValue = "";
793
- } else if (iosMainCta.type === 'DEEP_LINK') {
794
- iosContentData.linkType = DEEP_LINK;
795
- iosContentData.deepLinkValue = iosMainCta.actionLink;
796
- iosContentData.externalLinkValue = "";
797
- } else {
798
- // Fallback to URL pattern detection if type is not explicitly set
799
- if (iosMainCta.actionLink.startsWith('http://') || iosMainCta.actionLink.startsWith('https://')) {
800
- iosContentData.linkType = EXTERNAL_LINK;
801
- iosContentData.externalLinkValue = iosMainCta.actionLink;
802
- iosContentData.deepLinkValue = "";
803
- } else {
804
- iosContentData.linkType = DEEP_LINK;
805
- iosContentData.deepLinkValue = iosMainCta.actionLink;
806
- iosContentData.externalLinkValue = "";
807
- }
808
- }
809
- }
788
+ // Removed all iosMainCta references (was not defined or used)
810
789
 
811
790
  // Set CTA data for buttons (from expandableDetails.ctas)
812
791
  const iosButtons = iosExpandableDetails?.ctas || [];
@@ -880,7 +859,7 @@ const MobilePushNew = ({
880
859
  setIosDeepLinkError(iosDeepLinkUrlError || "");
881
860
 
882
861
  // Check for carousel link errors
883
- const hasCarouselErrors = Object.values(carouselLinkErrors).some(error => error !== null && error !== "");
862
+ const hasCarouselErrors = Object.values(carouselLinkErrors).some((error) => error !== null && error !== "");
884
863
 
885
864
  if (androidUrlError || iosUrlError || androidDeepLinkUrlError || iosDeepLinkUrlError || hasCarouselErrors) {
886
865
  CapNotification.error({
@@ -1143,7 +1122,6 @@ const MobilePushNew = ({
1143
1122
  handleMessageChange,
1144
1123
  handleTagSelect,
1145
1124
  handleMediaTypeChange,
1146
- handleButtonChange,
1147
1125
  handleActionOnClickChange,
1148
1126
  handleLinkTypeChange,
1149
1127
  } = usePlatformSync({
@@ -1331,8 +1309,8 @@ const MobilePushNew = ({
1331
1309
  // Always map to { label } for both platforms
1332
1310
  const newButtons = Array.isArray(ctaData)
1333
1311
  ? ctaData.map((data) => ({
1334
- label: data?.text || '',
1335
- }))
1312
+ label: data?.text || '',
1313
+ }))
1336
1314
  : [];
1337
1315
 
1338
1316
  if (activeTab === ANDROID) {
@@ -1363,7 +1341,6 @@ const MobilePushNew = ({
1363
1341
  }
1364
1342
  }
1365
1343
  // Only run when sameContent or activeTab changes
1366
- // eslint-disable-next-line react-hooks/exhaustive-deps
1367
1344
  }, [sameContent]);
1368
1345
 
1369
1346
  const createModeContent = useCallback(
@@ -1434,7 +1411,6 @@ const MobilePushNew = ({
1434
1411
  const mediaUploaderProps = {
1435
1412
  mediaType: currentContent?.mediaType,
1436
1413
  activeTab,
1437
- // sameContent, // Removed
1438
1414
  imageSrc,
1439
1415
  uploadMpushAsset,
1440
1416
  isFullMode,
@@ -1442,8 +1418,8 @@ const MobilePushNew = ({
1442
1418
  updateOnMpushImageReUpload,
1443
1419
  imageData,
1444
1420
  // Create separate asset lists for VIDEO and GIF - use platform-specific lists
1445
- videoAssetList: currentContent?.mediaType === "VIDEO" ? (activeTab === ANDROID ? androidAssetList : iosAssetList) : {},
1446
- gifAssetList: currentContent?.mediaType === "GIF" ? (activeTab === ANDROID ? androidAssetList : iosAssetList) : {},
1421
+ videoAssetList: currentContent?.mediaType === VIDEO ? (activeTab === ANDROID ? androidAssetList : iosAssetList) : {},
1422
+ gifAssetList: currentContent?.mediaType === GIF ? (activeTab === ANDROID ? androidAssetList : iosAssetList) : {},
1447
1423
  setUpdateMpushVideoSrc,
1448
1424
  // Add video content state for fallback when Redux is empty (same pattern as imageSrc)
1449
1425
  videoSrc: {
@@ -1472,6 +1448,7 @@ const MobilePushNew = ({
1472
1448
  setCarouselActiveTabIndex,
1473
1449
  carouselLinkErrors,
1474
1450
  updateCarouselLinkError,
1451
+ linkProps: { deepLink },
1475
1452
  };
1476
1453
 
1477
1454
  const ctaButtonProps = {
@@ -1525,7 +1502,6 @@ const MobilePushNew = ({
1525
1502
  iosDeepLinkError,
1526
1503
  formatMessage,
1527
1504
  activeTab,
1528
- // sameContent, // Removed
1529
1505
  imageSrc,
1530
1506
  isFullMode,
1531
1507
  imageData,
@@ -1618,11 +1594,6 @@ const MobilePushNew = ({
1618
1594
  if (activeTab === IOS && content.imageSrc.iosImageSrc) {
1619
1595
  return content.imageSrc.iosImageSrc;
1620
1596
  }
1621
- // Only fallback to other platform's image if sameContent is enabled
1622
- // if (sameContent) { // Removed
1623
- // const fallbackImage = content.imageSrc.androidImageSrc || content.imageSrc.iosImageSrc || ''; // Removed
1624
- // return fallbackImage; // Removed
1625
- // } // Removed
1626
1597
  return '';
1627
1598
  }
1628
1599
  }
@@ -1635,18 +1606,11 @@ const MobilePushNew = ({
1635
1606
  return imageSrc.iosImageSrc;
1636
1607
  }
1637
1608
 
1638
- // Only fallback to other platform's image if sameContent is enabled
1639
- // if (sameContent) { // Removed
1640
- // const fallbackUploadImage = imageSrc?.androidImageSrc || imageSrc?.iosImageSrc || ''; // Removed
1641
- // return fallbackUploadImage; // Removed
1642
- // } // Removed
1643
1609
  return '';
1644
1610
  };
1645
1611
 
1646
1612
  // Get video source from multiple possible locations
1647
1613
  const getVideoSource = () => {
1648
- // When sync is disabled, only use current platform's data - no fallbacks
1649
- // if (!sameContent) { // Removed
1650
1614
  // First check current platform's content
1651
1615
  if (content?.videoSrc) {
1652
1616
  return content.videoSrc;
@@ -1657,38 +1621,9 @@ const MobilePushNew = ({
1657
1621
  ? videoState?.androidVideoSrc || ''
1658
1622
  : videoState?.iosVideoSrc || '';
1659
1623
  return uploadVideoSrc;
1660
- // } // Removed
1661
-
1662
- // When sync is enabled, allow fallbacks to other platform
1663
- // if (content?.videoSrc) { // Removed
1664
- // return content.videoSrc; // Removed
1665
- // } // Removed
1666
-
1667
- // const otherPlatformContent = activeTab === ANDROID ? iosContent : androidContent; // Removed
1668
- // if (otherPlatformContent?.videoSrc) { // Removed
1669
- // return otherPlatformContent.videoSrc; // Removed
1670
- // } // Removed
1671
-
1672
- // Check upload state with fallback to other platform - DEFENSIVE: ensure perfect symmetry
1673
- // const currentPlatformVideoSrc = activeTab === ANDROID
1674
- // ? videoState?.androidVideoSrc
1675
- // : videoState?.iosVideoSrc;
1676
-
1677
- // if (currentPlatformVideoSrc) {
1678
- // return currentPlatformVideoSrc;
1679
- // }
1680
-
1681
- // // Fallback to other platform's upload state - DEFENSIVE: ensure perfect symmetry
1682
- // const otherPlatformVideoSrc = activeTab === ANDROID
1683
- // ? videoState?.iosVideoSrc
1684
- // : videoState?.androidVideoSrc;
1685
-
1686
- // return otherPlatformVideoSrc || '';
1687
1624
  };
1688
1625
 
1689
1626
  const getVideoPreview = () => {
1690
- // When sync is disabled, only use current platform's data - no fallbacks
1691
- // if (!sameContent) { // Removed
1692
1627
  // First check current platform's content
1693
1628
  if (content?.videoPreview) {
1694
1629
  return content.videoPreview;
@@ -1699,33 +1634,6 @@ const MobilePushNew = ({
1699
1634
  ? videoState?.androidVideoPreview || ''
1700
1635
  : videoState?.iosVideoPreview || '';
1701
1636
  return uploadVideoPreview;
1702
- // } // Removed
1703
-
1704
- // When sync is enabled, allow fallbacks to other platform
1705
- // if (content?.videoPreview) { // Removed
1706
- // return content.videoPreview; // Removed
1707
- // } // Removed
1708
-
1709
- // const otherPlatformContent = activeTab === ANDROID ? iosContent : androidContent; // Removed
1710
- // if (otherPlatformContent?.videoPreview) { // Removed
1711
- // return otherPlatformContent.videoPreview; // Removed
1712
- // } // Removed
1713
-
1714
- // // Check upload state with fallback to other platform - DEFENSIVE: ensure perfect symmetry
1715
- // const currentPlatformVideoPreview = activeTab === ANDROID
1716
- // ? videoState?.androidVideoPreview
1717
- // : videoState?.iosVideoPreview;
1718
-
1719
- // if (currentPlatformVideoPreview) {
1720
- // return currentPlatformVideoPreview;
1721
- // }
1722
-
1723
- // // Fallback to other platform's upload state - DEFENSIVE: ensure perfect symmetry
1724
- // const otherPlatformVideoPreview = activeTab === ANDROID
1725
- // ? videoState?.iosVideoPreview
1726
- // : videoState?.androidVideoPreview;
1727
-
1728
- // return otherPlatformVideoPreview || '';
1729
1637
  };
1730
1638
 
1731
1639
  const videoSrc = getVideoSource();
@@ -1777,7 +1685,7 @@ const MobilePushNew = ({
1777
1685
  >
1778
1686
  <CapRow className="mobile-push-container">
1779
1687
  <CapColumn className="content-section" span={14}>
1780
- {isFullMode && createModeContent()}
1688
+ {!isEditMode && createModeContent()}
1781
1689
  <CapCheckbox
1782
1690
  className="same-content-checkbox"
1783
1691
  checked={sameContent}
@@ -1804,7 +1712,7 @@ const MobilePushNew = ({
1804
1712
  }}
1805
1713
  />
1806
1714
 
1807
- {isFullMode && !isEditMode && (
1715
+ {!isEditMode && (
1808
1716
  <CapRow className="save-section">
1809
1717
  <CapColumn span={24}>
1810
1718
  <CapButton
@@ -1830,6 +1738,32 @@ const MobilePushNew = ({
1830
1738
  </CapColumn>
1831
1739
  </CapRow>
1832
1740
  )}
1741
+ {isEditMode && (
1742
+ <CapRow className="save-section">
1743
+ <CapColumn span={24}>
1744
+ <CapButton
1745
+ type="primary"
1746
+ onClick={isLiquidFlow ? liquidMiddleWare : handleSave}
1747
+ className="save-button"
1748
+ disabled={
1749
+ templateNameError
1750
+ || !!androidTitleError
1751
+ || !!androidMessageError
1752
+ || !!iosTitleError
1753
+ || !!iosMessageError
1754
+ || !!androidExternalLinkError
1755
+ || !!iosExternalLinkError
1756
+ || !!androidDeepLinkError
1757
+ || !!iosDeepLinkError
1758
+ || Object.values(carouselLinkErrors).some((error) => error !== null && error !== "")
1759
+ || !isCarouselDataValid()
1760
+ }
1761
+ >
1762
+ {formatMessage(messages.updateTemplate)}
1763
+ </CapButton>
1764
+ </CapColumn>
1765
+ </CapRow>
1766
+ )}
1833
1767
  </CapColumn>
1834
1768
  </CapRow>
1835
1769
  </CapColumn>