@capillarytech/creatives-library 8.0.123 → 8.0.125-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/containers/App/constants.js +1 -0
  2. package/package.json +1 -1
  3. package/services/api.js +1 -1
  4. package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +8 -3
  5. package/tests/integration/TemplateCreation/api-response.js +5 -0
  6. package/tests/integration/TemplateCreation/msw-handler.js +42 -63
  7. package/utils/common.js +7 -0
  8. package/utils/commonUtils.js +2 -6
  9. package/utils/createPayload.js +240 -0
  10. package/utils/tests/createPayload.test.js +761 -0
  11. package/v2Components/CapDeviceContent/index.js +1 -0
  12. package/v2Components/CapImageUpload/index.js +51 -45
  13. package/v2Components/CapInAppCTA/index.js +1 -0
  14. package/v2Components/CapMpushCTA/constants.js +25 -0
  15. package/v2Components/CapMpushCTA/index.js +332 -0
  16. package/v2Components/CapMpushCTA/index.scss +95 -0
  17. package/v2Components/CapMpushCTA/messages.js +89 -0
  18. package/v2Components/CapTagList/index.js +177 -120
  19. package/v2Components/CapVideoUpload/constants.js +3 -0
  20. package/v2Components/CapVideoUpload/index.js +167 -110
  21. package/v2Components/CapVideoUpload/messages.js +16 -0
  22. package/v2Components/Carousel/index.js +15 -13
  23. package/v2Components/ErrorInfoNote/style.scss +1 -0
  24. package/v2Components/MobilePushPreviewV2/index.js +37 -5
  25. package/v2Components/TemplatePreview/_templatePreview.scss +114 -72
  26. package/v2Components/TemplatePreview/assets/images/Android _ With date and time.svg +29 -0
  27. package/v2Components/TemplatePreview/assets/images/android.svg +9 -0
  28. package/v2Components/TemplatePreview/assets/images/iOS _ With date and time.svg +26 -0
  29. package/v2Components/TemplatePreview/assets/images/ios.svg +9 -0
  30. package/v2Components/TemplatePreview/index.js +178 -50
  31. package/v2Components/TemplatePreview/messages.js +4 -0
  32. package/v2Containers/CreativesContainer/SlideBoxContent.js +7 -8
  33. package/v2Containers/CreativesContainer/index.js +194 -138
  34. package/v2Containers/InApp/constants.js +1 -1
  35. package/v2Containers/InApp/index.js +13 -13
  36. package/v2Containers/MobilePush/Create/index.js +1 -0
  37. package/v2Containers/MobilePushNew/actions.js +116 -0
  38. package/v2Containers/MobilePushNew/components/CtaButtons.js +170 -0
  39. package/v2Containers/MobilePushNew/components/MediaUploaders.js +686 -0
  40. package/v2Containers/MobilePushNew/components/PlatformContentFields.js +279 -0
  41. package/v2Containers/MobilePushNew/components/index.js +5 -0
  42. package/v2Containers/MobilePushNew/components/tests/CtaButtons.test.js +779 -0
  43. package/v2Containers/MobilePushNew/components/tests/MediaUploaders.test.js +2114 -0
  44. package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +343 -0
  45. package/v2Containers/MobilePushNew/constants.js +115 -0
  46. package/v2Containers/MobilePushNew/hooks/tests/usePlatformSync.test.js +1299 -0
  47. package/v2Containers/MobilePushNew/hooks/tests/useUpload.test.js +1223 -0
  48. package/v2Containers/MobilePushNew/hooks/usePlatformSync.js +246 -0
  49. package/v2Containers/MobilePushNew/hooks/useUpload.js +709 -0
  50. package/v2Containers/MobilePushNew/index.js +1937 -0
  51. package/v2Containers/MobilePushNew/index.scss +308 -0
  52. package/v2Containers/MobilePushNew/messages.js +226 -0
  53. package/v2Containers/MobilePushNew/reducer.js +160 -0
  54. package/v2Containers/MobilePushNew/sagas.js +198 -0
  55. package/v2Containers/MobilePushNew/selectors.js +55 -0
  56. package/v2Containers/MobilePushNew/tests/reducer.test.js +741 -0
  57. package/v2Containers/MobilePushNew/tests/sagas.test.js +863 -0
  58. package/v2Containers/MobilePushNew/tests/selectors.test.js +425 -0
  59. package/v2Containers/MobilePushNew/tests/utils.test.js +322 -0
  60. package/v2Containers/MobilePushNew/utils.js +33 -0
  61. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +5 -5
  62. package/v2Containers/TagList/index.js +56 -10
  63. package/v2Containers/Templates/_templates.scss +101 -1
  64. package/v2Containers/Templates/index.js +147 -35
  65. package/v2Containers/Templates/messages.js +8 -0
  66. package/v2Containers/Templates/sagas.js +2 -0
  67. package/v2Containers/Whatsapp/constants.js +1 -0
