@capillarytech/creatives-library 8.0.126 → 8.0.127-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 (78) hide show
  1. package/containers/App/constants.js +1 -0
  2. package/index.html +3 -1
  3. package/package.json +1 -1
  4. package/services/api.js +4 -4
  5. package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +8 -3
  6. package/tests/integration/TemplateCreation/api-response.js +5 -0
  7. package/tests/integration/TemplateCreation/msw-handler.js +42 -63
  8. package/utils/common.js +7 -0
  9. package/utils/commonUtils.js +2 -6
  10. package/utils/createPayload.js +272 -0
  11. package/utils/tests/createPayload.test.js +761 -0
  12. package/v2Components/CapImageUpload/index.js +59 -46
  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/CustomerSearchSection/index.js +12 -7
  24. package/v2Components/ErrorInfoNote/style.scss +1 -0
  25. package/v2Components/MobilePushPreviewV2/index.js +37 -5
  26. package/v2Components/TemplatePreview/_templatePreview.scss +114 -72
  27. package/v2Components/TemplatePreview/assets/images/Android _ With date and time.svg +29 -0
  28. package/v2Components/TemplatePreview/assets/images/android.svg +9 -0
  29. package/v2Components/TemplatePreview/assets/images/iOS _ With date and time.svg +26 -0
  30. package/v2Components/TemplatePreview/assets/images/ios.svg +9 -0
  31. package/v2Components/TemplatePreview/index.js +178 -50
  32. package/v2Components/TemplatePreview/messages.js +4 -0
  33. package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +169 -0
  34. package/v2Components/TestAndPreviewSlidebox/LeftPanelContent.js +95 -0
  35. package/v2Components/TestAndPreviewSlidebox/PreviewSection.js +69 -0
  36. package/v2Components/TestAndPreviewSlidebox/SendTestMessage.js +68 -0
  37. package/v2Components/TestAndPreviewSlidebox/index.js +67 -246
  38. package/v2Components/TestAndPreviewSlidebox/tests/CustomValuesEditor.test.js +425 -0
  39. package/v2Components/TestAndPreviewSlidebox/tests/LeftPanelContent.test.js +400 -0
  40. package/v2Components/TestAndPreviewSlidebox/tests/SendTestMessage.test.js +448 -0
  41. package/v2Containers/CreativesContainer/SlideBoxContent.js +9 -9
  42. package/v2Containers/CreativesContainer/index.js +193 -134
  43. package/v2Containers/Email/index.js +15 -2
  44. package/v2Containers/InApp/constants.js +1 -0
  45. package/v2Containers/InApp/index.js +13 -13
  46. package/v2Containers/MobilePush/Create/index.js +1 -0
  47. package/v2Containers/MobilePush/commonMethods.js +7 -14
  48. package/v2Containers/MobilePushNew/actions.js +116 -0
  49. package/v2Containers/MobilePushNew/components/CtaButtons.js +170 -0
  50. package/v2Containers/MobilePushNew/components/MediaUploaders.js +754 -0
  51. package/v2Containers/MobilePushNew/components/PlatformContentFields.js +279 -0
  52. package/v2Containers/MobilePushNew/components/index.js +5 -0
  53. package/v2Containers/MobilePushNew/components/tests/CtaButtons.test.js +779 -0
  54. package/v2Containers/MobilePushNew/components/tests/MediaUploaders.test.js +2114 -0
  55. package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +343 -0
  56. package/v2Containers/MobilePushNew/constants.js +115 -0
  57. package/v2Containers/MobilePushNew/hooks/tests/usePlatformSync.test.js +1299 -0
  58. package/v2Containers/MobilePushNew/hooks/tests/useUpload.test.js +1223 -0
  59. package/v2Containers/MobilePushNew/hooks/usePlatformSync.js +246 -0
  60. package/v2Containers/MobilePushNew/hooks/useUpload.js +726 -0
  61. package/v2Containers/MobilePushNew/index.js +2280 -0
  62. package/v2Containers/MobilePushNew/index.scss +308 -0
  63. package/v2Containers/MobilePushNew/messages.js +226 -0
  64. package/v2Containers/MobilePushNew/reducer.js +160 -0
  65. package/v2Containers/MobilePushNew/sagas.js +198 -0
  66. package/v2Containers/MobilePushNew/selectors.js +55 -0
  67. package/v2Containers/MobilePushNew/tests/reducer.test.js +741 -0
  68. package/v2Containers/MobilePushNew/tests/sagas.test.js +863 -0
  69. package/v2Containers/MobilePushNew/tests/selectors.test.js +425 -0
  70. package/v2Containers/MobilePushNew/tests/utils.test.js +322 -0
  71. package/v2Containers/MobilePushNew/utils.js +33 -0
  72. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +5 -5
  73. package/v2Containers/TagList/index.js +56 -10
  74. package/v2Containers/Templates/_templates.scss +101 -1
  75. package/v2Containers/Templates/index.js +147 -35
  76. package/v2Containers/Templates/messages.js +8 -0
  77. package/v2Containers/Templates/sagas.js +2 -0
  78. package/v2Containers/Whatsapp/constants.js +1 -0
