@capillarytech/creatives-library 8.0.130 → 8.0.131

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 (77) hide show
  1. package/containers/App/constants.js +1 -0
  2. package/containers/Login/index.js +1 -2
  3. package/package.json +1 -1
  4. package/services/api.js +5 -0
  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/createMobilePushPayload.js +322 -0
  11. package/utils/tests/createMobilePushPayload.test.js +1054 -0
  12. package/v2Components/CapDeviceContent/index.js +1 -1
  13. package/v2Components/CapImageUpload/index.js +57 -44
  14. package/v2Components/CapInAppCTA/index.js +1 -0
  15. package/v2Components/CapMpushCTA/constants.js +25 -0
  16. package/v2Components/CapMpushCTA/index.js +403 -0
  17. package/v2Components/CapMpushCTA/index.scss +95 -0
  18. package/v2Components/CapMpushCTA/messages.js +101 -0
  19. package/v2Components/CapTagList/index.js +178 -121
  20. package/v2Components/CapVideoUpload/constants.js +3 -0
  21. package/v2Components/CapVideoUpload/index.js +182 -115
  22. package/v2Components/CapVideoUpload/messages.js +16 -0
  23. package/v2Components/Carousel/index.js +15 -13
  24. package/v2Components/ErrorInfoNote/style.scss +1 -0
  25. package/v2Components/MobilePushPreviewV2/index.js +57 -12
  26. package/v2Components/TemplatePreview/_templatePreview.scss +218 -74
  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 +234 -107
  32. package/v2Components/TemplatePreview/messages.js +4 -0
  33. package/v2Components/TemplatePreview/tests/__snapshots__/index.test.js.snap +10 -10
  34. package/v2Containers/CreativesContainer/SlideBoxContent.js +127 -62
  35. package/v2Containers/CreativesContainer/index.js +193 -136
  36. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -22
  37. package/v2Containers/InApp/constants.js +1 -0
  38. package/v2Containers/InApp/index.js +13 -13
  39. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +4748 -4658
  40. package/v2Containers/Login/index.js +1 -2
  41. package/v2Containers/MobilePush/Create/index.js +1 -0
  42. package/v2Containers/MobilePush/commonMethods.js +7 -14
  43. package/v2Containers/MobilePush/tests/commonMethods.test.js +401 -0
  44. package/v2Containers/MobilePushNew/actions.js +116 -0
  45. package/v2Containers/MobilePushNew/components/CtaButtons.js +183 -0
  46. package/v2Containers/MobilePushNew/components/MediaUploaders.js +835 -0
  47. package/v2Containers/MobilePushNew/components/PlatformContentFields.js +346 -0
  48. package/v2Containers/MobilePushNew/components/index.js +5 -0
  49. package/v2Containers/MobilePushNew/components/tests/CtaButtons.test.js +565 -0
  50. package/v2Containers/MobilePushNew/components/tests/MediaUploaders.test.js +3180 -0
  51. package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +654 -0
  52. package/v2Containers/MobilePushNew/constants.js +116 -0
  53. package/v2Containers/MobilePushNew/hooks/tests/usePlatformSync.test.js +1462 -0
  54. package/v2Containers/MobilePushNew/hooks/tests/useUpload.test.js +1459 -0
  55. package/v2Containers/MobilePushNew/hooks/usePlatformSync.js +366 -0
  56. package/v2Containers/MobilePushNew/hooks/useUpload.js +740 -0
  57. package/v2Containers/MobilePushNew/index.js +2158 -0
  58. package/v2Containers/MobilePushNew/index.scss +308 -0
  59. package/v2Containers/MobilePushNew/messages.js +272 -0
  60. package/v2Containers/MobilePushNew/reducer.js +160 -0
  61. package/v2Containers/MobilePushNew/sagas.js +193 -0
  62. package/v2Containers/MobilePushNew/selectors.js +55 -0
  63. package/v2Containers/MobilePushNew/tests/reducer.test.js +741 -0
  64. package/v2Containers/MobilePushNew/tests/sagas.test.js +864 -0
  65. package/v2Containers/MobilePushNew/tests/selectors.test.js +665 -0
  66. package/v2Containers/MobilePushNew/tests/utils.test.js +421 -0
  67. package/v2Containers/MobilePushNew/utils.js +84 -0
  68. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +1176 -976
  69. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +684 -424
  70. package/v2Containers/TagList/index.js +56 -10
  71. package/v2Containers/Templates/_templates.scss +100 -1
  72. package/v2Containers/Templates/index.js +170 -31
  73. package/v2Containers/Templates/messages.js +8 -0
  74. package/v2Containers/Templates/sagas.js +1 -0
  75. package/v2Containers/Whatsapp/constants.js +1 -0
  76. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +3992 -3677
  77. package/assets/loading_img.gif +0 -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
 
