@capillarytech/creatives-library 8.0.125-alpha.6 → 8.0.126

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 (105) hide show
  1. package/config/app.js +6 -0
  2. package/containers/App/constants.js +0 -1
  3. package/containers/Email/index.js +5 -5
  4. package/containers/WeChat/RichmediaTemplates/Create/index.js +1 -1
  5. package/initialReducer.js +2 -0
  6. package/package.json +1 -1
  7. package/services/api.js +94 -1
  8. package/services/tests/api.test.js +191 -0
  9. package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +3 -8
  10. package/tests/integration/TemplateCreation/api-response.js +0 -5
  11. package/tests/integration/TemplateCreation/msw-handler.js +63 -42
  12. package/utils/common.js +0 -7
  13. package/utils/commonUtils.js +6 -2
  14. package/v2Components/CapImageUpload/index.js +45 -51
  15. package/v2Components/CapInAppCTA/index.js +0 -1
  16. package/v2Components/CapTagList/index.js +120 -177
  17. package/v2Components/CapVideoUpload/constants.js +0 -3
  18. package/v2Components/CapVideoUpload/index.js +110 -167
  19. package/v2Components/CapVideoUpload/messages.js +0 -16
  20. package/v2Components/Carousel/index.js +13 -15
  21. package/v2Components/CustomerSearchSection/_customerSearch.scss +309 -0
  22. package/v2Components/CustomerSearchSection/constants.js +5 -0
  23. package/v2Components/CustomerSearchSection/index.js +362 -0
  24. package/v2Components/CustomerSearchSection/messages.js +20 -0
  25. package/v2Components/CustomerSearchSection/tests/utils.test.js +334 -0
  26. package/v2Components/CustomerSearchSection/utils.js +49 -0
  27. package/v2Components/ErrorInfoNote/style.scss +0 -1
  28. package/v2Components/MobilePushPreviewV2/index.js +5 -37
  29. package/v2Components/TemplatePreview/_templatePreview.scss +72 -114
  30. package/v2Components/TemplatePreview/index.js +50 -178
  31. package/v2Components/TemplatePreview/messages.js +0 -4
  32. package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +543 -0
  33. package/v2Components/TestAndPreviewSlidebox/actions.js +67 -0
  34. package/v2Components/TestAndPreviewSlidebox/constants.js +67 -0
  35. package/v2Components/TestAndPreviewSlidebox/index.js +771 -0
  36. package/v2Components/TestAndPreviewSlidebox/messages.js +147 -0
  37. package/v2Components/TestAndPreviewSlidebox/reducer.js +233 -0
  38. package/v2Components/TestAndPreviewSlidebox/sagas.js +258 -0
  39. package/v2Components/TestAndPreviewSlidebox/selectors.js +142 -0
  40. package/v2Components/TestAndPreviewSlidebox/tests/actions.test.js +80 -0
  41. package/v2Components/TestAndPreviewSlidebox/tests/reducer.test.js +367 -0
  42. package/v2Components/TestAndPreviewSlidebox/tests/saga.rtl.test.js +192 -0
  43. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +652 -0
  44. package/v2Components/TestAndPreviewSlidebox/tests/selector.test.js +182 -0
  45. package/v2Containers/CreativesContainer/SlideBoxContent.js +21 -9
  46. package/v2Containers/CreativesContainer/SlideBoxFooter.js +23 -2
  47. package/v2Containers/CreativesContainer/index.js +160 -195
  48. package/v2Containers/CreativesContainer/messages.js +4 -0
  49. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +21 -0
  50. package/v2Containers/Email/index.js +18 -6
  51. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +10 -0
  52. package/v2Containers/EmailWrapper/index.js +6 -0
  53. package/v2Containers/InApp/constants.js +0 -1
  54. package/v2Containers/InApp/index.js +13 -13
  55. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +3 -0
  56. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +2 -0
  57. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +2 -0
  58. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +9 -0
  59. package/v2Containers/MobilePush/Create/index.js +0 -1
  60. package/v2Containers/MobilePush/commonMethods.js +14 -7
  61. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +23 -5
  62. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4 -0
  63. package/v2Containers/TagList/index.js +10 -56
  64. package/v2Containers/Templates/_templates.scss +1 -101
  65. package/v2Containers/Templates/index.js +35 -147
  66. package/v2Containers/Templates/messages.js +0 -8
  67. package/v2Containers/Templates/sagas.js +0 -2
  68. package/v2Containers/WeChat/RichmediaTemplates/Create/index.js +1 -1
  69. package/v2Containers/Whatsapp/constants.js +0 -1
  70. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +35 -0
  71. package/utils/createPayload.js +0 -270
  72. package/utils/tests/createPayload.test.js +0 -761
  73. package/v2Components/CapMpushCTA/constants.js +0 -25
  74. package/v2Components/CapMpushCTA/index.js +0 -332
  75. package/v2Components/CapMpushCTA/index.scss +0 -95
  76. package/v2Components/CapMpushCTA/messages.js +0 -89
  77. package/v2Components/TemplatePreview/assets/images/Android _ With date and time.svg +0 -29
  78. package/v2Components/TemplatePreview/assets/images/android.svg +0 -9
  79. package/v2Components/TemplatePreview/assets/images/iOS _ With date and time.svg +0 -26
  80. package/v2Components/TemplatePreview/assets/images/ios.svg +0 -9
  81. package/v2Containers/Email/tests/index.test.js +0 -35
  82. package/v2Containers/MobilePushNew/actions.js +0 -116
  83. package/v2Containers/MobilePushNew/components/CtaButtons.js +0 -170
  84. package/v2Containers/MobilePushNew/components/MediaUploaders.js +0 -686
  85. package/v2Containers/MobilePushNew/components/PlatformContentFields.js +0 -279
  86. package/v2Containers/MobilePushNew/components/index.js +0 -5
  87. package/v2Containers/MobilePushNew/components/tests/CtaButtons.test.js +0 -779
  88. package/v2Containers/MobilePushNew/components/tests/MediaUploaders.test.js +0 -2114
  89. package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +0 -343
  90. package/v2Containers/MobilePushNew/constants.js +0 -115
  91. package/v2Containers/MobilePushNew/hooks/tests/usePlatformSync.test.js +0 -1299
  92. package/v2Containers/MobilePushNew/hooks/tests/useUpload.test.js +0 -1223
  93. package/v2Containers/MobilePushNew/hooks/usePlatformSync.js +0 -246
  94. package/v2Containers/MobilePushNew/hooks/useUpload.js +0 -709
  95. package/v2Containers/MobilePushNew/index.js +0 -2170
  96. package/v2Containers/MobilePushNew/index.scss +0 -308
  97. package/v2Containers/MobilePushNew/messages.js +0 -226
  98. package/v2Containers/MobilePushNew/reducer.js +0 -160
  99. package/v2Containers/MobilePushNew/sagas.js +0 -198
  100. package/v2Containers/MobilePushNew/selectors.js +0 -55
  101. package/v2Containers/MobilePushNew/tests/reducer.test.js +0 -741
  102. package/v2Containers/MobilePushNew/tests/sagas.test.js +0 -863
  103. package/v2Containers/MobilePushNew/tests/selectors.test.js +0 -425
  104. package/v2Containers/MobilePushNew/tests/utils.test.js +0 -322
  105. package/v2Containers/MobilePushNew/utils.js +0 -33
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { CAP_SPACE_32, CAP_SPACE_56, CAP_SPACE_64 } from '@capillarytech/cap-ui-library/styled/variables';
4
-
3
+ import Bugsnag from "@bugsnag/js";
5
4
  import CapSlideBox from '@capillarytech/cap-ui-library/CapSlideBox';