@@ -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,9 +15,10 @@ 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 {
@@ -44,20 +46,19 @@ import {
44
46
  import { IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
45
47
  import { CREATIVE } from '../Facebook/constants';
46
48
  import { LOYALTY } from '../App/constants';
47
- import { WHATSAPP_STATUSES, WHATSAPP_MEDIA_TYPES, PHONE_NUMBER, URL } from '../Whatsapp/constants';
48
-
49
+ import {
50
+ WHATSAPP_STATUSES, WHATSAPP_MEDIA_TYPES, PHONE_NUMBER, URL,
51
+ } from '../Whatsapp/constants';
52
+ import SlideBoxHeader from './SlideBoxHeader';
53
+ import SlideBoxFooter from './SlideBoxFooter';
54
+ import SlideBoxContent from './SlideBoxContent';
49
55
  import { updateImagesInHtml } from '../../utils/cdnTransformation';
50
- import { IOS } from '../InApp/constants';
56
+
51
57
  import injectReducer from '../../utils/injectReducer';
52
58
  import injectSaga from '../../utils/injectSaga';
53
59
  import creativesContainerReducer from './reducer';
54
- import { compose } from 'redux';
55
- import { capSagaForFetchSchemaForEntity,capSagaLiquidEntity } from '../Cap/sagas';
60
+ import { capSagaForFetchSchemaForEntity, capSagaLiquidEntity } from '../Cap/sagas';
56
61
  import { v2TemplateSagaWatchGetDefaultBeeTemplates } from '../Templates/sagas';
57
- import {
58
- CAP_SPACE_32, CAP_SPACE_56, CAP_SPACE_64,
59
- } from '@capillarytech/cap-ui-library/styled/variables';
60
- import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
61
62
  import { DYNAMIC_URL } from '../../v2Components/CapWhatsappCTA/constants';
62
63
  import ErrorInfoNote from '../../v2Components/ErrorInfoNote';
63
64
 
@@ -83,11 +84,14 @@ const SlideBoxWrapper = styled.div`
83
84
  export class Creatives extends React.Component {
84
85
  constructor(props) {
85
86
  super(props);
87
+
88
+ const initialSlidBoxContent = this.getSlideBoxContent({ mode: props.creativesMode, templateData: props.templateData, isFullMode: props.isFullMode });
89
+
86
90
  this.state = {
87
91
  isLoadingContent: true,
88
92
  templateStep: 1, //modeSelection: for template name and (for email selecting upload or editor), and createTemplate to create template create based on modeSelection
89
93
  showSlideBox: true,
90
- slidBoxContent: this.getSlideBoxContent({ mode: props.creativesMode, templateData: props.templateData, isFullMode: props.isFullMode }),
94
+ slidBoxContent: initialSlidBoxContent,
91
95
  templateData: this.getTemplateData(props.templateData),
92
96
  templateNameExists: props.creativesMode === 'edit', // if edit mode templateNameExists will be true, and false in create flow.
93
97
  currentChannel: this.props.channel || 'sms',
@@ -154,28 +158,26 @@ export class Creatives extends React.Component {
154
158
  const userId = parseInt(template.updatedBy, 10);
155
159
  templateData.updatedByName = commonUtil.getUserNameById(userId, usersList);
156
160
  this.setState({ slidBoxContent: constants.PREVIEW, templateData });
161
+ } else if (get(template, 'versions.base.content.zalo.previewUrl')) {
162
+ commonUtil.handlePreviewInNewTab(
163
+ template.versions.base.content.zalo.previewUrl
164
+ );
157
165
  } else {
158
- if (get(template, 'versions.base.content.zalo.previewUrl')) {
159
- commonUtil.handlePreviewInNewTab(
160
- template.versions.base.content.zalo.previewUrl
161
- );
162
- } else {
163
- const {
164
- name = "",
165
- sourceAccountIdentifier = "",
166
- configs: { token = "" } = {},
167
- hostName = ""
168
- } = get(this.props, "Templates.selectedZaloAccount", {});
169
- this.props.zaloActions.getTemplateInfoById({
170
- username: name,
171
- oa_id: sourceAccountIdentifier,
172
- token,
173
- host: hostName || this.props?.hostName || this.props.Templates?.senderDetails?.hostName,
174
- id: template?._id,
175
- preview: true,
176
- actionCallback: this.actionCallback,
177
- });
178
- }
166
+ const {
167
+ name = "",
168
+ sourceAccountIdentifier = "",
169
+ configs: { token = "" } = {},
170
+ hostName = "",
171
+ } = get(this.props, "Templates.selectedZaloAccount", {});
172
+ this.props.zaloActions.getTemplateInfoById({
173
+ username: name,
174
+ oa_id: sourceAccountIdentifier,
175
+ token,
176
+ host: hostName || this.props?.hostName || this.props.Templates?.senderDetails?.hostName,
177
+ id: template?._id,
178
+ preview: true,
179
+ actionCallback: this.actionCallback,
180
+ });
179
181
  }
180
182
  };
181
183
 
@@ -244,38 +246,40 @@ export class Creatives extends React.Component {
244
246
  this.setState({ isGetFormData: false });
245
247
  };
246
248
 
247
- mapCarouselDataToCreatives = (cards) => {
248
- return cards.map((card) => {
249
- const { cardVarMapped, bodyTemplate, media, buttons, mediaType } = card || {};
250
- const buttonData = buttons?.map((button) => {
251
- const { type, text, phoneNumber, url, dynamicUrlPayload } = button || {};
252
- const buttonObj = { type, text };
253
- if (type === PHONE_NUMBER) {
254
- buttonObj.phone_number = phoneNumber;
255
- }
256
- if (type === URL) {
257
- buttonObj.url = url;
258
- if (dynamicUrlPayload) {
259
- buttonObj.urlType = DYNAMIC_URL;
260
- }
249
+ mapCarouselDataToCreatives = (cards) => cards.map((card) => {
250
+ const {
251
+ cardVarMapped, bodyTemplate, media, buttons, mediaType,
252
+ } = card || {};
253
+ const buttonData = buttons?.map((button) => {
254
+ const {
255
+ type, text, phoneNumber, url, dynamicUrlPayload,
256
+ } = button || {};
257
+ const buttonObj = { type, text };
258
+ if (type === PHONE_NUMBER) {
259
+ buttonObj.phone_number = phoneNumber;
260
+ }
261
+ if (type === URL) {
262
+ buttonObj.url = url;
263
+ if (dynamicUrlPayload) {
264
+ buttonObj.urlType = DYNAMIC_URL;
261
265
  }
262
- return buttonObj;
263
- });
264
- return {
265
- bodyText: bodyTemplate,
266
- varMap: cardVarMapped,
267
- ...(mediaType === IMAGE && {
268
- imageUrl: media?.url,
269
- }),
270
- ...(mediaType === VIDEO && {
271
- videoUrl: media?.url,
272
- videoPreviewImg: media?.previewUrl,
273
- }),
274
- buttons: buttonData,
275
- mediaType: mediaType?.toLowerCase(),
276
- };
266
+ }
267
+ return buttonObj;
277
268
  });
278
- }
269
+ return {
270
+ bodyText: bodyTemplate,
271
+ varMap: cardVarMapped,
272
+ ...(mediaType === IMAGE && {
273
+ imageUrl: media?.url,
274
+ }),
275
+ ...(mediaType === VIDEO && {
276
+ videoUrl: media?.url,
277
+ videoPreviewImg: media?.previewUrl,
278
+ }),
279
+ buttons: buttonData,
280
+ mediaType: mediaType?.toLowerCase(),
281
+ };
282
+ })
279
283
 
280
284
  getTemplateData = (templateData) => { //from consumers to creatives
281
285
  const { isFullMode, messageDetails = {}, smsRegister } = this.props;
@@ -355,13 +359,33 @@ export class Creatives extends React.Component {
355
359
  }
356
360
  case constants.MOBILE_PUSH: {
357
361
  const mode = get(templateData, 'androidContent.type') || get(templateData, 'iosContent.type') || '';
362
+ const androidCarouselMedia = get(templateData, 'androidContent.expandableDetails.media', []);
363
+ const iosCarouselMedia = get(templateData, 'iosContent.expandableDetails.media', []);
364
+ const androidContent = { ...(templateData?.androidContent || {}) };
365
+ const iosContent = { ...(templateData?.iosContent || {}) };
366
+ if (androidCarouselMedia?.length) {
367
+ androidContent.expandableDetails.carouselData = androidCarouselMedia.map((media) => ({
368
+ mediaType: media.type,
369
+ imageUrl: media.url,
370
+ buttons: [],
371
+ videoSrc: '',
372
+ }));
373
+ }
374
+ if (iosCarouselMedia?.length) {
375
+ iosContent.expandableDetails.carouselData = iosCarouselMedia.map((media) => ({
376
+ mediaType: media.type,
377
+ imageUrl: media.url,
378
+ buttons: [],
379
+ videoSrc: '',
380
+ }));
381
+ }
358
382
  creativesTemplateData = {
359
383
  type: channel,
360
384
  name: templateData.messageSubject,
361
385
  versions: {
362
386
  base: {
363
- ANDROID: templateData.androidContent,
364
- IOS: templateData.iosContent,
387
+ ANDROID: androidContent,
388
+ IOS: iosContent,
365
389
  },
366
390
  },
367
391
  definition: { accountId: templateData.accountId, mode: mode.toLowerCase() },
@@ -523,7 +547,9 @@ export class Creatives extends React.Component {
523
547
  } = {},
524
548
  } = templateData;
525
549
  const mediaParams = {};
526
- const { url = '', previewUrl = '', docParams = {}, footer = '', headerVarMapped = {}, headerTemplate = '' } = whatsappMedia || {};
550
+ const {
551
+ url = '', previewUrl = '', docParams = {}, footer = '', headerVarMapped = {}, headerTemplate = '',
552
+ } = whatsappMedia || {};
527
553
  switch (mediaType) {
528
554
  case (WHATSAPP_MEDIA_TYPES.IMAGE):
529
555
  mediaParams.imageUrl = url;
@@ -543,7 +569,7 @@ export class Creatives extends React.Component {
543
569
  break;
544
570
  }
545
571
  const modifiedButtons = cloneDeep(buttons)?.map((btn) => {
546
- if (btn.type === 'PHONE_NUMBER') {
572
+ if (btn.type === PHONE_NUMBER) {
547
573
  btn.phone_number = btn.phoneNumber;
548
574
  delete btn.phoneNumber;
549
575
  return btn;
@@ -636,46 +662,61 @@ export class Creatives extends React.Component {
636
662
  return templateData || null;
637
663
  }
638
664
 
639
- getCarouselMappedData = (carouselData = []) => {
640
- return carouselData.map((carousel) => {
641
- const { bodyText, imageUrl, videoUrl, videoPreviewImg, buttons, mediaType, cardVarMapped, bodyTemplate } = carousel || {};
642
- const buttonData = buttons.map((button, index) => {
643
- const { type, text, phone_number, urlType, url } = button || {};
644
- const buttonObj = {
645
- type,
646
- text,
647
- index,
648
- };
649
- if (type === PHONE_NUMBER) {
650
- buttonObj.phoneNumber = phone_number;
651
- }
652
- if (type === URL) {
653
- buttonObj.url = url;
654
- if (urlType === DYNAMIC_URL) {
655
- const dynamicUrlPayload = url?.match(/{{(.*?)}}/g);
656
- buttonObj.dynamicUrlPayload = dynamicUrlPayload?.length === 1 ? dynamicUrlPayload[0] : '';
657
- }
658
- }
659
- return buttonObj;
660
- });
661
- return {
662
- body: bodyText,
663
- cardVarMapped,
664
- bodyTemplate,
665
- media: {
666
- ...(mediaType?.toLowerCase() === IMAGE.toLowerCase() && {
667
- url: imageUrl,
668
- }),
669
- ...(mediaType?.toLowerCase() === VIDEO.toLowerCase() && {
670
- url: videoUrl,
671
- previewUrl: videoPreviewImg,
672
- }),
673
- },
674
- buttons: buttonData,
675
- mediaType: mediaType?.toUpperCase(),
665
+ getCarouselMappedData = (carouselData = []) => carouselData.map((carousel) => {
666
+ const {
667
+ bodyText, imageUrl, videoUrl, videoPreviewImg, buttons, mediaType, cardVarMapped, bodyTemplate,
668
+ } = carousel || {};
669
+ const buttonData = buttons.map((button, index) => {
670
+ const {
671
+ type, text, phone_number, urlType, url,
672
+ } = button || {};
673
+ const buttonObj = {
674
+ type,
675
+ text,
676
+ index,
676
677
  };
678
+ if (type === PHONE_NUMBER) {
679
+ buttonObj.phoneNumber = phone_number;
680
+ }
681
+ if (type === URL) {
682
+ buttonObj.url = url;
683
+ if (urlType === DYNAMIC_URL) {
684
+ const dynamicUrlPayload = url?.match(/{{(.*?)}}/g);
685
+ buttonObj.dynamicUrlPayload = dynamicUrlPayload?.length === 1 ? dynamicUrlPayload[0] : '';
686
+ }
687
+ }
688
+ return buttonObj;
677
689
  });
678
- };
690
+ return {
691
+ body: bodyText,
692
+ cardVarMapped,
693
+ bodyTemplate,
694
+ media: {
695
+ ...(mediaType?.toLowerCase() === IMAGE.toLowerCase() && {
696
+ url: imageUrl,
697
+ }),
698
+ ...(mediaType?.toLowerCase() === VIDEO.toLowerCase() && {
699
+ url: videoUrl,
700
+ previewUrl: videoPreviewImg,
701
+ }),
702
+ },
703
+ buttons: buttonData,
704
+ mediaType: mediaType?.toUpperCase(),
705
+ };
706
+ });
707
+
708
+ getMobilePushCarouselData = (expandableDetails = []) => {
709
+ const newExpandableDetails = {...expandableDetails};
710
+ newExpandableDetails.style = expandableDetails.style || 'MANUAL_CAROUSEL';
711
+ newExpandableDetails.message = expandableDetails.message || '';
712
+ newExpandableDetails.ctas = expandableDetails.ctas || [];
713
+ newExpandableDetails.media = expandableDetails.carouselData.map((carousel) => ({
714
+ url: carousel.imageUrl,
715
+ type: carousel?.mediaType?.toUpperCase(),
716
+ text: '',
717
+ }));
718
+ return newExpandableDetails;
719
+ }
679
720
 
680
721
  getCreativesData = async (channel, template, templateRecords) => { //from creatives to consumers
681
722
  let templateData = { channel };
@@ -759,6 +800,9 @@ export class Creatives extends React.Component {
759
800
  if (channel !== constants.MOBILE_PUSH) {
760
801
  androidContent.custom = custom;
761
802
  }
803
+ if (channel === constants.MOBILE_PUSH && androidContent?.expandableDetails?.carouselData?.length) {
804
+ androidContent.expandableDetails = this.getMobilePushCarouselData({...androidContent?.expandableDetails});
805
+ }
762
806
  templateData.androidContent = androidContent;
763
807
  templateData.androidContent.type = get(channelTemplate, 'definition.mode', '').toUpperCase();
764
808
  templateData.androidContent.deviceType = constants.ANDROID;
@@ -778,6 +822,9 @@ export class Creatives extends React.Component {
778
822
  if (channel !== constants.MOBILE_PUSH) {
779
823
  iosContent.custom = custom;
780
824
  }
825
+ if (channel === constants.MOBILE_PUSH && iosContent?.expandableDetails?.carouselData?.length) {
826
+ iosContent.expandableDetails = this.getMobilePushCarouselData({...iosContent?.expandableDetails});
827
+ }
781
828
  templateData.iosContent = iosContent;
782
829
  templateData.iosContent.type = get(channelTemplate, 'definition.mode').toUpperCase();
783
830
  templateData.iosContent.deviceType = constants.IOS;
@@ -947,7 +994,7 @@ export class Creatives extends React.Component {
947
994
  fBContent.forEach((obj) => {
948
995
  const data = cloneDeep(obj);
949
996
  const {
950
- subType, linkDesc, imgSrc, webSiteLink, video
997
+ subType, linkDesc, imgSrc, webSiteLink, video,
951
998
  } = obj;
952
999
  delete data.type;
953
1000
  delete data.linkDesc;
@@ -985,7 +1032,7 @@ export class Creatives extends React.Component {
985
1032
  break;
986
1033
  case constants.RCS: {
987
1034
  if (template.value) {
988
- const { name = "", versions = {}, type = "" } = {
1035
+ const { name = "", versions = {} } = {
989
1036
  } = template.value || {};
990
1037
  const {
991
1038
  cardContent = [],
@@ -1113,7 +1160,6 @@ export class Creatives extends React.Component {
1113
1160
  }
1114
1161
 
1115
1162
  getFormData = (template) => {
1116
-
1117
1163
  if (template.validity) {
1118
1164
  this.setState(
1119
1165
  {
@@ -1131,7 +1177,7 @@ export class Creatives extends React.Component {
1131
1177
  );
1132
1178
  }
1133
1179
  }
1134
-
1180
+
1135
1181
  processCentralCommsMetaId = (channel, creativesData) => {
1136
1182
  // Create the payload for the centralcommnsmetaId API call
1137
1183
  const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
@@ -1222,13 +1268,16 @@ export class Creatives extends React.Component {
1222
1268
 
1223
1269
  shouldShowFooter = () => {
1224
1270
  const { isFullMode } = this.props;
1225
- const { slidBoxContent, currentChannel, emailCreateMode, templateNameExists, templateStep, mobilePushCreateMode, inAppCreateMode, weChatTemplateType, templateData } = this.state;
1271
+ const {
1272
+ slidBoxContent, currentChannel, emailCreateMode, templateNameExists, templateStep, mobilePushCreateMode, weChatTemplateType, templateData,
1273
+ } = this.state;
1226
1274
  const channel = currentChannel.toUpperCase();
1227
1275
  const currentStep = this.creativesTemplateSteps[templateStep];
1228
1276
  let showFooter = false;
1229
1277
  showFooter = isFullMode && slidBoxContent === "preview";
1230
1278
  const isMobilepush = channel === constants.MOBILE_PUSH;
1231
- const isInApp = channel === constants.INAPP;
1279
+
1280
+
1232
1281
  if (!isFullMode) {
1233
1282
  const isEmailCreate = slidBoxContent === 'createTemplate' && channel === constants.EMAIL && currentStep !== 'createTemplateContent';
1234
1283
  const isCreate = (slidBoxContent === 'editTemplate' || slidBoxContent === 'createTemplate') && !isEmailCreate;
@@ -1250,15 +1299,15 @@ export class Creatives extends React.Component {
1250
1299
  if (slidBoxContent === "editTemplate" && ((channel === constants.EMAIL && currentStep === 'modeSelection'))) {
1251
1300
  showFooter = true;
1252
1301
  }
1253
- if (channel === constants.MOBILE_PUSH &&
1254
- ((slidBoxContent === 'createTemplate' && !isEmpty(mobilePushCreateMode))
1255
- || (slidBoxContent === 'editTemplate' && currentStep === 'modeSelection')) &&
1302
+ if (channel === constants.MOBILE_PUSH
1303
+ && ((slidBoxContent === 'createTemplate' && !isEmpty(mobilePushCreateMode))
1304
+ || (slidBoxContent === 'editTemplate' && (currentStep === 'modeSelection' || isFullMode))) &&
1256
1305
  templateNameExists) {
1257
1306
  showFooter = true;
1258
1307
  }
1259
1308
 
1260
- if (channel === constants.WECHAT &&
1261
- ((slidBoxContent === 'createTemplate' && !isEmpty(weChatTemplateType))
1309
+ if (channel === constants.WECHAT
1310
+ && ((slidBoxContent === 'createTemplate' && !isEmpty(weChatTemplateType))
1262
1311
  || (slidBoxContent === 'editTemplate' && currentStep === 'modeSelection'))) {
1263
1312
  showFooter = true;
1264
1313
  }
@@ -1267,9 +1316,9 @@ export class Creatives extends React.Component {
1267
1316
  if (slidBoxContent === "createTemplate" && ((channel === constants.EMAIL && currentStep === 'createTemplateContent') ||
1268
1317
  ([constants.SMS, constants.WECHAT].includes(channel) && currentStep === 'modeSelection'))) {
1269
1318
  showFooter = showFooter && !this.state.isLoadingContent;
1270
- } else if (slidBoxContent === "editTemplate" &&
1271
- ([constants.SMS, constants.WECHAT, constants.EMAIL].includes(channel) &&
1272
- currentStep === 'modeSelection')) {
1319
+ } else if (slidBoxContent === "editTemplate"
1320
+ && ([constants.SMS, constants.WECHAT, constants.EMAIL].includes(channel)
1321
+ && currentStep === 'modeSelection')) {
1273
1322
  showFooter = showFooter && !this.state.isLoadingContent;
1274
1323
  }
1275
1324
  }
@@ -1278,6 +1327,8 @@ export class Creatives extends React.Component {
1278
1327
  if ([constants.LINE, constants.VIBER, constants.FACEBOOK].includes(channel) || isLineViberChannel) {
1279
1328
  showFooter = false;
1280
1329
  }
1330
+
1331
+
1281
1332
  return showFooter;
1282
1333
  }
1283
1334
 
@@ -1290,13 +1341,21 @@ export class Creatives extends React.Component {
1290
1341
  let showDone = false;
1291
1342
  const channelName = !isFullMode && templateData ? templateData.type : currentChannel;
1292
1343
  const channel = channelName?.toUpperCase();
1344
+
1345
+
1293
1346
  if (channel === constants.EMAIL || channel === constants.SMS) {
1294
1347
  const isEmailCreate = slidBoxContent === 'createTemplate' && channel === constants.EMAIL && currentStep !== 'createTemplateContent';
1295
1348
  showDone = (slidBoxContent === 'editTemplate' || slidBoxContent === 'createTemplate') && !isEmailCreate;
1296
1349
  } else if ([constants.WECHAT, constants.MOBILE_PUSH].includes(channel)) {
1297
1350
  showDone = currentStep === "createTemplateContent" || slidBoxContent === "editTemplate";
1351
+
1352
+ // Additional condition for MobilePush edit in full mode
1353
+ if (channel === constants.MOBILE_PUSH && slidBoxContent === "editTemplate" && isFullMode) {
1354
+ showDone = true;
1355
+ }
1298
1356
  }
1299
1357
 
1358
+
1300
1359
  return showDone;
1301
1360
  }
1302
1361
 
@@ -1356,7 +1415,9 @@ export class Creatives extends React.Component {
1356
1415
  }
1357
1416
 
1358
1417
  shouldShowContinueFooter = () => { // only for email for now, has to be modified according to channel
1359
- const { slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppCreateMode, weChatTemplateType } = this.state;
1418
+ const {
1419
+ slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppCreateMode, weChatTemplateType,
1420
+ } = this.state;
1360
1421
  let isShowContinueFooter = false;
1361
1422
  const currentStep = this.creativesTemplateSteps[templateStep];
1362
1423
  const channel = currentChannel.toUpperCase();
@@ -1439,17 +1500,16 @@ export class Creatives extends React.Component {
1439
1500
  loyaltyMetaData = {},
1440
1501
  } = this.props;
1441
1502
  const mapTemplateCreate =
1442
- slidBoxContent === "createTemplate" &&
1443
- weChatTemplateType === MAP_TEMPLATE &&
1444
- templateStep !== "modeSelection";
1445
- const slideBoxWrapperMargin =
1446
- (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
1447
- ? CAP_SPACE_64
1448
- : get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
1449
- ? CAP_SPACE_56
1450
- : get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
1451
- ? CAP_SPACE_32
1452
- : 0;
1503
+ slidBoxContent === "createTemplate"
1504
+ && weChatTemplateType === MAP_TEMPLATE
1505
+ && templateStep !== "modeSelection";
1506
+ const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
1507
+ ? CAP_SPACE_64
1508
+ : get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
1509
+ ? CAP_SPACE_56
1510
+ : get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
1511
+ ? CAP_SPACE_32
1512
+ : 0;
1453
1513
  /* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
1454
1514
  return (
1455
1515
  <SlideBoxWrapper slideBoxWrapperMargin={slideBoxWrapperMargin} className={classnames(`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`)}>
@@ -1577,7 +1637,6 @@ export class Creatives extends React.Component {
1577
1637
  ) : isLiquidValidationError && (
1578
1638
  <CapRow className="template-footer-width">
1579
1639
  {(() => {
1580
-
1581
1640
  const errorsToShow = get(liquidErrorMessage, constants.LIQUID_ERROR_MSG, []);
1582
1641
  const standardErrorsToShow = get(liquidErrorMessage, constants.STANDARD_ERROR_MSG, []);
1583
1642
  return <ErrorInfoNote currentTab={activeFormBuilderTab?.toUpperCase()} errorMessages={{LIQUID_ERROR_MSG: errorsToShow, STANDARD_ERROR_MSG: standardErrorsToShow}} />;
@@ -1647,7 +1706,7 @@ function mapDispatchToProps(dispatch) {
1647
1706
  const withConnect = connect(mapStatesToProps, mapDispatchToProps);
1648
1707
  const withReducer = injectReducer({ key: 'creativesContainer', reducer: creativesContainerReducer });
1649
1708
  const withSaga = injectSaga({ key: 'cap', saga: capSagaForFetchSchemaForEntity });
1650
- const withLiquidSaga = injectSaga({ key: 'liquid', saga: capSagaLiquidEntity , mode: DAEMON });
1709
+ const withLiquidSaga = injectSaga({ key: 'liquid', saga: capSagaLiquidEntity, mode: DAEMON });
1651
1710
  const withDefaultTempSaga = injectSaga({ key: 'creativesContainer', saga: v2TemplateSagaWatchGetDefaultBeeTemplates });
1652
1711
 
1653
- export default compose(withSaga,withLiquidSaga, withDefaultTempSaga, withReducer, withConnect)(injectIntl(Creatives));
1712
+ export default compose(withSaga, withLiquidSaga, withDefaultTempSaga, withReducer, withConnect)(injectIntl(Creatives));
@@ -820,6 +820,18 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
820
820
  // return response;
821
821
  }
822
822
 
823
+ getTemplateContent = () => {
824
+ const { formData, currentTab } = this.state;
825
+ const currentTabData = formData[currentTab - 1];
826
+ const activeTab = currentTabData?.activeTab;
827
+
828
+ if (currentTabData && activeTab && currentTabData[activeTab]) {
829
+ return currentTabData[activeTab]['template-content'] || '';
830
+ }
831
+
832
+ return '';
833
+ }
834
+
823
835
  setFormValidity = (isFormValid) => {
824
836
  this.setState({isFormValid});
825
837
  }
@@ -2661,7 +2673,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
2661
2673
  formData,
2662
2674
  };
2663
2675
  }, () => {
2664
- this.setState({
2676
+ !this.props.showTestAndPreviewSlidebox && this.setState({
2665
2677
  startValidation: true,
2666
2678
  });
2667
2679
  });
@@ -2774,7 +2786,8 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
2774
2786
  show={showTestAndPreviewSlidebox}
2775
2787
  onClose={handleCloseTestAndPreview}
2776
2788
  formData={this.state.formData}
2777
- content={this.state.formData[(this.state.currentTab - 1)][this.state.formData[(this.state.currentTab - 1)].activeTab] ? this.state.formData[(this.state.currentTab - 1)][this.state.formData[(this.state.currentTab - 1)].activeTab][`template-content`] : ''}
2789
+ beeInstance={this.beeInstance}
2790
+ content={this.getTemplateContent()}
2778
2791
  currentChannel={EMAIL}
2779
2792
  />
2780
2793
  </div>
@@ -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
  {
@@ -46,10 +46,12 @@ import {
46
46
  INITIAL_CTA_DATA,
47
47
  IOS,
48
48
  LAYOUT_RADIO_OPTIONS,
49
- AI_CONTENT_BOT_DISABLED
49
+ AI_CONTENT_BOT_DISABLED,
50
50
  } from "./constants";
51
51
  import { INAPP, SMS } from "../CreativesContainer/constants";
52
- import { ALL, TAG, EMBEDDED, DEFAULT, FULL, LIBRARY } from "../Whatsapp/constants";
52
+ import {
53
+ ALL, TAG, EMBEDDED, DEFAULT, FULL, LIBRARY,
54
+ } from "../Whatsapp/constants";
53
55
  import CapDeviceContent from "../../v2Components/CapDeviceContent";
54
56
  import { getCdnUrl } from "../../utils/cdnTransformation";
55
57
  import { getCtaObject, hasAnyErrors, getSingleTab } from "./utils";
@@ -297,14 +299,13 @@ export const InApp = (props) => {
297
299
 
298
300
  const templateDescErrorHandler = (value) => {
299
301
  let errorMessage = false;
300
- const { unsupportedTags, isBraceError } =
301
- validateTags({
302
- content: value,
303
- tagsParam: tags,
304
- injectedTagsParams: injectedTags,
305
- location,
306
- tagModule: getDefaultTags,
307
- }) || {};
302
+ const { unsupportedTags, isBraceError } = validateTags({
303
+ content: value,
304
+ tagsParam: tags,
305
+ injectedTagsParams: injectedTags,
306
+ location,
307
+ tagModule: getDefaultTags,
308
+ }) || {};
308
309
  if (value === '' && INAPP_MEDIA_TYPES.NONE) {
309
310
  errorMessage = formatMessage(messages.emptyTemplateDescErrorMessage);
310
311
  } else if (unsupportedTags?.length > 0) {
@@ -472,7 +473,7 @@ export const InApp = (props) => {
472
473
  placeholder={formatMessage(globalMessages.templateNamePlaceholder)}
473
474
  value={templateName}
474
475
  size="default"
475
- />
476
+ />
476
477
  </CapRow>
477
478
  );
478
479
  //create methods end
@@ -582,8 +583,7 @@ export const InApp = (props) => {
582
583
  return false;
583
584
  };
584
585
 
585
- const getCtaPayload = (type) =>
586
- (type === ANDROID ? ctaDataAndroid : ctaDataIos).map((cta) => {
586
+ const getCtaPayload = (type) => (type === ANDROID ? ctaDataAndroid : ctaDataIos).map((cta) => {
587
587
  const { text, urlType, url } = cta;
588
588
  return {
589
589
  type: urlType,
@@ -239,6 +239,7 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
239
239
  onLinkTypeChange = (eventTriggered, formData, field) => {
240
240
  let schema = cloneDeep(this.state.schema);
241
241
  const inputFields = get(schema, `containers[0].panes[${this.state.currentTab - 1}].sections[0].childSections[0].childSections[0].inputFields`);
242
+
242
243
  forEach(inputFields, (inputField, fieldIndex) => {
243
244
  if (inputField) {
244
245
  forEach(inputField.cols, (col) => {
@@ -248,20 +248,13 @@ function getLinkTypeFields({inputFieldsArgs, fieldIndex, deepLinkOptions, formDa
248
248
  }
249
249
 
250
250
  function getContent(obj) {
251
- const {
252
- versions : {
253
- base: {
254
- ANDROID: {
255
- title : androidTitle,
256
- message : androidMessage
257
- } = {},
258
- IOS: {
259
- title: iosTitle,
260
- message: iosMessage
261
- } = {}
262
- } = {}
263
- } = {}
264
- } = obj;
251
+ const base = obj?.versions?.base || {};
252
+ const android = base.ANDROID || {};
253
+ const ios = base.IOS || {};
254
+ const androidTitle = android.title || '';
255
+ const androidMessage = android.message || '';
256
+ const iosTitle = ios.title || '';
257
+ const iosMessage = ios.message || '';
265
258
  return `${androidTitle} ${androidMessage} ${iosTitle} ${iosMessage}`;
266
259
  }
267
260
  export {