@@ -90,4 +90,8 @@ export default defineMessages({
90
90
  id: `creatives.componentsV2.TemplatePreview.addToCart`,
91
91
  defaultMessage: 'Add to cart',
92
92
  },
93
+ videoNotSupported: {
94
+ id: 'creatives.componentsV2.TemplatePreview.videoNotSupported',
95
+ defaultMessage: 'Your browser does not support the video tag.',
96
+ },
93
97
  });
@@ -7,17 +7,14 @@ import cloneDeep from 'lodash/cloneDeep';
7
7
  import TemplatesV2 from '../TemplatesV2';
8
8
  import TemplatePreview from '../../v2Components/TemplatePreview';
9
9
  import SmsWrapper from '../SmsWrapper';
10
- // import SmsEdit from '../Sms/Edit';
11
10
  import Email from '../Email';
12
11
  import EmailWrapper from '../EmailWrapper';
13
- import MobilepushWrapper from '../MobilepushWrapper';
14
12
  import EmailPreviewV2 from '../../v2Components/EmailPreviewV2';
15
13
  import MobilePushPreview from '../../v2Components/MobilePushPreviewV2';
16
14
  import WechatWrapper from '../WeChat/Wrapper';
17
15
  import Facebook from '../Facebook';
18
16
  import { RICH_MEDIA, MAP_TEMPLATE, CREATE } from '../WeChat/Wrapper/constants';
19
17
  import CallTask from '../CallTask';
20
- import MobliPushEdit from '../MobilePush/Edit';
21
18
  import * as constants from './constants';
22
19
  import LineContainer from '../Line/Container';
23
20
  import FTP from '../FTP';
@@ -28,6 +25,7 @@ import Rcs from '../Rcs';
28
25
  import { getWhatsappContent } from '../Whatsapp/utils';
29
26
  import * as commonUtil from '../../utils/common';
30
27
  import Zalo from '../Zalo';
