@capillarytech/creatives-library 8.0.126 → 8.0.127-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.
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 +191 -136
  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,18 +15,18 @@ 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
27
  import SlideBoxHeader from './SlideBoxHeader';
27
28
  import SlideBoxFooter from './SlideBoxFooter';
28
- import TestAndPreviewSlidebox from '../../v2Components/TestAndPreviewSlidebox';
29
+ import SlideBoxContent from './SlideBoxContent';
29
30
  import * as constants from './constants';
30
31
  import * as commonUtil from '../../utils/common';
31
32
  import { gtmPush } from '../../utils/gtmTrackers';
@@ -44,20 +45,16 @@ import {
44
45
  import { IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
45
46
  import { CREATIVE } from '../Facebook/constants';
46
47
  import { LOYALTY } from '../App/constants';
47
- import { WHATSAPP_STATUSES, WHATSAPP_MEDIA_TYPES, PHONE_NUMBER, URL } from '../Whatsapp/constants';
48
-
48
+ import {
49
+ WHATSAPP_STATUSES, WHATSAPP_MEDIA_TYPES, PHONE_NUMBER, URL,
50
+ } from '../Whatsapp/constants';
49
51
  import { updateImagesInHtml } from '../../utils/cdnTransformation';
50
- import { IOS } from '../InApp/constants';
52
+
51
53
  import injectReducer from '../../utils/injectReducer';
52
54
  import injectSaga from '../../utils/injectSaga';
53
55
  import creativesContainerReducer from './reducer';
54
- import { compose } from 'redux';
55
- import { capSagaForFetchSchemaForEntity,capSagaLiquidEntity } from '../Cap/sagas';
56
+ import { capSagaForFetchSchemaForEntity, capSagaLiquidEntity } from '../Cap/sagas';
56
57
  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
58
  import { DYNAMIC_URL } from '../../v2Components/CapWhatsappCTA/constants';
62
59
  import ErrorInfoNote from '../../v2Components/ErrorInfoNote';
63
60
 
@@ -83,11 +80,14 @@ const SlideBoxWrapper = styled.div`
83
80
  export class Creatives extends React.Component {
84
81
  constructor(props) {
85
82
  super(props);
83
+
84
+ const initialSlidBoxContent = this.getSlideBoxContent({ mode: props.creativesMode, templateData: props.templateData, isFullMode: props.isFullMode });
85
+
86
86
  this.state = {
87
87
  isLoadingContent: true,
88
88
  templateStep: 1, //modeSelection: for template name and (for email selecting upload or editor), and createTemplate to create template create based on modeSelection
89
89
  showSlideBox: true,
90
- slidBoxContent: this.getSlideBoxContent({ mode: props.creativesMode, templateData: props.templateData, isFullMode: props.isFullMode }),
90
+ slidBoxContent: initialSlidBoxContent,
91
91
  templateData: this.getTemplateData(props.templateData),
92
92
  templateNameExists: props.creativesMode === 'edit', // if edit mode templateNameExists will be true, and false in create flow.
93
93
  currentChannel: this.props.channel || 'sms',
@@ -154,28 +154,26 @@ export class Creatives extends React.Component {
154
154
  const userId = parseInt(template.updatedBy, 10);
155
155
  templateData.updatedByName = commonUtil.getUserNameById(userId, usersList);
156
156
  this.setState({ slidBoxContent: constants.PREVIEW, templateData });
157
+ } else if (get(template, 'versions.base.content.zalo.previewUrl')) {
158
+ commonUtil.handlePreviewInNewTab(
159
+ template.versions.base.content.zalo.previewUrl
160
+ );
157
161
  } 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
- }
162
+ const {
163
+ name = "",
164
+ sourceAccountIdentifier = "",
165
+ configs: { token = "" } = {},
166
+ hostName = "",
167
+ } = get(this.props, "Templates.selectedZaloAccount", {});
168
+ this.props.zaloActions.getTemplateInfoById({
169
+ username: name,
170
+ oa_id: sourceAccountIdentifier,
171
+ token,
172
+ host: hostName || this.props?.hostName || this.props.Templates?.senderDetails?.hostName,
173
+ id: template?._id,
174
+ preview: true,
175
+ actionCallback: this.actionCallback,
176
+ });
179
177
  }
180
178
  };
181
179
 
@@ -244,38 +242,40 @@ export class Creatives extends React.Component {
244
242
  this.setState({ isGetFormData: false });
245
243
  };
246
244
 
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
- }
245
+ mapCarouselDataToCreatives = (cards) => cards.map((card) => {
246
+ const {
247
+ cardVarMapped, bodyTemplate, media, buttons, mediaType,
248
+ } = card || {};
249
+ const buttonData = buttons?.map((button) => {
250
+ const {
251
+ type, text, phoneNumber, url, dynamicUrlPayload,
252
+ } = button || {};
253
+ const buttonObj = { type, text };
254
+ if (type === PHONE_NUMBER) {
255
+ buttonObj.phone_number = phoneNumber;
256
+ }
257
+ if (type === URL) {
258
+ buttonObj.url = url;
259
+ if (dynamicUrlPayload) {
260
+ buttonObj.urlType = DYNAMIC_URL;
261
261
  }
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
- };
262
+ }
263
+ return buttonObj;
277
264
  });
278
- }
265
+ return {
266
+ bodyText: bodyTemplate,
267
+ varMap: cardVarMapped,
268
+ ...(mediaType === IMAGE && {
269
+ imageUrl: media?.url,
270
+ }),
271
+ ...(mediaType === VIDEO && {
272
+ videoUrl: media?.url,
273
+ videoPreviewImg: media?.previewUrl,
274
+ }),
275
+ buttons: buttonData,
276
+ mediaType: mediaType?.toLowerCase(),
277
+ };
278
+ })
279
279
 
280
280
  getTemplateData = (templateData) => { //from consumers to creatives
281
281
  const { isFullMode, messageDetails = {}, smsRegister } = this.props;
@@ -355,13 +355,33 @@ export class Creatives extends React.Component {
355
355
  }
356
356
  case constants.MOBILE_PUSH: {
357
357
  const mode = get(templateData, 'androidContent.type') || get(templateData, 'iosContent.type') || '';
358
+ const androidCarouselMedia = get(templateData, 'androidContent.expandableDetails.media', []);
359
+ const iosCarouselMedia = get(templateData, 'iosContent.expandableDetails.media', []);
360
+ const androidContent = { ...(templateData?.androidContent || {}) };
361
+ const iosContent = { ...(templateData?.iosContent || {}) };
362
+ if (androidCarouselMedia?.length) {
363
+ androidContent.expandableDetails.carouselData = androidCarouselMedia.map((media) => ({
364
+ mediaType: media.type,
365
+ imageUrl: media.url,
366
+ buttons: [],
367
+ videoSrc: '',
368
+ }));
369
+ }
370
+ if (iosCarouselMedia?.length) {
371
+ iosContent.expandableDetails.carouselData = iosCarouselMedia.map((media) => ({
372
+ mediaType: media.type,
373
+ imageUrl: media.url,
374
+ buttons: [],
375
+ videoSrc: '',
376
+ }));
377
+ }
358
378
  creativesTemplateData = {
359
379
  type: channel,
360
380
  name: templateData.messageSubject,
361
381
  versions: {
362
382
  base: {
363
- ANDROID: templateData.androidContent,
364
- IOS: templateData.iosContent,
383
+ ANDROID: androidContent,
384
+ IOS: iosContent,
365
385
  },
366
386
  },
367
387
  definition: { accountId: templateData.accountId, mode: mode.toLowerCase() },
@@ -523,7 +543,9 @@ export class Creatives extends React.Component {
523
543
  } = {},
524
544
  } = templateData;
525
545
  const mediaParams = {};
526
- const { url = '', previewUrl = '', docParams = {}, footer = '', headerVarMapped = {}, headerTemplate = '' } = whatsappMedia || {};
546
+ const {
547
+ url = '', previewUrl = '', docParams = {}, footer = '', headerVarMapped = {}, headerTemplate = '',
548
+ } = whatsappMedia || {};
527
549
  switch (mediaType) {
528
550
  case (WHATSAPP_MEDIA_TYPES.IMAGE):
529
551
  mediaParams.imageUrl = url;
@@ -543,7 +565,7 @@ export class Creatives extends React.Component {
543
565
  break;
544
566
  }
545
567
  const modifiedButtons = cloneDeep(buttons)?.map((btn) => {
546
- if (btn.type === 'PHONE_NUMBER') {
568
+ if (btn.type === PHONE_NUMBER) {
547
569
  btn.phone_number = btn.phoneNumber;
548
570
  delete btn.phoneNumber;
549
571
  return btn;
@@ -636,46 +658,61 @@ export class Creatives extends React.Component {
636
658
  return templateData || null;
637
659
  }
638
660
 
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(),
661
+ getCarouselMappedData = (carouselData = []) => carouselData.map((carousel) => {
662
+ const {
663
+ bodyText, imageUrl, videoUrl, videoPreviewImg, buttons, mediaType, cardVarMapped, bodyTemplate,
664
+ } = carousel || {};
665
+ const buttonData = buttons.map((button, index) => {
666
+ const {
667
+ type, text, phone_number, urlType, url,
668
+ } = button || {};
669
+ const buttonObj = {
670
+ type,
671
+ text,
672
+ index,
676
673
  };
674
+ if (type === PHONE_NUMBER) {
675
+ buttonObj.phoneNumber = phone_number;
676
+ }
677
+ if (type === URL) {
678
+ buttonObj.url = url;
679
+ if (urlType === DYNAMIC_URL) {
680
+ const dynamicUrlPayload = url?.match(/{{(.*?)}}/g);
681
+ buttonObj.dynamicUrlPayload = dynamicUrlPayload?.length === 1 ? dynamicUrlPayload[0] : '';
682
+ }
683
+ }
684
+ return buttonObj;
677
685
  });
678
- };
686
+ return {
687
+ body: bodyText,
688
+ cardVarMapped,
689
+ bodyTemplate,
690
+ media: {
691
+ ...(mediaType?.toLowerCase() === IMAGE.toLowerCase() && {
692
+ url: imageUrl,
693
+ }),
694
+ ...(mediaType?.toLowerCase() === VIDEO.toLowerCase() && {
695
+ url: videoUrl,
696
+ previewUrl: videoPreviewImg,
697
+ }),
698
+ },
699
+ buttons: buttonData,
700
+ mediaType: mediaType?.toUpperCase(),
701
+ };
702
+ });
703
+
704
+ getMobilePushCarouselData = (expandableDetails = []) => {
705
+ const newExpandableDetails = {...expandableDetails};
706
+ newExpandableDetails.style = expandableDetails.style || 'MANUAL_CAROUSEL';
707
+ newExpandableDetails.message = expandableDetails.message || '';
708
+ newExpandableDetails.ctas = expandableDetails.ctas || [];
709
+ newExpandableDetails.media = expandableDetails.carouselData.map((carousel) => ({
710
+ url: carousel.imageUrl,
711
+ type: carousel?.mediaType?.toUpperCase(),
712
+ text: '',
713
+ }));
714
+ return newExpandableDetails;
715
+ }
679
716
 
680
717
  getCreativesData = async (channel, template, templateRecords) => { //from creatives to consumers
681
718
  let templateData = { channel };
@@ -759,6 +796,9 @@ export class Creatives extends React.Component {
759
796
  if (channel !== constants.MOBILE_PUSH) {
760
797
  androidContent.custom = custom;
761
798
  }
799
+ if (channel === constants.MOBILE_PUSH && androidContent?.expandableDetails?.carouselData?.length) {
800
+ androidContent.expandableDetails = this.getMobilePushCarouselData({...androidContent?.expandableDetails});
801
+ }
762
802
  templateData.androidContent = androidContent;
763
803
  templateData.androidContent.type = get(channelTemplate, 'definition.mode', '').toUpperCase();
764
804
  templateData.androidContent.deviceType = constants.ANDROID;
@@ -778,6 +818,9 @@ export class Creatives extends React.Component {
778
818
  if (channel !== constants.MOBILE_PUSH) {
779
819
  iosContent.custom = custom;
780
820
  }
821
+ if (channel === constants.MOBILE_PUSH && iosContent?.expandableDetails?.carouselData?.length) {
822
+ iosContent.expandableDetails = this.getMobilePushCarouselData({...iosContent?.expandableDetails});
823
+ }
781
824
  templateData.iosContent = iosContent;
782
825
  templateData.iosContent.type = get(channelTemplate, 'definition.mode').toUpperCase();
783
826
  templateData.iosContent.deviceType = constants.IOS;
@@ -947,7 +990,7 @@ export class Creatives extends React.Component {
947
990
  fBContent.forEach((obj) => {
948
991
  const data = cloneDeep(obj);
949
992
  const {
950
- subType, linkDesc, imgSrc, webSiteLink, video
993
+ subType, linkDesc, imgSrc, webSiteLink, video,
951
994
  } = obj;
952
995
  delete data.type;
953
996
  delete data.linkDesc;
@@ -985,7 +1028,7 @@ export class Creatives extends React.Component {
985
1028
  break;
986
1029
  case constants.RCS: {
987
1030
  if (template.value) {
988
- const { name = "", versions = {}, type = "" } = {
1031
+ const { name = "", versions = {} } = {
989
1032
  } = template.value || {};
990
1033
  const {
991
1034
  cardContent = [],
@@ -1113,7 +1156,6 @@ export class Creatives extends React.Component {
1113
1156
  }
1114
1157
 
1115
1158
  getFormData = (template) => {
1116
-
1117
1159
  if (template.validity) {
1118
1160
  this.setState(
1119
1161
  {
@@ -1131,7 +1173,7 @@ export class Creatives extends React.Component {
1131
1173
  );
1132
1174
  }
1133
1175
  }
1134
-
1176
+
1135
1177
  processCentralCommsMetaId = (channel, creativesData) => {
1136
1178
  // Create the payload for the centralcommnsmetaId API call
1137
1179
  const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
@@ -1222,13 +1264,16 @@ export class Creatives extends React.Component {
1222
1264
 
1223
1265
  shouldShowFooter = () => {
1224
1266
  const { isFullMode } = this.props;
1225
- const { slidBoxContent, currentChannel, emailCreateMode, templateNameExists, templateStep, mobilePushCreateMode, inAppCreateMode, weChatTemplateType, templateData } = this.state;
1267
+ const {
1268
+ slidBoxContent, currentChannel, emailCreateMode, templateNameExists, templateStep, mobilePushCreateMode, weChatTemplateType, templateData,
1269
+ } = this.state;
1226
1270
  const channel = currentChannel.toUpperCase();
1227
1271
  const currentStep = this.creativesTemplateSteps[templateStep];
1228
1272
  let showFooter = false;
1229
1273
  showFooter = isFullMode && slidBoxContent === "preview";
1230
1274
  const isMobilepush = channel === constants.MOBILE_PUSH;
1231
- const isInApp = channel === constants.INAPP;
1275
+
1276
+
1232
1277
  if (!isFullMode) {
1233
1278
  const isEmailCreate = slidBoxContent === 'createTemplate' && channel === constants.EMAIL && currentStep !== 'createTemplateContent';
1234
1279
  const isCreate = (slidBoxContent === 'editTemplate' || slidBoxContent === 'createTemplate') && !isEmailCreate;
@@ -1250,15 +1295,15 @@ export class Creatives extends React.Component {
1250
1295
  if (slidBoxContent === "editTemplate" && ((channel === constants.EMAIL && currentStep === 'modeSelection'))) {
1251
1296
  showFooter = true;
1252
1297
  }
1253
- if (channel === constants.MOBILE_PUSH &&
1254
- ((slidBoxContent === 'createTemplate' && !isEmpty(mobilePushCreateMode))
1255
- || (slidBoxContent === 'editTemplate' && currentStep === 'modeSelection')) &&
1298
+ if (channel === constants.MOBILE_PUSH
1299
+ && ((slidBoxContent === 'createTemplate' && !isEmpty(mobilePushCreateMode))
1300
+ || (slidBoxContent === 'editTemplate' && (currentStep === 'modeSelection' || isFullMode))) &&
1256
1301
  templateNameExists) {
1257
1302
  showFooter = true;
1258
1303
  }
1259
1304
 
1260
- if (channel === constants.WECHAT &&
1261
- ((slidBoxContent === 'createTemplate' && !isEmpty(weChatTemplateType))
1305
+ if (channel === constants.WECHAT
1306
+ && ((slidBoxContent === 'createTemplate' && !isEmpty(weChatTemplateType))
1262
1307
  || (slidBoxContent === 'editTemplate' && currentStep === 'modeSelection'))) {
1263
1308
  showFooter = true;
1264
1309
  }
@@ -1267,9 +1312,9 @@ export class Creatives extends React.Component {
1267
1312
  if (slidBoxContent === "createTemplate" && ((channel === constants.EMAIL && currentStep === 'createTemplateContent') ||
1268
1313
  ([constants.SMS, constants.WECHAT].includes(channel) && currentStep === 'modeSelection'))) {
1269
1314
  showFooter = showFooter && !this.state.isLoadingContent;
1270
- } else if (slidBoxContent === "editTemplate" &&
1271
- ([constants.SMS, constants.WECHAT, constants.EMAIL].includes(channel) &&
1272
- currentStep === 'modeSelection')) {
1315
+ } else if (slidBoxContent === "editTemplate"
1316
+ && ([constants.SMS, constants.WECHAT, constants.EMAIL].includes(channel)
1317
+ && currentStep === 'modeSelection')) {
1273
1318
  showFooter = showFooter && !this.state.isLoadingContent;
1274
1319
  }
1275
1320
  }
@@ -1278,6 +1323,8 @@ export class Creatives extends React.Component {
1278
1323
  if ([constants.LINE, constants.VIBER, constants.FACEBOOK].includes(channel) || isLineViberChannel) {
1279
1324
  showFooter = false;
1280
1325
  }
1326
+
1327
+
1281
1328
  return showFooter;
1282
1329
  }
1283
1330
 
@@ -1290,13 +1337,21 @@ export class Creatives extends React.Component {
1290
1337
  let showDone = false;
1291
1338
  const channelName = !isFullMode && templateData ? templateData.type : currentChannel;
1292
1339
  const channel = channelName?.toUpperCase();
1340
+
1341
+
1293
1342
  if (channel === constants.EMAIL || channel === constants.SMS) {
1294
1343
  const isEmailCreate = slidBoxContent === 'createTemplate' && channel === constants.EMAIL && currentStep !== 'createTemplateContent';
1295
1344
  showDone = (slidBoxContent === 'editTemplate' || slidBoxContent === 'createTemplate') && !isEmailCreate;
1296
1345
  } else if ([constants.WECHAT, constants.MOBILE_PUSH].includes(channel)) {
1297
1346
  showDone = currentStep === "createTemplateContent" || slidBoxContent === "editTemplate";
1347
+
1348
+ // Additional condition for MobilePush edit in full mode
1349
+ if (channel === constants.MOBILE_PUSH && slidBoxContent === "editTemplate" && isFullMode) {
1350
+ showDone = true;
1351
+ }
1298
1352
  }
1299
1353
 
1354
+
1300
1355
  return showDone;
1301
1356
  }
1302
1357
 
@@ -1356,7 +1411,9 @@ export class Creatives extends React.Component {
1356
1411
  }
1357
1412
 
1358
1413
  shouldShowContinueFooter = () => { // only for email for now, has to be modified according to channel
1359
- const { slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppCreateMode, weChatTemplateType } = this.state;
1414
+ const {
1415
+ slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppCreateMode, weChatTemplateType,
1416
+ } = this.state;
1360
1417
  let isShowContinueFooter = false;
1361
1418
  const currentStep = this.creativesTemplateSteps[templateStep];
1362
1419
  const channel = currentChannel.toUpperCase();
@@ -1439,17 +1496,16 @@ export class Creatives extends React.Component {
1439
1496
  loyaltyMetaData = {},
1440
1497
  } = this.props;
1441
1498
  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;
1499
+ slidBoxContent === "createTemplate"
1500
+ && weChatTemplateType === MAP_TEMPLATE
1501
+ && templateStep !== "modeSelection";
1502
+ const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
1503
+ ? CAP_SPACE_64
1504
+ : get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
1505
+ ? CAP_SPACE_56
1506
+ : get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
1507
+ ? CAP_SPACE_32
1508
+ : 0;
1453
1509
  /* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
1454
1510
  return (
1455
1511
  <SlideBoxWrapper slideBoxWrapperMargin={slideBoxWrapperMargin} className={classnames(`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`)}>
@@ -1577,7 +1633,6 @@ export class Creatives extends React.Component {
1577
1633
  ) : isLiquidValidationError && (
1578
1634
  <CapRow className="template-footer-width">
1579
1635
  {(() => {
1580
-
1581
1636
  const errorsToShow = get(liquidErrorMessage, constants.LIQUID_ERROR_MSG, []);
1582
1637
  const standardErrorsToShow = get(liquidErrorMessage, constants.STANDARD_ERROR_MSG, []);
1583
1638
  return <ErrorInfoNote currentTab={activeFormBuilderTab?.toUpperCase()} errorMessages={{LIQUID_ERROR_MSG: errorsToShow, STANDARD_ERROR_MSG: standardErrorsToShow}} />;
@@ -1647,7 +1702,7 @@ function mapDispatchToProps(dispatch) {
1647
1702
  const withConnect = connect(mapStatesToProps, mapDispatchToProps);
1648
1703
  const withReducer = injectReducer({ key: 'creativesContainer', reducer: creativesContainerReducer });
1649
1704
  const withSaga = injectSaga({ key: 'cap', saga: capSagaForFetchSchemaForEntity });
1650
- const withLiquidSaga = injectSaga({ key: 'liquid', saga: capSagaLiquidEntity , mode: DAEMON });
1705
+ const withLiquidSaga = injectSaga({ key: 'liquid', saga: capSagaLiquidEntity, mode: DAEMON });
1651
1706
  const withDefaultTempSaga = injectSaga({ key: 'creativesContainer', saga: v2TemplateSagaWatchGetDefaultBeeTemplates });
1652
1707
 
1653
- export default compose(withSaga,withLiquidSaga, withDefaultTempSaga, withReducer, withConnect)(injectIntl(Creatives));
1708
+ 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) => {