@@ -65,6 +62,7 @@ import {
65
62
  transformChannelPayload,
66
63
  // getTemplateDiffState
67
64
  } from "../../utils/transformerUtils";
65
+ import { MANUAL_CAROUSEL } from '../MobilePushNew/constants';
68
66
 
69
67
  const classPrefix = 'add-creatives-section';
70
68
  const CREATIVES_CONTAINER = 'creativesContainer';
@@ -83,11 +81,14 @@ const SlideBoxWrapper = styled.div`
83
81
  export class Creatives extends React.Component {
84
82
  constructor(props) {
85
83
  super(props);
84
+
85
+ const initialSlidBoxContent = this.getSlideBoxContent({ mode: props.creativesMode, templateData: props.templateData, isFullMode: props.isFullMode });
86
+
86
87
  this.state = {
87
88
  isLoadingContent: true,
88
89
  templateStep: 1, //modeSelection: for template name and (for email selecting upload or editor), and createTemplate to create template create based on modeSelection
89
90
  showSlideBox: true,
90
- slidBoxContent: this.getSlideBoxContent({ mode: props.creativesMode, templateData: props.templateData, isFullMode: props.isFullMode }),
91
+ slidBoxContent: initialSlidBoxContent,
91
92
  templateData: this.getTemplateData(props.templateData),
92
93
  templateNameExists: props.creativesMode === 'edit', // if edit mode templateNameExists will be true, and false in create flow.
93
94
  currentChannel: this.props.channel || 'sms',
@@ -154,28 +155,26 @@ export class Creatives extends React.Component {
154
155
  const userId = parseInt(template.updatedBy, 10);
155
156
  templateData.updatedByName = commonUtil.getUserNameById(userId, usersList);
156
157
  this.setState({ slidBoxContent: constants.PREVIEW, templateData });
158
+ } else if (get(template, 'versions.base.content.zalo.previewUrl')) {
159
+ commonUtil.handlePreviewInNewTab(
160
+ template.versions.base.content.zalo.previewUrl
161
+ );
157
162
  } 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
- }
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
+ });
179
178
  }
180
179
  };
181
180
 
@@ -244,38 +243,41 @@ export class Creatives extends React.Component {
244
243
  this.setState({ isGetFormData: false });
245
244
  };
246
245
 
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
- }
246
+ mapCarouselDataToCreatives = (cards) => cards.map((card) => {
247
+ const {
248
+ cardVarMapped, bodyTemplate, media, buttons, mediaType,
249
+ } = card || {};
250
+ const buttonData = buttons?.map((button) => {
251
+ const {
252
+ type, text, phoneNumber, url, dynamicUrlPayload,
253
+ } = button || {};
254
+ const buttonObj = { type, text };
255
+ if (type === PHONE_NUMBER) {
256
+ buttonObj.phone_number = phoneNumber;
257
+ }
258
+ if (type === URL) {
259
+ buttonObj.url = url;
260
+ if (dynamicUrlPayload) {
261
+ buttonObj.urlType = DYNAMIC_URL;
261
262
  }
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
- };
263
+ }
264
+ return buttonObj;
277
265
  });
278
- }
266
+ const {url, previewUrl} = media || {};
267
+ return {
268
+ bodyText: bodyTemplate,
269
+ varMap: cardVarMapped,
270
+ ...(mediaType === IMAGE && {
271
+ imageUrl: url,
272
+ }),
273
+ ...(mediaType === VIDEO && {
274
+ videoUrl: url,
275
+ videoPreviewImg: previewUrl,
276
+ }),
277
+ buttons: buttonData,
278
+ mediaType: mediaType?.toLowerCase(),
279
+ };
280
+ })
279
281
 
280
282
  getTemplateData = (templateData) => { //from consumers to creatives
281
283
  const { isFullMode, messageDetails = {}, smsRegister } = this.props;
@@ -355,13 +357,33 @@ export class Creatives extends React.Component {
355
357
  }
356
358
  case constants.MOBILE_PUSH: {
357
359
  const mode = get(templateData, 'androidContent.type') || get(templateData, 'iosContent.type') || '';
360
+ const androidCarouselMedia = get(templateData, 'androidContent.expandableDetails.media', []);
361
+ const iosCarouselMedia = get(templateData, 'iosContent.expandableDetails.media', []);
362
+ const androidContent = { ...(templateData?.androidContent || {}) };
363
+ const iosContent = { ...(templateData?.iosContent || {}) };
364
+ if (androidCarouselMedia?.length) {
365
+ androidContent.expandableDetails.carouselData = androidCarouselMedia.map((media) => ({
366
+ mediaType: media.type,
367
+ imageUrl: media.url,
368
+ buttons: [],
369
+ videoSrc: '',
370
+ }));
371
+ }
372
+ if (iosCarouselMedia?.length) {
373
+ iosContent.expandableDetails.carouselData = iosCarouselMedia.map((media) => ({
374
+ mediaType: media.type,
375
+ imageUrl: media.url,
376
+ buttons: [],
377
+ videoSrc: '',
378
+ }));
379
+ }
358
380
  creativesTemplateData = {
359
381
  type: channel,
360
382
  name: templateData.messageSubject,
361
383
  versions: {
362
384
  base: {
363
- ANDROID: templateData.androidContent,
364
- IOS: templateData.iosContent,
385
+ ANDROID: androidContent,
386
+ IOS: iosContent,
365
387
  },
366
388
  },
367
389
  definition: { accountId: templateData.accountId, mode: mode.toLowerCase() },
@@ -523,7 +545,9 @@ export class Creatives extends React.Component {
523
545
  } = {},
524
546
  } = templateData;
525
547
  const mediaParams = {};
526
- const { url = '', previewUrl = '', docParams = {}, footer = '', headerVarMapped = {}, headerTemplate = '' } = whatsappMedia || {};
548
+ const {
549
+ url = '', previewUrl = '', docParams = {}, footer = '', headerVarMapped = {}, headerTemplate = '',
550
+ } = whatsappMedia || {};
527
551
  switch (mediaType) {
528
552
  case (WHATSAPP_MEDIA_TYPES.IMAGE):
529
553
  mediaParams.imageUrl = url;
@@ -543,7 +567,7 @@ export class Creatives extends React.Component {
543
567
  break;
544
568
  }
545
569
  const modifiedButtons = cloneDeep(buttons)?.map((btn) => {
546
- if (btn.type === 'PHONE_NUMBER') {
570
+ if (btn.type === PHONE_NUMBER) {
547
571
  btn.phone_number = btn.phoneNumber;
548
572
  delete btn.phoneNumber;
549
573
  return btn;
@@ -636,46 +660,61 @@ export class Creatives extends React.Component {
636
660
  return templateData || null;
637
661
  }
638
662
 
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(),
663
+ getCarouselMappedData = (carouselData = []) => carouselData.map((carousel) => {
664
+ const {
665
+ bodyText, imageUrl, videoUrl, videoPreviewImg, buttons, mediaType, cardVarMapped, bodyTemplate,
666
+ } = carousel || {};
667
+ const buttonData = buttons.map((button, index) => {
668
+ const {
669
+ type, text, phone_number, urlType, url,
670
+ } = button || {};
671
+ const buttonObj = {
672
+ type,
673
+ text,
674
+ index,
676
675
  };
676
+ if (type === PHONE_NUMBER) {
677
+ buttonObj.phoneNumber = phone_number;
678
+ }
679
+ if (type === URL) {
680
+ buttonObj.url = url;
681
+ if (urlType === DYNAMIC_URL) {
682
+ const dynamicUrlPayload = url?.match(/{{(.*?)}}/g);
683
+ buttonObj.dynamicUrlPayload = dynamicUrlPayload?.length === 1 ? dynamicUrlPayload[0] : '';
684
+ }
685
+ }
686
+ return buttonObj;
677
687
  });
678
- };
688
+ return {
689
+ body: bodyText,
690
+ cardVarMapped,
691
+ bodyTemplate,
692
+ media: {
693
+ ...(mediaType?.toLowerCase() === IMAGE.toLowerCase() && {
694
+ url: imageUrl,
695
+ }),
696
+ ...(mediaType?.toLowerCase() === VIDEO.toLowerCase() && {
697
+ url: videoUrl,
698
+ previewUrl: videoPreviewImg,
699
+ }),
700
+ },
701
+ buttons: buttonData,
702
+ mediaType: mediaType?.toUpperCase(),
703
+ };
704
+ });
705
+
706
+ getMobilePushCarouselData = (expandableDetails = []) => {
707
+ const newExpandableDetails = {...expandableDetails};
708
+ newExpandableDetails.style = expandableDetails.style || MANUAL_CAROUSEL;
709
+ newExpandableDetails.message = expandableDetails.message || '';
710
+ newExpandableDetails.ctas = expandableDetails.ctas || [];
711
+ newExpandableDetails.media = expandableDetails.carouselData.map((carousel) => ({
712
+ url: carousel.imageUrl,
713
+ type: carousel?.mediaType?.toUpperCase(),
714
+ text: '',
715
+ }));
716
+ return newExpandableDetails;
717
+ }
679
718
 
680
719
  getCreativesData = async (channel, template, templateRecords) => { //from creatives to consumers
681
720
  let templateData = { channel };
@@ -759,6 +798,9 @@ export class Creatives extends React.Component {
759
798
  if (channel !== constants.MOBILE_PUSH) {
760
799
  androidContent.custom = custom;
761
800
  }
801
+ if (channel === constants.MOBILE_PUSH && androidContent?.expandableDetails?.carouselData?.length) {
802
+ androidContent.expandableDetails = this.getMobilePushCarouselData({...androidContent?.expandableDetails});
803
+ }
762
804
  templateData.androidContent = androidContent;
763
805
  templateData.androidContent.type = get(channelTemplate, 'definition.mode', '').toUpperCase();
764
806
  templateData.androidContent.deviceType = constants.ANDROID;
@@ -778,6 +820,9 @@ export class Creatives extends React.Component {
778
820
  if (channel !== constants.MOBILE_PUSH) {
779
821
  iosContent.custom = custom;
780
822
  }
823
+ if (channel === constants.MOBILE_PUSH && iosContent?.expandableDetails?.carouselData?.length) {
824
+ iosContent.expandableDetails = this.getMobilePushCarouselData({...iosContent?.expandableDetails});
825
+ }
781
826
  templateData.iosContent = iosContent;
782
827
  templateData.iosContent.type = get(channelTemplate, 'definition.mode').toUpperCase();
783
828
  templateData.iosContent.deviceType = constants.IOS;
@@ -947,7 +992,7 @@ export class Creatives extends React.Component {
947
992
  fBContent.forEach((obj) => {
948
993
  const data = cloneDeep(obj);
949
994
  const {
950
- subType, linkDesc, imgSrc, webSiteLink, video
995
+ subType, linkDesc, imgSrc, webSiteLink, video,
951
996
  } = obj;
952
997
  delete data.type;
953
998
  delete data.linkDesc;
@@ -985,7 +1030,7 @@ export class Creatives extends React.Component {
985
1030
  break;
986
1031
  case constants.RCS: {
987
1032
  if (template.value) {
988
- const { name = "", versions = {}, type = "" } = {
1033
+ const { name = "", versions = {} } = {
989
1034
  } = template.value || {};
990
1035
  const {
991
1036
  cardContent = [],
@@ -1113,7 +1158,6 @@ export class Creatives extends React.Component {
1113
1158
  }
1114
1159
 
1115
1160
  getFormData = (template) => {
1116
-
1117
1161
  if (template.validity) {
1118
1162
  this.setState(
1119
1163
  {
@@ -1131,7 +1175,7 @@ export class Creatives extends React.Component {
1131
1175
  );
1132
1176
  }
1133
1177
  }
1134
-
1178
+
1135
1179
  processCentralCommsMetaId = (channel, creativesData) => {
1136
1180
  // Create the payload for the centralcommnsmetaId API call
1137
1181
  const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
@@ -1222,13 +1266,16 @@ export class Creatives extends React.Component {
1222
1266
 
1223
1267
  shouldShowFooter = () => {
1224
1268
  const { isFullMode } = this.props;
1225
- const { slidBoxContent, currentChannel, emailCreateMode, templateNameExists, templateStep, mobilePushCreateMode, inAppCreateMode, weChatTemplateType, templateData } = this.state;
1269
+ const {
1270
+ slidBoxContent, currentChannel, emailCreateMode, templateNameExists, templateStep, mobilePushCreateMode, weChatTemplateType, templateData,
1271
+ } = this.state;
1226
1272
  const channel = currentChannel.toUpperCase();
1227
1273
  const currentStep = this.creativesTemplateSteps[templateStep];
1228
1274
  let showFooter = false;
1229
1275
  showFooter = isFullMode && slidBoxContent === "preview";
1230
1276
  const isMobilepush = channel === constants.MOBILE_PUSH;
1231
- const isInApp = channel === constants.INAPP;
1277
+
1278
+
1232
1279
  if (!isFullMode) {
1233
1280
  const isEmailCreate = slidBoxContent === 'createTemplate' && channel === constants.EMAIL && currentStep !== 'createTemplateContent';
1234
1281
  const isCreate = (slidBoxContent === 'editTemplate' || slidBoxContent === 'createTemplate') && !isEmailCreate;
@@ -1250,15 +1297,15 @@ export class Creatives extends React.Component {
1250
1297
  if (slidBoxContent === "editTemplate" && ((channel === constants.EMAIL && currentStep === 'modeSelection'))) {
1251
1298
  showFooter = true;
1252
1299
  }
1253
- if (channel === constants.MOBILE_PUSH &&
1254
- ((slidBoxContent === 'createTemplate' && !isEmpty(mobilePushCreateMode))
1255
- || (slidBoxContent === 'editTemplate' && currentStep === 'modeSelection')) &&
1300
+ if (channel === constants.MOBILE_PUSH
1301
+ && ((slidBoxContent === 'createTemplate' && !isEmpty(mobilePushCreateMode))
1302
+ || (slidBoxContent === 'editTemplate' && (currentStep === 'modeSelection' || isFullMode))) &&
1256
1303
  templateNameExists) {
1257
1304
  showFooter = true;
1258
1305
  }
1259
1306
 
1260
- if (channel === constants.WECHAT &&
1261
- ((slidBoxContent === 'createTemplate' && !isEmpty(weChatTemplateType))
1307
+ if (channel === constants.WECHAT
1308
+ && ((slidBoxContent === 'createTemplate' && !isEmpty(weChatTemplateType))
1262
1309
  || (slidBoxContent === 'editTemplate' && currentStep === 'modeSelection'))) {
1263
1310
  showFooter = true;
1264
1311
  }
@@ -1267,9 +1314,9 @@ export class Creatives extends React.Component {
1267
1314
  if (slidBoxContent === "createTemplate" && ((channel === constants.EMAIL && currentStep === 'createTemplateContent') ||
1268
1315
  ([constants.SMS, constants.WECHAT].includes(channel) && currentStep === 'modeSelection'))) {
1269
1316
  showFooter = showFooter && !this.state.isLoadingContent;
1270
- } else if (slidBoxContent === "editTemplate" &&
1271
- ([constants.SMS, constants.WECHAT, constants.EMAIL].includes(channel) &&
1272
- currentStep === 'modeSelection')) {
1317
+ } else if (slidBoxContent === "editTemplate"
1318
+ && ([constants.SMS, constants.WECHAT, constants.EMAIL].includes(channel)
1319
+ && currentStep === 'modeSelection')) {
1273
1320
  showFooter = showFooter && !this.state.isLoadingContent;
1274
1321
  }
1275
1322
  }
@@ -1278,6 +1325,8 @@ export class Creatives extends React.Component {
1278
1325
  if ([constants.LINE, constants.VIBER, constants.FACEBOOK].includes(channel) || isLineViberChannel) {
1279
1326
  showFooter = false;
1280
1327
  }
1328
+
1329
+
1281
1330
  return showFooter;
1282
1331
  }
1283
1332
 
@@ -1290,13 +1339,21 @@ export class Creatives extends React.Component {
1290
1339
  let showDone = false;
1291
1340
  const channelName = !isFullMode && templateData ? templateData.type : currentChannel;
1292
1341
  const channel = channelName?.toUpperCase();
1342
+
1343
+
1293
1344
  if (channel === constants.EMAIL || channel === constants.SMS) {
1294
1345
  const isEmailCreate = slidBoxContent === 'createTemplate' && channel === constants.EMAIL && currentStep !== 'createTemplateContent';
1295
1346
  showDone = (slidBoxContent === 'editTemplate' || slidBoxContent === 'createTemplate') && !isEmailCreate;
1296
1347
  } else if ([constants.WECHAT, constants.MOBILE_PUSH].includes(channel)) {
1297
1348
  showDone = currentStep === "createTemplateContent" || slidBoxContent === "editTemplate";
1349
+
1350
+ // Additional condition for MobilePush edit in full mode
1351
+ if (channel === constants.MOBILE_PUSH && slidBoxContent === "editTemplate" && isFullMode) {
1352
+ showDone = true;
1353
+ }
1298
1354
  }
1299
1355
 
1356
+
1300
1357
  return showDone;
1301
1358
  }
1302
1359
 
@@ -1356,7 +1413,9 @@ export class Creatives extends React.Component {
1356
1413
  }
1357
1414
 
1358
1415
  shouldShowContinueFooter = () => { // only for email for now, has to be modified according to channel
1359
- const { slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppCreateMode, weChatTemplateType } = this.state;
1416
+ const {
1417
+ slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppCreateMode, weChatTemplateType,
1418
+ } = this.state;
1360
1419
  let isShowContinueFooter = false;
1361
1420
  const currentStep = this.creativesTemplateSteps[templateStep];
1362
1421
  const channel = currentChannel.toUpperCase();
@@ -1439,17 +1498,16 @@ export class Creatives extends React.Component {
1439
1498
  loyaltyMetaData = {},
1440
1499
  } = this.props;
1441
1500
  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;
1501
+ slidBoxContent === "createTemplate"
1502
+ && weChatTemplateType === MAP_TEMPLATE
1503
+ && templateStep !== "modeSelection";
1504
+ const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
1505
+ ? CAP_SPACE_64
1506
+ : get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
1507
+ ? CAP_SPACE_56
1508
+ : get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
1509
+ ? CAP_SPACE_32
1510
+ : 0;
1453
1511
  /* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
1454
1512
  return (
1455
1513
  <SlideBoxWrapper slideBoxWrapperMargin={slideBoxWrapperMargin} className={classnames(`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`)}>
@@ -1577,7 +1635,6 @@ export class Creatives extends React.Component {
1577
1635
  ) : isLiquidValidationError && (
1578
1636
  <CapRow className="template-footer-width">
1579
1637
  {(() => {
1580
-
1581
1638
  const errorsToShow = get(liquidErrorMessage, constants.LIQUID_ERROR_MSG, []);
1582
1639
  const standardErrorsToShow = get(liquidErrorMessage, constants.STANDARD_ERROR_MSG, []);
1583
1640
  return <ErrorInfoNote currentTab={activeFormBuilderTab?.toUpperCase()} errorMessages={{LIQUID_ERROR_MSG: errorsToShow, STANDARD_ERROR_MSG: standardErrorsToShow}} />;
@@ -1647,7 +1704,7 @@ function mapDispatchToProps(dispatch) {
1647
1704
  const withConnect = connect(mapStatesToProps, mapDispatchToProps);
1648
1705
  const withReducer = injectReducer({ key: 'creativesContainer', reducer: creativesContainerReducer });
1649
1706
  const withSaga = injectSaga({ key: 'cap', saga: capSagaForFetchSchemaForEntity });
1650
- const withLiquidSaga = injectSaga({ key: 'liquid', saga: capSagaLiquidEntity , mode: DAEMON });
1707
+ const withLiquidSaga = injectSaga({ key: 'liquid', saga: capSagaLiquidEntity, mode: DAEMON });
1651
1708
  const withDefaultTempSaga = injectSaga({ key: 'creativesContainer', saga: v2TemplateSagaWatchGetDefaultBeeTemplates });
1652
1709
 
1653
- export default compose(withSaga,withLiquidSaga, withDefaultTempSaga, withReducer, withConnect)(injectIntl(Creatives));
1710
+ export default compose(withSaga, withLiquidSaga, withDefaultTempSaga, withReducer, withConnect)(injectIntl(Creatives));
@@ -640,17 +640,6 @@ exports[`Test SlideBoxContent container Should render correct component for rcs
640
640
  <Connect(UserIsAuthenticated(Connect(InjectIntl(withStyles__StyledComponent))))
641
641
  FTPMode="create"
642
642
  channel="rcs"
643
- location={
644
- Object {
645
- "pathname": "/sms/edit",
646
- "query": Object {
647
- "isEditFromCampaigns": undefined,
648
- "module": "library",
649
- "type": "embedded",
650
- },
651
- "search": "",
652
- }
653
- }
654
643
  loyaltyMetaData={Object {}}
655
644
  messageDetails={Object {}}
656
645
  onCreateComplete={[MockFunction]}
@@ -1032,17 +1021,6 @@ exports[`Test SlideBoxContent container Should render correct component for what
1032
1021
  <Connect(UserIsAuthenticated(Connect(InjectIntl(withStyles__StyledComponent))))
1033
1022
  FTPMode="create"
1034
1023
  channel="whatsapp"
1035
- location={
1036
- Object {
1037
- "pathname": "/sms/edit",
1038
- "query": Object {
1039
- "isEditFromCampaigns": undefined,
1040
- "module": "library",
1041
- "type": "embedded",
1042
- },
1043
- "search": "",
1044
- }
1045
- }
1046
1024
  loyaltyMetaData={Object {}}
1047
1025
  messageDetails={Object {}}
1048
1026
  onCreateComplete={[MockFunction]}
@@ -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,