6
5
  import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
7
6
  import CapRow from '@capillarytech/cap-ui-library/CapRow';
@@ -15,15 +14,18 @@ import {
15
14
  } from 'lodash';
16
15
  import { connect } from 'react-redux';
17
16
  import { createStructuredSelector } from 'reselect';
18
- import { bindActionCreators, compose } from 'redux';
17
+ import { bindActionCreators } from 'redux';
19
18
  import styled from 'styled-components';
20
19
  import { GA } from '@capillarytech/cap-ui-utils';
21
- import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
22
20
 
23
21
  import * as actions from './actions';
24
22
  import {
25
23
  selectEmailLayout, uploadSelector, templateUserList, makeSelectTemplates,
26
24
  } from '../Templates/selectors';
25
+ import SlideBoxContent from './SlideBoxContent';
26
+ import SlideBoxHeader from './SlideBoxHeader';
27
+ import SlideBoxFooter from './SlideBoxFooter';
28
+ import TestAndPreviewSlidebox from '../../v2Components/TestAndPreviewSlidebox';
27
29
  import * as constants from './constants';
28
30
  import * as commonUtil from '../../utils/common';
29
31
  import { gtmPush } from '../../utils/gtmTrackers';
@@ -42,19 +44,20 @@ import {
42
44
  import { IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
43
45
  import { CREATIVE } from '../Facebook/constants';
44
46
  import { LOYALTY } from '../App/constants';
45
- import {
46
- WHATSAPP_STATUSES, WHATSAPP_MEDIA_TYPES, PHONE_NUMBER, URL,
47
- } from '../Whatsapp/constants';
48
- import SlideBoxHeader from './SlideBoxHeader';
49
- import SlideBoxFooter from './SlideBoxFooter';
50
- import SlideBoxContent from './SlideBoxContent';
51
- import { updateImagesInHtml } from '../../utils/cdnTransformation';
47
+ import { WHATSAPP_STATUSES, WHATSAPP_MEDIA_TYPES, PHONE_NUMBER, URL } from '../Whatsapp/constants';
52
48
 
49
+ import { updateImagesInHtml } from '../../utils/cdnTransformation';
50
+ import { IOS } from '../InApp/constants';
53
51
  import injectReducer from '../../utils/injectReducer';
54
52
  import injectSaga from '../../utils/injectSaga';
55
53
  import creativesContainerReducer from './reducer';
56
- import { capSagaForFetchSchemaForEntity, capSagaLiquidEntity } from '../Cap/sagas';
54
+ import { compose } from 'redux';
55
+ import { capSagaForFetchSchemaForEntity,capSagaLiquidEntity } from '../Cap/sagas';
57
56
  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';
58
61
  import { DYNAMIC_URL } from '../../v2Components/CapWhatsappCTA/constants';
59
62
  import ErrorInfoNote from '../../v2Components/ErrorInfoNote';
60
63
 
@@ -80,14 +83,11 @@ const SlideBoxWrapper = styled.div`
80
83
  export class Creatives extends React.Component {
81
84
  constructor(props) {
82
85
  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: initialSlidBoxContent,
90
+ slidBoxContent: this.getSlideBoxContent({ mode: props.creativesMode, templateData: props.templateData, isFullMode: props.isFullMode }),
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',
@@ -100,6 +100,8 @@ export class Creatives extends React.Component {
100
100
  LIQUID_ERROR_MSG: [],
101
101
  },
102
102
  activeFormBuilderTab: constants.ANDROID,
103
+ // NEW: Test and Preview feature state
104
+ showTestAndPreviewSlidebox: false,
103
105
  };
104
106
  this.liquidFlow = Boolean(commonUtil.hasLiquidSupportFeature());
105
107
  this.creativesTemplateSteps = {
@@ -152,26 +154,28 @@ export class Creatives extends React.Component {
152
154
  const userId = parseInt(template.updatedBy, 10);
153
155
  templateData.updatedByName = commonUtil.getUserNameById(userId, usersList);
154
156
  this.setState({ slidBoxContent: constants.PREVIEW, templateData });
155
- } else if (get(template, 'versions.base.content.zalo.previewUrl')) {
156
- commonUtil.handlePreviewInNewTab(
157
- template.versions.base.content.zalo.previewUrl
158
- );
159
157
  } else {
160
- const {
161
- name = "",
162
- sourceAccountIdentifier = "",
163
- configs: { token = "" } = {},
164
- hostName = "",
165
- } = get(this.props, "Templates.selectedZaloAccount", {});
166
- this.props.zaloActions.getTemplateInfoById({
167
- username: name,
168
- oa_id: sourceAccountIdentifier,
169
- token,
170
- host: hostName || this.props?.hostName || this.props.Templates?.senderDetails?.hostName,
171
- id: template?._id,
172
- preview: true,
173
- actionCallback: this.actionCallback,
174
- });
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
+ }
175
179
  }
176
180
  };
177
181
 
@@ -240,40 +244,38 @@ export class Creatives extends React.Component {
240
244
  this.setState({ isGetFormData: false });
241
245
  };
242
246
 
243
- mapCarouselDataToCreatives = (cards) => cards.map((card) => {
244
- const {
245
- cardVarMapped, bodyTemplate, media, buttons, mediaType,
246
- } = card || {};
247
- const buttonData = buttons?.map((button) => {
248
- const {
249
- type, text, phoneNumber, url, dynamicUrlPayload,
250
- } = button || {};
251
- const buttonObj = { type, text };
252
- if (type === PHONE_NUMBER) {
253
- buttonObj.phone_number = phoneNumber;
254
- }
255
- if (type === URL) {
256
- buttonObj.url = url;
257
- if (dynamicUrlPayload) {
258
- buttonObj.urlType = DYNAMIC_URL;
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;
259
255
  }
260
- }
261
- return buttonObj;
256
+ if (type === URL) {
257
+ buttonObj.url = url;
258
+ if (dynamicUrlPayload) {
259
+ buttonObj.urlType = DYNAMIC_URL;
260
+ }
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
277
  });
263
- return {
264
- bodyText: bodyTemplate,
265
- varMap: cardVarMapped,
266
- ...(mediaType === IMAGE && {
267
- imageUrl: media?.url,
268
- }),
269
- ...(mediaType === VIDEO && {
270
- videoUrl: media?.url,
271
- videoPreviewImg: media?.previewUrl,
272
- }),
273
- buttons: buttonData,
274
- mediaType: mediaType?.toLowerCase(),
275
- };
276
- })
278
+ }
277
279
 
278
280
  getTemplateData = (templateData) => { //from consumers to creatives
279
281
  const { isFullMode, messageDetails = {}, smsRegister } = this.props;
@@ -353,33 +355,13 @@ export class Creatives extends React.Component {
353
355
  }
354
356
  case constants.MOBILE_PUSH: {
355
357
  const mode = get(templateData, 'androidContent.type') || get(templateData, 'iosContent.type') || '';
356
- const androidCarouselMedia = get(templateData, 'androidContent.expandableDetails.media', []);
357
- const iosCarouselMedia = get(templateData, 'iosContent.expandableDetails.media', []);
358
- const androidContent = { ...(templateData?.androidContent || {}) };
359
- const iosContent = { ...(templateData?.iosContent || {}) };
360
- if (androidCarouselMedia?.length) {
361
- androidContent.expandableDetails.carouselData = androidCarouselMedia.map((media) => ({
362
- mediaType: media.type,
363
- imageUrl: media.url,
364
- buttons: [],
365
- videoSrc: '',
366
- }));
367
- }
368
- if (iosCarouselMedia?.length) {
369
- iosContent.expandableDetails.carouselData = iosCarouselMedia.map((media) => ({
370
- mediaType: media.type,
371
- imageUrl: media.url,
372
- buttons: [],
373
- videoSrc: '',
374
- }));
375
- }
376
358
  creativesTemplateData = {
377
359
  type: channel,
378
360
  name: templateData.messageSubject,
379
361
  versions: {
380
362
  base: {
381
- ANDROID: androidContent,
382
- IOS: iosContent,
363
+ ANDROID: templateData.androidContent,
364
+ IOS: templateData.iosContent,
383
365
  },
384
366
  },
385
367
  definition: { accountId: templateData.accountId, mode: mode.toLowerCase() },
@@ -541,9 +523,7 @@ export class Creatives extends React.Component {
541
523
  } = {},
542
524
  } = templateData;
543
525
  const mediaParams = {};
544
- const {
545
- url = '', previewUrl = '', docParams = {}, footer = '', headerVarMapped = {}, headerTemplate = '',
546
- } = whatsappMedia || {};
526
+ const { url = '', previewUrl = '', docParams = {}, footer = '', headerVarMapped = {}, headerTemplate = '' } = whatsappMedia || {};
547
527
  switch (mediaType) {
548
528
  case (WHATSAPP_MEDIA_TYPES.IMAGE):
549
529
  mediaParams.imageUrl = url;
@@ -563,7 +543,7 @@ export class Creatives extends React.Component {
563
543
  break;
564
544
  }
565
545
  const modifiedButtons = cloneDeep(buttons)?.map((btn) => {
566
- if (btn.type === PHONE_NUMBER) {
546
+ if (btn.type === 'PHONE_NUMBER') {
567
547
  btn.phone_number = btn.phoneNumber;
568
548
  delete btn.phoneNumber;
569
549
  return btn;
@@ -656,61 +636,46 @@ export class Creatives extends React.Component {
656
636
  return templateData || null;
657
637
  }
658
638
 
659
- getCarouselMappedData = (carouselData = []) => carouselData.map((carousel) => {
660
- const {
661
- bodyText, imageUrl, videoUrl, videoPreviewImg, buttons, mediaType, cardVarMapped, bodyTemplate,
662
- } = carousel || {};
663
- const buttonData = buttons.map((button, index) => {
664
- const {
665
- type, text, phone_number, urlType, url,
666
- } = button || {};
667
- const buttonObj = {
668
- type,
669
- text,
670
- index,
671
- };
672
- if (type === PHONE_NUMBER) {
673
- buttonObj.phoneNumber = phone_number;
674
- }
675
- if (type === URL) {
676
- buttonObj.url = url;
677
- if (urlType === DYNAMIC_URL) {
678
- const dynamicUrlPayload = url?.match(/{{(.*?)}}/g);
679
- buttonObj.dynamicUrlPayload = dynamicUrlPayload?.length === 1 ? dynamicUrlPayload[0] : '';
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;
680
651
  }
681
- }
682
- return buttonObj;
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(),
676
+ };
683
677
  });
684
- return {
685
- body: bodyText,
686
- cardVarMapped,
687
- bodyTemplate,
688
- media: {
689
- ...(mediaType?.toLowerCase() === IMAGE.toLowerCase() && {
690
- url: imageUrl,
691
- }),
692
- ...(mediaType?.toLowerCase() === VIDEO.toLowerCase() && {
693
- url: videoUrl,
694
- previewUrl: videoPreviewImg,
695
- }),
696
- },
697
- buttons: buttonData,
698
- mediaType: mediaType?.toUpperCase(),
699
- };
700
- });
701
-
702
- getMobilePushCarouselData = (expandableDetails = []) => {
703
- const newExpandableDetails = {...expandableDetails};
704
- newExpandableDetails.style = expandableDetails.style || 'MANUAL_CAROUSEL';
705
- newExpandableDetails.message = expandableDetails.message || '';
706
- newExpandableDetails.ctas = expandableDetails.ctas || [];
707
- newExpandableDetails.media = expandableDetails.carouselData.map((carousel) => ({
708
- url: carousel.imageUrl,
709
- type: carousel?.mediaType?.toUpperCase(),
710
- text: '',
711
- }));
712
- return newExpandableDetails;
713
- }
678
+ };
714
679
 
715
680
  getCreativesData = async (channel, template, templateRecords) => { //from creatives to consumers
716
681
  let templateData = { channel };
@@ -794,9 +759,6 @@ export class Creatives extends React.Component {
794
759
  if (channel !== constants.MOBILE_PUSH) {
795
760
  androidContent.custom = custom;
796
761
  }
797
- if (channel === constants.MOBILE_PUSH && androidContent?.expandableDetails?.carouselData?.length) {
798
- androidContent.expandableDetails = this.getMobilePushCarouselData({...androidContent?.expandableDetails});
799
- }
800
762
  templateData.androidContent = androidContent;
801
763
  templateData.androidContent.type = get(channelTemplate, 'definition.mode', '').toUpperCase();
802
764
  templateData.androidContent.deviceType = constants.ANDROID;
@@ -816,9 +778,6 @@ export class Creatives extends React.Component {
816
778
  if (channel !== constants.MOBILE_PUSH) {
817
779
  iosContent.custom = custom;
818
780
  }
819
- if (channel === constants.MOBILE_PUSH && iosContent?.expandableDetails?.carouselData?.length) {
820
- iosContent.expandableDetails = this.getMobilePushCarouselData({...iosContent?.expandableDetails});
821
- }
822
781
  templateData.iosContent = iosContent;
823
782
  templateData.iosContent.type = get(channelTemplate, 'definition.mode').toUpperCase();
824
783
  templateData.iosContent.deviceType = constants.IOS;
@@ -988,7 +947,7 @@ export class Creatives extends React.Component {
988
947
  fBContent.forEach((obj) => {
989
948
  const data = cloneDeep(obj);
990
949
  const {
991
- subType, linkDesc, imgSrc, webSiteLink, video,
950
+ subType, linkDesc, imgSrc, webSiteLink, video
992
951
  } = obj;
993
952
  delete data.type;
994
953
  delete data.linkDesc;
@@ -1026,7 +985,7 @@ export class Creatives extends React.Component {
1026
985
  break;
1027
986
  case constants.RCS: {
1028
987
  if (template.value) {
1029
- const { name = "", versions = {} } = {
988
+ const { name = "", versions = {}, type = "" } = {
1030
989
  } = template.value || {};
1031
990
  const {
1032
991
  cardContent = [],
@@ -1154,6 +1113,7 @@ export class Creatives extends React.Component {
1154
1113
  }
1155
1114
 
1156
1115
  getFormData = (template) => {
1116
+
1157
1117
  if (template.validity) {
1158
1118
  this.setState(
1159
1119
  {
@@ -1171,7 +1131,7 @@ export class Creatives extends React.Component {
1171
1131
  );
1172
1132
  }
1173
1133
  }
1174
-
1134
+
1175
1135
  processCentralCommsMetaId = (channel, creativesData) => {
1176
1136
  // Create the payload for the centralcommnsmetaId API call
1177
1137
  const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
@@ -1250,18 +1210,25 @@ export class Creatives extends React.Component {
1250
1210
  this.setState({ isDiscardMessage: true });
1251
1211
  }
1252
1212
 
1213
+ // NEW: Handler for Test and Preview button
1214
+ handleTestAndPreview = () => {
1215
+ this.setState({ showTestAndPreviewSlidebox: true });
1216
+ }
1217
+
1218
+ // NEW: Handler to close Test and Preview slidebox
1219
+ handleCloseTestAndPreview = () => {
1220
+ this.setState({ showTestAndPreviewSlidebox: false });
1221
+ }
1222
+
1253
1223
  shouldShowFooter = () => {
1254
1224
  const { isFullMode } = this.props;
1255
- const {
1256
- slidBoxContent, currentChannel, emailCreateMode, templateNameExists, templateStep, mobilePushCreateMode, weChatTemplateType, templateData,
1257
- } = this.state;
1225
+ const { slidBoxContent, currentChannel, emailCreateMode, templateNameExists, templateStep, mobilePushCreateMode, inAppCreateMode, weChatTemplateType, templateData } = this.state;
1258
1226
  const channel = currentChannel.toUpperCase();
1259
1227
  const currentStep = this.creativesTemplateSteps[templateStep];
1260
1228
  let showFooter = false;
1261
1229
  showFooter = isFullMode && slidBoxContent === "preview";
1262
1230
  const isMobilepush = channel === constants.MOBILE_PUSH;
1263
-
1264
-
1231
+ const isInApp = channel === constants.INAPP;
1265
1232
  if (!isFullMode) {
1266
1233
  const isEmailCreate = slidBoxContent === 'createTemplate' && channel === constants.EMAIL && currentStep !== 'createTemplateContent';
1267
1234
  const isCreate = (slidBoxContent === 'editTemplate' || slidBoxContent === 'createTemplate') && !isEmailCreate;
@@ -1283,15 +1250,15 @@ export class Creatives extends React.Component {
1283
1250
  if (slidBoxContent === "editTemplate" && ((channel === constants.EMAIL && currentStep === 'modeSelection'))) {
1284
1251
  showFooter = true;
1285
1252
  }
1286
- if (channel === constants.MOBILE_PUSH
1287
- && ((slidBoxContent === 'createTemplate' && !isEmpty(mobilePushCreateMode))
1288
- || (slidBoxContent === 'editTemplate' && (currentStep === 'modeSelection' || isFullMode))) &&
1253
+ if (channel === constants.MOBILE_PUSH &&
1254
+ ((slidBoxContent === 'createTemplate' && !isEmpty(mobilePushCreateMode))
1255
+ || (slidBoxContent === 'editTemplate' && currentStep === 'modeSelection')) &&
1289
1256
  templateNameExists) {
1290
1257
  showFooter = true;
1291
1258
  }
1292
1259
 
1293
- if (channel === constants.WECHAT
1294
- && ((slidBoxContent === 'createTemplate' && !isEmpty(weChatTemplateType))
1260
+ if (channel === constants.WECHAT &&
1261
+ ((slidBoxContent === 'createTemplate' && !isEmpty(weChatTemplateType))
1295
1262
  || (slidBoxContent === 'editTemplate' && currentStep === 'modeSelection'))) {
1296
1263
  showFooter = true;
1297
1264
  }
@@ -1300,9 +1267,9 @@ export class Creatives extends React.Component {
1300
1267
  if (slidBoxContent === "createTemplate" && ((channel === constants.EMAIL && currentStep === 'createTemplateContent') ||
1301
1268
  ([constants.SMS, constants.WECHAT].includes(channel) && currentStep === 'modeSelection'))) {
1302
1269
  showFooter = showFooter && !this.state.isLoadingContent;
1303
- } else if (slidBoxContent === "editTemplate"
1304
- && ([constants.SMS, constants.WECHAT, constants.EMAIL].includes(channel)
1305
- && currentStep === 'modeSelection')) {
1270
+ } else if (slidBoxContent === "editTemplate" &&
1271
+ ([constants.SMS, constants.WECHAT, constants.EMAIL].includes(channel) &&
1272
+ currentStep === 'modeSelection')) {
1306
1273
  showFooter = showFooter && !this.state.isLoadingContent;
1307
1274
  }
1308
1275
  }
@@ -1311,8 +1278,6 @@ export class Creatives extends React.Component {
1311
1278
  if ([constants.LINE, constants.VIBER, constants.FACEBOOK].includes(channel) || isLineViberChannel) {
1312
1279
  showFooter = false;
1313
1280
  }
1314
-
1315
-
1316
1281
  return showFooter;
1317
1282
  }
1318
1283
 
@@ -1324,22 +1289,14 @@ export class Creatives extends React.Component {
1324
1289
  const currentStep = this.creativesTemplateSteps[templateStep];
1325
1290
  let showDone = false;
1326
1291
  const channelName = !isFullMode && templateData ? templateData.type : currentChannel;
1327
- const channel = channelName && channelName.toUpperCase();
1328
-
1329
-
1292
+ const channel = channelName?.toUpperCase();
1330
1293
  if (channel === constants.EMAIL || channel === constants.SMS) {
1331
1294
  const isEmailCreate = slidBoxContent === 'createTemplate' && channel === constants.EMAIL && currentStep !== 'createTemplateContent';
1332
1295
  showDone = (slidBoxContent === 'editTemplate' || slidBoxContent === 'createTemplate') && !isEmailCreate;
1333
1296
  } else if ([constants.WECHAT, constants.MOBILE_PUSH].includes(channel)) {
1334
1297
  showDone = currentStep === "createTemplateContent" || slidBoxContent === "editTemplate";
1335
-
1336
- // Additional condition for MobilePush edit in full mode
1337
- if (channel === constants.MOBILE_PUSH && slidBoxContent === "editTemplate" && isFullMode) {
1338
- showDone = true;
1339
- }
1340
1298
  }
1341
1299
 
1342
-
1343
1300
  return showDone;
1344
1301
  }
1345
1302
 
@@ -1399,9 +1356,7 @@ export class Creatives extends React.Component {
1399
1356
  }
1400
1357
 
1401
1358
  shouldShowContinueFooter = () => { // only for email for now, has to be modified according to channel
1402
- const {
1403
- slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppCreateMode, weChatTemplateType,
1404
- } = this.state;
1359
+ const { slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppCreateMode, weChatTemplateType } = this.state;
1405
1360
  let isShowContinueFooter = false;
1406
1361
  const currentStep = this.creativesTemplateSteps[templateStep];
1407
1362
  const channel = currentChannel.toUpperCase();
@@ -1460,6 +1415,7 @@ export class Creatives extends React.Component {
1460
1415
  isLiquidValidationError,
1461
1416
  liquidErrorMessage,
1462
1417
  activeFormBuilderTab,
1418
+ showTestAndPreviewSlidebox,
1463
1419
  } = this.state;
1464
1420
  const {
1465
1421
  isFullMode,
@@ -1483,16 +1439,17 @@ export class Creatives extends React.Component {
1483
1439
  loyaltyMetaData = {},
1484
1440
  } = this.props;
1485
1441
  const mapTemplateCreate =
1486
- slidBoxContent === "createTemplate"
1487
- && weChatTemplateType === MAP_TEMPLATE
1488
- && templateStep !== "modeSelection";
1489
- const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
1490
- ? CAP_SPACE_64
1491
- : get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
1492
- ? CAP_SPACE_56
1493
- : get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
1494
- ? CAP_SPACE_32
1495
- : 0;
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;
1496
1453
  /* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
1497
1454
  return (
1498
1455
  <SlideBoxWrapper slideBoxWrapperMargin={slideBoxWrapperMargin} className={classnames(`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`)}>
@@ -1587,6 +1544,9 @@ export class Creatives extends React.Component {
1587
1544
  eventContextTags={eventContextTags}
1588
1545
  isLoyaltyModule={isLoyaltyModule}
1589
1546
  loyaltyMetaData={loyaltyMetaData}
1547
+ showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
1548
+ handleTestAndPreview={this.handleTestAndPreview}
1549
+ handleCloseTestAndPreview={this.handleCloseTestAndPreview}
1590
1550
  />
1591
1551
  )}
1592
1552
  footer={this.shouldShowFooter() ? (
@@ -1608,10 +1568,16 @@ export class Creatives extends React.Component {
1608
1568
  isLiquidValidationError={isLiquidValidationError}
1609
1569
  errorMessages={liquidErrorMessage}
1610
1570
  currentTab={activeFormBuilderTab}
1571
+ onTestAndPreview={this.handleTestAndPreview}
1572
+ showTestAndPreviewButton={(() => {
1573
+ const showButton = currentChannel.toUpperCase() === constants.EMAIL && (slidBoxContent === 'editTemplate' || slidBoxContent === 'createTemplate');
1574
+ return showButton;
1575
+ })()}
1611
1576
  />
1612
1577
  ) : isLiquidValidationError && (
1613
1578
  <CapRow className="template-footer-width">
1614
1579
  {(() => {
1580
+
1615
1581
  const errorsToShow = get(liquidErrorMessage, constants.LIQUID_ERROR_MSG, []);
1616
1582
  const standardErrorsToShow = get(liquidErrorMessage, constants.STANDARD_ERROR_MSG, []);
1617
1583
  return <ErrorInfoNote currentTab={activeFormBuilderTab?.toUpperCase()} errorMessages={{LIQUID_ERROR_MSG: errorsToShow, STANDARD_ERROR_MSG: standardErrorsToShow}} />;
@@ -1622,7 +1588,6 @@ export class Creatives extends React.Component {
1622
1588
  show={showSlideBox}
1623
1589
  size="size-xl"
1624
1590
  />
1625
-
1626
1591
  </SlideBoxWrapper>
1627
1592
  );
1628
1593
  }
@@ -1682,7 +1647,7 @@ function mapDispatchToProps(dispatch) {
1682
1647
  const withConnect = connect(mapStatesToProps, mapDispatchToProps);
1683
1648
  const withReducer = injectReducer({ key: 'creativesContainer', reducer: creativesContainerReducer });
1684
1649
  const withSaga = injectSaga({ key: 'cap', saga: capSagaForFetchSchemaForEntity });
1685
- const withLiquidSaga = injectSaga({ key: 'liquid', saga: capSagaLiquidEntity, mode: DAEMON });
1650
+ const withLiquidSaga = injectSaga({ key: 'liquid', saga: capSagaLiquidEntity , mode: DAEMON });
1686
1651
  const withDefaultTempSaga = injectSaga({ key: 'creativesContainer', saga: v2TemplateSagaWatchGetDefaultBeeTemplates });
1687
1652
 
1688
- export default compose(withSaga, withLiquidSaga, withDefaultTempSaga, withReducer, withConnect)(injectIntl(Creatives));
1653
+ export default compose(withSaga,withLiquidSaga, withDefaultTempSaga, withReducer, withConnect)(injectIntl(Creatives));
@@ -362,4 +362,8 @@ export default defineMessages({
362
362
  id: `${scope}.noCommunication`,
363
363
  defaultMessage: `NO_COMMUNICATION`,
364
364
  },
365
+ "testAndPreview": {
366
+ id: `${scope}.testAndPreview`,
367
+ defaultMessage: `Preview and Test`,
368
+ },
365
369
  });