28
+ import MobilePushNew from '../MobilePushNew';
31
29
  const CreativesWrapper = styled.div`
32
30
  .ant-popover,
33
31
  .ant-notification,
@@ -476,9 +474,6 @@ export function SlideBoxContent(props) {
476
474
  forwardedTags={forwardedTags}
477
475
  />
478
476
  )}
479
- {isMpushPreview &&
480
- <MobilePushPreview templateData={templateData} channel={channel}/>
481
- }
482
477
  {
483
478
  (currentChannel === constants.WECHAT && !!slidBoxContent) && <WechatWrapper
484
479
  mode={slidBoxContent}
@@ -657,7 +652,7 @@ export function SlideBoxContent(props) {
657
652
  />
658
653
  )}
659
654
  {isEditMPush &&
660
- <MobliPushEdit
655
+ <MobilePushNew
661
656
  getFormLibraryData={getFormData}
662
657
  setIsLoadingContent={setIsLoadingContent}
663
658
  location={{
@@ -684,7 +679,7 @@ export function SlideBoxContent(props) {
684
679
  />
685
680
  }
686
681
  {isCreateMPush &&
687
- <MobilepushWrapper
682
+ <MobilePushNew
688
683
  key="creatives-mobilepush-wrapper"
689
684
  date={new Date().getMilliseconds()}
690
685
  setIsLoadingContent={setIsLoadingContent}
@@ -692,8 +687,11 @@ export function SlideBoxContent(props) {
692
687
  mobilePushCreateMode={mobilePushCreateMode}
693
688
  isGetFormData={isGetFormData}
694
689
  getFormData={getFormData}
690
+ location={location}
691
+ getDefaultTags={type}
695
692
  templateData={templateData}
696
693
  type={type}
694
+ handleClose={handleClose}
697
695
  step={templateStep}
698
696
  showNextStep={onCreateNextStep}
699
697
  isFullMode={isFullMode}
@@ -711,6 +709,7 @@ export function SlideBoxContent(props) {
711
709
  onTestContentClicked={onTestContentClicked}
712
710
  eventContextTags={eventContextTags}
713
711
  showLiquidErrorInFooter={showLiquidErrorInFooter}
712
+ onCreateComplete={onCreateComplete}
714
713
  />
715
714
  }
716
715
  {
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import Bugsnag from "@bugsnag/js";
3
+ import { CAP_SPACE_32, CAP_SPACE_56, CAP_SPACE_64 } from '@capillarytech/cap-ui-library/styled/variables';
4
+
4
5
  import CapSlideBox from '@capillarytech/cap-ui-library/CapSlideBox';
5
6
  import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
6
7
  import CapRow from '@capillarytech/cap-ui-library/CapRow';
@@ -14,17 +15,15 @@ import {
14
15
  } from 'lodash';
15
16
  import { connect } from 'react-redux';
16
17
  import { createStructuredSelector } from 'reselect';
17
- import { bindActionCreators } from 'redux';
18
+ import { bindActionCreators, compose } from 'redux';
18
19
  import styled from 'styled-components';
19
20
  import { GA } from '@capillarytech/cap-ui-utils';
21
+ import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
20
22
 
21
23
  import * as actions from './actions';
22
24
  import {
23
25
  selectEmailLayout, uploadSelector, templateUserList, makeSelectTemplates,
24
26
  } from '../Templates/selectors';
25
- import SlideBoxContent from './SlideBoxContent';
26
- import SlideBoxHeader from './SlideBoxHeader';
27
- import SlideBoxFooter from './SlideBoxFooter';
28
27
  import * as constants from './constants';
29
28
  import * as commonUtil from '../../utils/common';
30
29
  import { gtmPush } from '../../utils/gtmTrackers';
@@ -43,20 +42,19 @@ import {
43
42
  import { IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
44
43
  import { CREATIVE } from '../Facebook/constants';
45
44
  import { LOYALTY } from '../App/constants';
46
- import { WHATSAPP_STATUSES, WHATSAPP_MEDIA_TYPES, PHONE_NUMBER, URL } from '../Whatsapp/constants';
47
-
45
+ import {
46
+ WHATSAPP_STATUSES, WHATSAPP_MEDIA_TYPES, PHONE_NUMBER, URL,
47
+ } from '../Whatsapp/constants';
48
+ import SlideBoxHeader from './SlideBoxHeader';
49
+ import SlideBoxFooter from './SlideBoxFooter';
50
+ import SlideBoxContent from './SlideBoxContent';
48
51
  import { updateImagesInHtml } from '../../utils/cdnTransformation';
49
- import { IOS } from '../InApp/constants';
52
+
50
53
  import injectReducer from '../../utils/injectReducer';
51
54
  import injectSaga from '../../utils/injectSaga';
52
55
  import creativesContainerReducer from './reducer';
53
- import { compose } from 'redux';
54
- import { capSagaForFetchSchemaForEntity,capSagaLiquidEntity } from '../Cap/sagas';
56
+ import { capSagaForFetchSchemaForEntity, capSagaLiquidEntity } from '../Cap/sagas';
55
57
  import { v2TemplateSagaWatchGetDefaultBeeTemplates } from '../Templates/sagas';
56
- import {
57
- CAP_SPACE_32, CAP_SPACE_56, CAP_SPACE_64,
58
- } from '@capillarytech/cap-ui-library/styled/variables';
59
- import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
60
58
  import { DYNAMIC_URL } from '../../v2Components/CapWhatsappCTA/constants';
61
59
  import ErrorInfoNote from '../../v2Components/ErrorInfoNote';
62
60
 
@@ -82,11 +80,14 @@ const SlideBoxWrapper = styled.div`
82
80
  export class Creatives extends React.Component {
83
81
  constructor(props) {
84
82
  super(props);
83
+
84
+ const initialSlidBoxContent = this.getSlideBoxContent({ mode: props.creativesMode, templateData: props.templateData, isFullMode: props.isFullMode });
85
+
85
86
  this.state = {
86
87
  isLoadingContent: true,
87
88
  templateStep: 1, //modeSelection: for template name and (for email selecting upload or editor), and createTemplate to create template create based on modeSelection
88
89
  showSlideBox: true,
89
- slidBoxContent: this.getSlideBoxContent({ mode: props.creativesMode, templateData: props.templateData, isFullMode: props.isFullMode }),
90
+ slidBoxContent: initialSlidBoxContent,
90
91
  templateData: this.getTemplateData(props.templateData),
91
92
  templateNameExists: props.creativesMode === 'edit', // if edit mode templateNameExists will be true, and false in create flow.
92
93
  currentChannel: this.props.channel || 'sms',
@@ -151,28 +152,26 @@ export class Creatives extends React.Component {
151
152
  const userId = parseInt(template.updatedBy, 10);
152
153
  templateData.updatedByName = commonUtil.getUserNameById(userId, usersList);
153
154
  this.setState({ slidBoxContent: constants.PREVIEW, templateData });
155
+ } else if (get(template, 'versions.base.content.zalo.previewUrl')) {
156
+ commonUtil.handlePreviewInNewTab(
157
+ template.versions.base.content.zalo.previewUrl
158
+ );
154
159
  } else {
155
- if (get(template, 'versions.base.content.zalo.previewUrl')) {
156
- commonUtil.handlePreviewInNewTab(
157
- template.versions.base.content.zalo.previewUrl
158
- );
159
- } else {
160
- const {
161
- name = "",
162
- sourceAccountIdentifier = "",
163
- configs: { token = "" } = {},
164
- hostName = ""
165
- } = get(this.props, "Templates.selectedZaloAccount", {});
166
- this.props.zaloActions.getTemplateInfoById({
167
- username: name,
168
- oa_id: sourceAccountIdentifier,
169
- token,
170
- host: hostName || this.props?.hostName || this.props.Templates?.senderDetails?.hostName,
171
- id: template?._id,
172
- preview: true,
173
- actionCallback: this.actionCallback,
174
- });
175
- }
160
+ const {
161
+ name = "",
162
+ sourceAccountIdentifier = "",
163
+ configs: { token = "" } = {},
164
+ hostName = "",
165
+ } = get(this.props, "Templates.selectedZaloAccount", {});
166
+ this.props.zaloActions.getTemplateInfoById({
167
+ username: name,
168
+ oa_id: sourceAccountIdentifier,
169
+ token,
170
+ host: hostName || this.props?.hostName || this.props.Templates?.senderDetails?.hostName,
171
+ id: template?._id,
172
+ preview: true,
173
+ actionCallback: this.actionCallback,
174
+ });
176
175
  }
177
176
  };
178
177
 
@@ -241,38 +240,40 @@ export class Creatives extends React.Component {
241
240
  this.setState({ isGetFormData: false });
242
241
  };
243
242
 
244
- mapCarouselDataToCreatives = (cards) => {
245
- return cards.map((card) => {
246
- const { cardVarMapped, bodyTemplate, media, buttons, mediaType } = card || {};
247
- const buttonData = buttons?.map((button) => {
248
- const { type, text, phoneNumber, url, dynamicUrlPayload } = button || {};
249
- const buttonObj = { type, text };
250
- if (type === PHONE_NUMBER) {
251
- buttonObj.phone_number = phoneNumber;
252
- }
253
- if (type === URL) {
254
- buttonObj.url = url;
255
- if (dynamicUrlPayload) {
256
- buttonObj.urlType = DYNAMIC_URL;
257
- }
243
+ mapCarouselDataToCreatives = (cards) => cards.map((card) => {
244
+ const {
245
+ cardVarMapped, bodyTemplate, media, buttons, mediaType,
246
+ } = card || {};
247
+ const buttonData = buttons?.map((button) => {
248
+ const {
249
+ type, text, phoneNumber, url, dynamicUrlPayload,
250
+ } = button || {};
251
+ const buttonObj = { type, text };
252
+ if (type === PHONE_NUMBER) {
253
+ buttonObj.phone_number = phoneNumber;
254
+ }
255
+ if (type === URL) {
256
+ buttonObj.url = url;
257
+ if (dynamicUrlPayload) {
258
+ buttonObj.urlType = DYNAMIC_URL;
258
259
  }
259
- return buttonObj;
260
- });
261
- return {
262
- bodyText: bodyTemplate,
263
- varMap: cardVarMapped,
264
- ...(mediaType === IMAGE && {
265
- imageUrl: media?.url,
266
- }),
267
- ...(mediaType === VIDEO && {
268
- videoUrl: media?.url,
269
- videoPreviewImg: media?.previewUrl,
270
- }),
271
- buttons: buttonData,
272
- mediaType: mediaType?.toLowerCase(),
273
- };
260
+ }
261
+ return buttonObj;
274
262
  });
275
- }
263
+ return {
264
+ bodyText: bodyTemplate,
265
+ varMap: cardVarMapped,
266
+ ...(mediaType === IMAGE && {
267
+ imageUrl: media?.url,
268
+ }),
269
+ ...(mediaType === VIDEO && {
270
+ videoUrl: media?.url,
271
+ videoPreviewImg: media?.previewUrl,
272
+ }),
273
+ buttons: buttonData,
274
+ mediaType: mediaType?.toLowerCase(),
275
+ };
276
+ })
276
277
 
277
278
  getTemplateData = (templateData) => { //from consumers to creatives
278
279
  const { isFullMode, messageDetails = {}, smsRegister } = this.props;
@@ -352,13 +353,33 @@ export class Creatives extends React.Component {
352
353
  }
353
354
  case constants.MOBILE_PUSH: {
354
355
  const mode = get(templateData, 'androidContent.type') || get(templateData, 'iosContent.type') || '';
356
+ const androidCarouselMedia = get(templateData, 'androidContent.expandableDetails.media', []);
357
+ const iosCarouselMedia = get(templateData, 'iosContent.expandableDetails.media', []);
358
+ const androidContent = { ...(templateData?.androidContent || {}) };
359
+ const iosContent = { ...(templateData?.iosContent || {}) };
360
+ if (androidCarouselMedia?.length) {
361
+ androidContent.expandableDetails.carouselData = androidCarouselMedia.map((media) => ({
362
+ mediaType: media.type,
363
+ imageUrl: media.url,
364
+ buttons: [],
365
+ videoSrc: '',
366
+ }));
367
+ }
368
+ if (iosCarouselMedia?.length) {
369
+ iosContent.expandableDetails.carouselData = iosCarouselMedia.map((media) => ({
370
+ mediaType: media.type,
371
+ imageUrl: media.url,
372
+ buttons: [],
373
+ videoSrc: '',
374
+ }));
375
+ }
355
376
  creativesTemplateData = {
356
377
  type: channel,
357
378
  name: templateData.messageSubject,
358
379
  versions: {
359
380
  base: {
360
- ANDROID: templateData.androidContent,
361
- IOS: templateData.iosContent,
381
+ ANDROID: androidContent,
382
+ IOS: iosContent,
362
383
  },
363
384
  },
364
385
  definition: { accountId: templateData.accountId, mode: mode.toLowerCase() },
@@ -520,7 +541,9 @@ export class Creatives extends React.Component {
520
541
  } = {},
521
542
  } = templateData;
522
543
  const mediaParams = {};
523
- const { url = '', previewUrl = '', docParams = {}, footer = '', headerVarMapped = {}, headerTemplate = '' } = whatsappMedia || {};
544
+ const {
545
+ url = '', previewUrl = '', docParams = {}, footer = '', headerVarMapped = {}, headerTemplate = '',
546
+ } = whatsappMedia || {};
524
547
  switch (mediaType) {
525
548
  case (WHATSAPP_MEDIA_TYPES.IMAGE):
526
549
  mediaParams.imageUrl = url;
@@ -540,7 +563,7 @@ export class Creatives extends React.Component {
540
563
  break;
541
564
  }
542
565
  const modifiedButtons = cloneDeep(buttons)?.map((btn) => {
543
- if (btn.type === 'PHONE_NUMBER') {
566
+ if (btn.type === PHONE_NUMBER) {
544
567
  btn.phone_number = btn.phoneNumber;
545
568
  delete btn.phoneNumber;
546
569
  return btn;
@@ -633,46 +656,61 @@ export class Creatives extends React.Component {
633
656
  return templateData || null;
634
657
  }
635
658
 
636
- getCarouselMappedData = (carouselData = []) => {
637
- return carouselData.map((carousel) => {
638
- const { bodyText, imageUrl, videoUrl, videoPreviewImg, buttons, mediaType, cardVarMapped, bodyTemplate } = carousel || {};
639
- const buttonData = buttons.map((button, index) => {
640
- const { type, text, phone_number, urlType, url } = button || {};
641
- const buttonObj = {
642
- type,
643
- text,
644
- index,
645
- };
646
- if (type === PHONE_NUMBER) {
647
- buttonObj.phoneNumber = phone_number;
648
- }
649
- if (type === URL) {
650
- buttonObj.url = url;
651
- if (urlType === DYNAMIC_URL) {
652
- const dynamicUrlPayload = url?.match(/{{(.*?)}}/g);
653
- buttonObj.dynamicUrlPayload = dynamicUrlPayload?.length === 1 ? dynamicUrlPayload[0] : '';
654
- }
655
- }
656
- return buttonObj;
657
- });
658
- return {
659
- body: bodyText,
660
- cardVarMapped,
661
- bodyTemplate,
662
- media: {
663
- ...(mediaType?.toLowerCase() === IMAGE.toLowerCase() && {
664
- url: imageUrl,
665
- }),
666
- ...(mediaType?.toLowerCase() === VIDEO.toLowerCase() && {
667
- url: videoUrl,
668
- previewUrl: videoPreviewImg,
669
- }),
670
- },
671
- buttons: buttonData,
672
- mediaType: mediaType?.toUpperCase(),
659
+ getCarouselMappedData = (carouselData = []) => carouselData.map((carousel) => {
660
+ const {
661
+ bodyText, imageUrl, videoUrl, videoPreviewImg, buttons, mediaType, cardVarMapped, bodyTemplate,
662
+ } = carousel || {};
663
+ const buttonData = buttons.map((button, index) => {
664
+ const {
665
+ type, text, phone_number, urlType, url,
666
+ } = button || {};
667
+ const buttonObj = {
668
+ type,
669
+ text,
670
+ index,
673
671
  };
672
+ if (type === PHONE_NUMBER) {
673
+ buttonObj.phoneNumber = phone_number;
674
+ }
675
+ if (type === URL) {
676
+ buttonObj.url = url;
677
+ if (urlType === DYNAMIC_URL) {
678
+ const dynamicUrlPayload = url?.match(/{{(.*?)}}/g);
679
+ buttonObj.dynamicUrlPayload = dynamicUrlPayload?.length === 1 ? dynamicUrlPayload[0] : '';
680
+ }
681
+ }
682
+ return buttonObj;
674
683
  });
675
- };
684
+ return {
685
+ body: bodyText,
686
+ cardVarMapped,
687
+ bodyTemplate,
688
+ media: {
689
+ ...(mediaType?.toLowerCase() === IMAGE.toLowerCase() && {
690
+ url: imageUrl,
691
+ }),
692
+ ...(mediaType?.toLowerCase() === VIDEO.toLowerCase() && {
693
+ url: videoUrl,
694
+ previewUrl: videoPreviewImg,
695
+ }),
696
+ },
697
+ buttons: buttonData,
698
+ mediaType: mediaType?.toUpperCase(),
699
+ };
700
+ });
701
+
702
+ getMobilePushCarouselData = (expandableDetails = []) => {
703
+ const newExpandableDetails = {...expandableDetails};
704
+ newExpandableDetails.style = expandableDetails.style || 'MANUAL_CAROUSEL';
705
+ newExpandableDetails.message = expandableDetails.message || '';
706
+ newExpandableDetails.ctas = expandableDetails.ctas || [];
707
+ newExpandableDetails.media = expandableDetails.carouselData.map((carousel) => ({
708
+ url: carousel.imageUrl,
709
+ type: carousel?.mediaType?.toUpperCase(),
710
+ text: '',
711
+ }));
712
+ return newExpandableDetails;
713
+ }
676
714
 
677
715
  getCreativesData = async (channel, template, templateRecords) => { //from creatives to consumers
678
716
  let templateData = { channel };
@@ -756,6 +794,9 @@ export class Creatives extends React.Component {
756
794
  if (channel !== constants.MOBILE_PUSH) {
757
795
  androidContent.custom = custom;
758
796
  }
797
+ if (channel === constants.MOBILE_PUSH && androidContent?.expandableDetails?.carouselData?.length) {
798
+ androidContent.expandableDetails = this.getMobilePushCarouselData({...androidContent?.expandableDetails});
799
+ }
759
800
  templateData.androidContent = androidContent;
760
801
  templateData.androidContent.type = get(channelTemplate, 'definition.mode', '').toUpperCase();
761
802
  templateData.androidContent.deviceType = constants.ANDROID;
@@ -775,6 +816,9 @@ export class Creatives extends React.Component {
775
816
  if (channel !== constants.MOBILE_PUSH) {
776
817
  iosContent.custom = custom;
777
818
  }
819
+ if (channel === constants.MOBILE_PUSH && iosContent?.expandableDetails?.carouselData?.length) {
820
+ iosContent.expandableDetails = this.getMobilePushCarouselData({...iosContent?.expandableDetails});
821
+ }
778
822
  templateData.iosContent = iosContent;
779
823
  templateData.iosContent.type = get(channelTemplate, 'definition.mode').toUpperCase();
780
824
  templateData.iosContent.deviceType = constants.IOS;
@@ -944,7 +988,7 @@ export class Creatives extends React.Component {
944
988
  fBContent.forEach((obj) => {
945
989
  const data = cloneDeep(obj);
946
990
  const {
947
- subType, linkDesc, imgSrc, webSiteLink, video
991
+ subType, linkDesc, imgSrc, webSiteLink, video,
948
992
  } = obj;
949
993
  delete data.type;
950
994
  delete data.linkDesc;
@@ -982,7 +1026,7 @@ export class Creatives extends React.Component {
982
1026
  break;
983
1027
  case constants.RCS: {
984
1028
  if (template.value) {
985
- const { name = "", versions = {}, type = "" } = {
1029
+ const { name = "", versions = {} } = {
986
1030
  } = template.value || {};
987
1031
  const {
988
1032
  cardContent = [],
@@ -1110,7 +1154,6 @@ export class Creatives extends React.Component {
1110
1154
  }
1111
1155
 
1112
1156
  getFormData = (template) => {
1113
-
1114
1157
  if (template.validity) {
1115
1158
  this.setState(
1116
1159
  {
@@ -1128,7 +1171,7 @@ export class Creatives extends React.Component {
1128
1171
  );
1129
1172
  }
1130
1173
  }
1131
-
1174
+
1132
1175
  processCentralCommsMetaId = (channel, creativesData) => {
1133
1176
  // Create the payload for the centralcommnsmetaId API call
1134
1177
  const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
@@ -1209,13 +1252,16 @@ export class Creatives extends React.Component {
1209
1252
 
1210
1253
  shouldShowFooter = () => {
1211
1254
  const { isFullMode } = this.props;
1212
- const { slidBoxContent, currentChannel, emailCreateMode, templateNameExists, templateStep, mobilePushCreateMode, inAppCreateMode, weChatTemplateType, templateData } = this.state;
1255
+ const {
1256
+ slidBoxContent, currentChannel, emailCreateMode, templateNameExists, templateStep, mobilePushCreateMode, weChatTemplateType, templateData,
1257
+ } = this.state;
1213
1258
  const channel = currentChannel.toUpperCase();
1214
1259
  const currentStep = this.creativesTemplateSteps[templateStep];
1215
1260
  let showFooter = false;
1216
1261
  showFooter = isFullMode && slidBoxContent === "preview";
1217
1262
  const isMobilepush = channel === constants.MOBILE_PUSH;
1218
- const isInApp = channel === constants.INAPP;
1263
+
1264
+
1219
1265
  if (!isFullMode) {
1220
1266
  const isEmailCreate = slidBoxContent === 'createTemplate' && channel === constants.EMAIL && currentStep !== 'createTemplateContent';
1221
1267
  const isCreate = (slidBoxContent === 'editTemplate' || slidBoxContent === 'createTemplate') && !isEmailCreate;
@@ -1237,15 +1283,15 @@ export class Creatives extends React.Component {
1237
1283
  if (slidBoxContent === "editTemplate" && ((channel === constants.EMAIL && currentStep === 'modeSelection'))) {
1238
1284
  showFooter = true;
1239
1285
  }
1240
- if (channel === constants.MOBILE_PUSH &&
1241
- ((slidBoxContent === 'createTemplate' && !isEmpty(mobilePushCreateMode))
1242
- || (slidBoxContent === 'editTemplate' && currentStep === 'modeSelection')) &&
1286
+ if (channel === constants.MOBILE_PUSH
1287
+ && ((slidBoxContent === 'createTemplate' && !isEmpty(mobilePushCreateMode))
1288
+ || (slidBoxContent === 'editTemplate' && (currentStep === 'modeSelection' || isFullMode))) &&
1243
1289
  templateNameExists) {
1244
1290
  showFooter = true;
1245
1291
  }
1246
1292
 
1247
- if (channel === constants.WECHAT &&
1248
- ((slidBoxContent === 'createTemplate' && !isEmpty(weChatTemplateType))
1293
+ if (channel === constants.WECHAT
1294
+ && ((slidBoxContent === 'createTemplate' && !isEmpty(weChatTemplateType))
1249
1295
  || (slidBoxContent === 'editTemplate' && currentStep === 'modeSelection'))) {
1250
1296
  showFooter = true;
1251
1297
  }
@@ -1254,9 +1300,9 @@ export class Creatives extends React.Component {
1254
1300
  if (slidBoxContent === "createTemplate" && ((channel === constants.EMAIL && currentStep === 'createTemplateContent') ||
1255
1301
  ([constants.SMS, constants.WECHAT].includes(channel) && currentStep === 'modeSelection'))) {
1256
1302
  showFooter = showFooter && !this.state.isLoadingContent;
1257
- } else if (slidBoxContent === "editTemplate" &&
1258
- ([constants.SMS, constants.WECHAT, constants.EMAIL].includes(channel) &&
1259
- currentStep === 'modeSelection')) {
1303
+ } else if (slidBoxContent === "editTemplate"
1304
+ && ([constants.SMS, constants.WECHAT, constants.EMAIL].includes(channel)
1305
+ && currentStep === 'modeSelection')) {
1260
1306
  showFooter = showFooter && !this.state.isLoadingContent;
1261
1307
  }
1262
1308
  }
@@ -1265,6 +1311,8 @@ export class Creatives extends React.Component {
1265
1311
  if ([constants.LINE, constants.VIBER, constants.FACEBOOK].includes(channel) || isLineViberChannel) {
1266
1312
  showFooter = false;
1267
1313
  }
1314
+
1315
+
1268
1316
  return showFooter;
1269
1317
  }
1270
1318
 
@@ -1277,13 +1325,21 @@ export class Creatives extends React.Component {
1277
1325
  let showDone = false;
1278
1326
  const channelName = !isFullMode && templateData ? templateData.type : currentChannel;
1279
1327
  const channel = channelName && channelName.toUpperCase();
1328
+
1329
+
1280
1330
  if (channel === constants.EMAIL || channel === constants.SMS) {
1281
1331
  const isEmailCreate = slidBoxContent === 'createTemplate' && channel === constants.EMAIL && currentStep !== 'createTemplateContent';
1282
1332
  showDone = (slidBoxContent === 'editTemplate' || slidBoxContent === 'createTemplate') && !isEmailCreate;
1283
1333
  } else if ([constants.WECHAT, constants.MOBILE_PUSH].includes(channel)) {
1284
1334
  showDone = currentStep === "createTemplateContent" || slidBoxContent === "editTemplate";
1335
+
1336
+ // Additional condition for MobilePush edit in full mode
1337
+ if (channel === constants.MOBILE_PUSH && slidBoxContent === "editTemplate" && isFullMode) {
1338
+ showDone = true;
1339
+ }
1285
1340
  }
1286
1341
 
1342
+
1287
1343
  return showDone;
1288
1344
  }
1289
1345
 
@@ -1343,7 +1399,9 @@ export class Creatives extends React.Component {
1343
1399
  }
1344
1400
 
1345
1401
  shouldShowContinueFooter = () => { // only for email for now, has to be modified according to channel
1346
- const { slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppCreateMode, weChatTemplateType } = this.state;
1402
+ const {
1403
+ slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppCreateMode, weChatTemplateType,
1404
+ } = this.state;
1347
1405
  let isShowContinueFooter = false;
1348
1406
  const currentStep = this.creativesTemplateSteps[templateStep];
1349
1407
  const channel = currentChannel.toUpperCase();
@@ -1425,17 +1483,16 @@ export class Creatives extends React.Component {
1425
1483
  loyaltyMetaData = {},
1426
1484
  } = this.props;
1427
1485
  const mapTemplateCreate =
1428
- slidBoxContent === "createTemplate" &&
1429
- weChatTemplateType === MAP_TEMPLATE &&
1430
- templateStep !== "modeSelection";
1431
- const slideBoxWrapperMargin =
1432
- (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
1433
- ? CAP_SPACE_64
1434
- : get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
1435
- ? CAP_SPACE_56
1436
- : get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
1437
- ? CAP_SPACE_32
1438
- : 0;
1486
+ slidBoxContent === "createTemplate"
1487
+ && weChatTemplateType === MAP_TEMPLATE
1488
+ && templateStep !== "modeSelection";
1489
+ const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
1490
+ ? CAP_SPACE_64
1491
+ : get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
1492
+ ? CAP_SPACE_56
1493
+ : get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
1494
+ ? CAP_SPACE_32
1495
+ : 0;
1439
1496
  /* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
1440
1497
  return (
1441
1498
  <SlideBoxWrapper slideBoxWrapperMargin={slideBoxWrapperMargin} className={classnames(`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`)}>
@@ -1555,7 +1612,6 @@ export class Creatives extends React.Component {
1555
1612
  ) : isLiquidValidationError && (
1556
1613
  <CapRow className="template-footer-width">
1557
1614
  {(() => {
1558
-
1559
1615
  const errorsToShow = get(liquidErrorMessage, constants.LIQUID_ERROR_MSG, []);
1560
1616
  const standardErrorsToShow = get(liquidErrorMessage, constants.STANDARD_ERROR_MSG, []);
1561
1617
  return <ErrorInfoNote currentTab={activeFormBuilderTab?.toUpperCase()} errorMessages={{LIQUID_ERROR_MSG: errorsToShow, STANDARD_ERROR_MSG: standardErrorsToShow}} />;
@@ -1566,7 +1622,7 @@ export class Creatives extends React.Component {
1566
1622
  show={showSlideBox}
1567
1623
  size="size-xl"
1568
1624
  />
1569
-
1625
+
1570
1626
  </SlideBoxWrapper>
1571
1627
  );
1572
1628
  }
@@ -1626,7 +1682,7 @@ function mapDispatchToProps(dispatch) {
1626
1682
  const withConnect = connect(mapStatesToProps, mapDispatchToProps);
1627
1683
  const withReducer = injectReducer({ key: 'creativesContainer', reducer: creativesContainerReducer });
1628
1684
  const withSaga = injectSaga({ key: 'cap', saga: capSagaForFetchSchemaForEntity });
1629
- const withLiquidSaga = injectSaga({ key: 'liquid', saga: capSagaLiquidEntity , mode: DAEMON });
1685
+ const withLiquidSaga = injectSaga({ key: 'liquid', saga: capSagaLiquidEntity, mode: DAEMON });
1630
1686
  const withDefaultTempSaga = injectSaga({ key: 'creativesContainer', saga: v2TemplateSagaWatchGetDefaultBeeTemplates });
1631
1687
 
1632
- export default compose(withSaga,withLiquidSaga, withDefaultTempSaga, withReducer, withConnect)(injectIntl(Creatives));
1688
+ export default compose(withSaga, withLiquidSaga, withDefaultTempSaga, withReducer, withConnect)(injectIntl(Creatives));
@@ -49,6 +49,7 @@ export const INAPP_BUTTON_TYPES = {
49
49
  };
50
50
 
51
51
  export const DEEP_LINK = 'DEEP_LINK';
52
+ export const EXTERNAL_LINK = 'EXTERNAL_LINK';
52
53
 
53
54
  export const INITIAL_CTA_DATA = [
54
55
  {
@@ -131,7 +132,6 @@ export const BUTTON_RADIO_OPTIONS = [
131
132
  </div>
132
133
  </>
133
134
  ),
134
- disabled: true,
135
135
  },
136
136
  ];
137
137