@capillarytech/creatives-library 3.10.0 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/assets/lineImageTemplate.png +0 -0
  2. package/components/TemplatePreview/WechatRichmediaTemplatePreview/index.js +7 -7
  3. package/components/TemplatePreview/_templatePreview.scss +287 -20
  4. package/components/TemplatePreview/assets/images/home-screen-android.svg +21 -0
  5. package/components/TemplatePreview/assets/images/home-screen-ios.svg +16 -0
  6. package/components/TemplatePreview/assets/images/sms_mobile_android.svg +22 -0
  7. package/components/TemplatePreview/assets/images/sms_mobile_ios.svg +16 -0
  8. package/components/TemplatePreview/assets/images/wechat_mobile_android.svg +20 -0
  9. package/components/TemplatePreview/index.js +203 -31
  10. package/components/TemplatePreview/messages.js +21 -0
  11. package/containers/Assets/Gallery/index.js +53 -59
  12. package/containers/Cap/index.js +1 -0
  13. package/index.js +6 -0
  14. package/package.json +1 -1
  15. package/routes.js +5 -0
  16. package/services/getSchema.js +4 -1
  17. package/translations/en.json +40 -4
  18. package/translations/zh.json +39 -3
  19. package/v2Components/FormBuilder/index.js +188 -37
  20. package/v2Components/FormBuilder/messages.js +16 -0
  21. package/v2Components/MobilePushPreviewV2/index.js +44 -36
  22. package/v2Components/MobilePushPreviewV2/messages.js +0 -8
  23. package/v2Components/TemplatePreview/WechatRichmediaTemplatePreview/_wechatRichmediaTemplatePrev.scss +64 -0
  24. package/v2Components/TemplatePreview/WechatRichmediaTemplatePreview/index.js +100 -18
  25. package/v2Components/TemplatePreview/WechatRichmediaTemplatePreview/messages.js +12 -0
  26. package/v2Components/TemplatePreview/_templatePreview.scss +24 -4
  27. package/v2Components/TemplatePreview/assets/images/home-screen-android.svg +21 -0
  28. package/v2Components/TemplatePreview/assets/images/home-screen-ios.svg +16 -0
  29. package/v2Components/TemplatePreview/assets/images/sms_mobile_android.svg +22 -0
  30. package/v2Components/TemplatePreview/assets/images/wechat-home-screen-android.svg +21 -0
  31. package/v2Components/TemplatePreview/assets/images/wechat_mobile_android.svg +20 -0
  32. package/v2Components/TemplatePreview/index.js +162 -23
  33. package/v2Components/TemplatePreview/messages.js +8 -0
  34. package/v2Containers/Assets/Gallery/index.js +54 -48
  35. package/v2Containers/CreativesContainer/SlideBoxContent.js +87 -4
  36. package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -1
  37. package/v2Containers/CreativesContainer/index.js +58 -2
  38. package/v2Containers/CreativesContainer/messages.js +2 -2
  39. package/v2Containers/Email/_email.scss +7 -1
  40. package/v2Containers/Email/index.js +40 -14
  41. package/v2Containers/Email/messages.js +4 -0
  42. package/v2Containers/Email/reducer.js +1 -0
  43. package/v2Containers/EmailWrapper/index.js +7 -5
  44. package/v2Containers/Line/Create/_lineCreate.scss +40 -19
  45. package/v2Containers/Line/Create/actions.js +13 -9
  46. package/v2Containers/Line/Create/index.js +498 -237
  47. package/v2Containers/Line/Create/initialSchema.js +378 -0
  48. package/v2Containers/Line/Create/messages.js +42 -2
  49. package/v2Containers/Line/Create/sagas.js +10 -4
  50. package/v2Containers/Line/Create/selectors.js +3 -9
  51. package/v2Containers/Line/CreateWrapper/constants.js +2 -0
  52. package/v2Containers/Line/CreateWrapper/index.js +117 -0
  53. package/v2Containers/Line/CreateWrapper/messages.js +55 -0
  54. package/v2Containers/MobilePush/Create/index.js +5 -0
  55. package/v2Containers/MobilePush/Edit/index.js +5 -0
  56. package/v2Containers/MobilepushWrapper/index.js +4 -1
  57. package/v2Containers/Sms/Create/index.js +2 -1
  58. package/v2Containers/Sms/Edit/index.js +2 -0
  59. package/v2Containers/Templates/_templates.scss +24 -1
  60. package/v2Containers/Templates/actions.js +7 -0
  61. package/v2Containers/Templates/constants.js +2 -0
  62. package/v2Containers/Templates/index.js +118 -15
  63. package/v2Containers/Templates/messages.js +8 -0
  64. package/v2Containers/Templates/reducer.js +2 -0
  65. package/v2Containers/TemplatesV2/index.js +5 -4
  66. package/v2Containers/TemplatesV2/messages.js +4 -0
@@ -11,9 +11,10 @@ import PropTypes from 'prop-types';
11
11
  import React from 'react';
12
12
  import _ from 'lodash';
13
13
  import { Tabs, Table, Modal} from 'antd';
14
- import { CapButton, CapInput, CapPopover, CapCheckbox, CapRadio, CapSelect, CapTable, CapRow, CapColumn, CapNotification, CapUploader, CapHeading, CapIcon} from '@capillarytech/cap-ui-library';
14
+ import { CapDrawer, CapButton, CapInput, CapPopover, CapImage, CapCheckbox, CapRadio, CapSelect, CapTable, CapRow, CapColumn, CapNotification, CapUploader, CapHeading, CapIcon} from '@capillarytech/cap-ui-library';
15
15
  import { injectIntl, intlShape, FormattedMessage } from 'react-intl';
16
16
  import LabelHOC from '@capillarytech/cap-ui-library/assets/HOCs/ComponentWithLabelHOC';
17
+ import { CAP_SPACE_12, CAP_SPACE_08, FONT_COLOR_05, FONT_COLOR_04 } from '@capillarytech/cap-ui-library/styled/variables';
17
18
  import TemplatePreview from '../TemplatePreview';
18
19
  import TagList from '../../v2Containers/TagList';
19
20
  import SlideBox from '../SlideBox';
@@ -24,7 +25,7 @@ import CustomPopOver from '../CustomPopOver';
24
25
  import messages from './messages';
25
26
  import './_formBuilder.scss';
26
27
  import {updateCharCount, checkUnicode} from "../../utils/smsCharCountV2";
27
- import {SMS} from '../../v2Containers/CreativesContainer/constants';
28
+ import { SMS, LINE } from '../../v2Containers/CreativesContainer/constants';
28
29
  const TabPane = Tabs.TabPane;
29
30
  const {Column} = Table;
30
31
  const {TextArea} = CapInput;
@@ -55,6 +56,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
55
56
  currentEventData: {},
56
57
  popoverVisible: false,
57
58
  customPopoverVisible: false,
59
+ isDrawerVisible: false,
58
60
  };
59
61
  this.renderForm = this.renderForm.bind(this);
60
62
  this.updateFormData = this.updateFormData.bind(this);
@@ -207,7 +209,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
207
209
  if (nextProps.isNewVersionFlow && !this.state.formData[this.state.currentTab - 1][this.state.formData[this.state.currentTab - 1].activeTab].tabKey) {
208
210
  this.resetTabKeys(nextProps.formData, nextProps.tabCount, false, true);
209
211
  }
210
- if (type === 'embedded' || this.props.schema.channel.toUpperCase() === 'EMAIL') {
212
+ if (type === 'embedded' || ( this.props.schema.channel && this.props.schema.channel.toUpperCase() === 'EMAIL')) {
211
213
  this.validateForm();
212
214
  }
213
215
  if ((this.props.schema && this.props.schema.channel && this.props.schema.channel.toUpperCase() === 'MOBILEPUSH')) {
@@ -253,6 +255,11 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
253
255
  if (nextProps.modal && (!_.isEqual(nextProps.modal, this.props.modal) || _.isEmpty(this.state.modal))) {
254
256
  this.setState({modal: nextProps.modal});
255
257
  }
258
+ if (nextProps.isDrawerRequired !== this.props.isDrawerRequired) {
259
+ this.setState({
260
+ isDrawerVisible: nextProps.isDrawerRequired,
261
+ });
262
+ }
256
263
  }
257
264
 
258
265
  onEdit() {
@@ -484,38 +491,74 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
484
491
  }
485
492
 
486
493
  //validation for LINE
487
- if (this.props.schema.channel === 'LINE') {
494
+ if (channel === LINE) {
488
495
 
489
- if (this.state.formData['0']['message-editor'] !== undefined ) {
490
- const content = this.state.formData['0']['message-editor'];
496
+ if (this.state.formData['message-editor'] !== undefined ) {
497
+ const content = this.state.formData['0']['message-editor'] || '';
491
498
 
492
- const tagValidationResponse = this.validateTags(content, tags, injectedTags);
499
+ const tagValidationResponse = this.validateTags((content), tags, injectedTags);
493
500
 
494
501
  if (tagValidationResponse.valid) {
495
- errorData['0']['message-editor'] = false;
502
+ errorData = {
503
+ ...errorData,
504
+ 0: {
505
+ ...errorData[0],
506
+ 'message-editor': false,
507
+ }
508
+ };
496
509
  } else {
497
-
498
- errorData['0']['message-editor'] = true;
510
+ errorData = {
511
+ ...errorData,
512
+ 0: {
513
+ ...errorData[0],
514
+ 'message-editor': true,
515
+ }
516
+ };
499
517
  isValid = false;
500
518
  }
501
519
  if (content.trim() === '') {
502
-
503
- errorData['0']['message-editor'] = true;
520
+ errorData = {
521
+ ...errorData,
522
+ 0: {
523
+ ...errorData[0],
524
+ 'message-editor': true,
525
+ }
526
+ };
504
527
  isValid = false;
505
528
  }
506
529
  }
507
530
 
508
- if ( (this.state.formData['0'].image !== undefined) && (this.state.formData['0'].imagePreview !== undefined)){
509
- const imgContentLength = this.state.formData['0'].image.length;
510
- const imgContentLengthPreview = this.state.formData['0'].imagePreview.length;
531
+ if (this.state.formData['image-upload-line'] !== undefined) {
532
+ const {
533
+ formData: {
534
+ 0: {
535
+ image,
536
+ imagePreview,
537
+ }
538
+ }
539
+ } = this.state;
540
+ const imgContentLength = image ? image.length : 0;
541
+ const imgContentLengthPreview = imagePreview ? imagePreview.length : 0;
511
542
  if ( (imgContentLength < 1) && (imgContentLengthPreview < 1) ) {
512
543
 
513
- errorData['0'].image = true;
514
- errorData['0'].imagePreview = true;
544
+ errorData = {
545
+ ...errorData,
546
+ 0: {
547
+ ...errorData[0],
548
+ image: true,
549
+ imagePreview: true,
550
+ }
551
+ };
515
552
  isValid = false;
516
553
  }else{
517
- errorData['0'].image = false;
518
- errorData['0'].imagePreview = false;
554
+ errorData = {
555
+ ...errorData,
556
+ 0: {
557
+ ...errorData[0],
558
+ image: false,
559
+ imagePreview: false,
560
+ }
561
+ };
519
562
  }
520
563
  }
521
564
  if(type !== 'embedded' && (!this.state.formData['template-name'] || this.state.formData['template-name'] === '')) {
@@ -1149,7 +1192,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1149
1192
  // this.formElements.push(col.id);
1150
1193
  // }
1151
1194
  if (!col.onlyDisplay && !ifError) {
1152
- if (col.id.indexOf('tagList-') === -1) {
1195
+ if (col.id && col.id.indexOf('tagList-') === -1) {
1153
1196
  this.formElements.push(col.id);
1154
1197
  }
1155
1198
 
@@ -1349,7 +1392,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1349
1392
  delete tempFormData[key];
1350
1393
  } else if (typeof element === "object") {
1351
1394
  _.forEach(element, (innerElement, innerKey) => {
1352
- if (innerKey !== "tabKey" && innerKey !== "base" && innerKey !== 'name' && innerKey !== 'imagePreview' && this.formElements.indexOf(innerKey) === -1) {
1395
+ if (innerKey !== "tabKey" && innerKey !== "base" && innerKey !== 'name' && innerKey !== 'imagePreview' && innerKey !== 'image' && this.formElements.indexOf(innerKey) === -1) {
1353
1396
  delete tempFormData[key][innerKey];
1354
1397
  }
1355
1398
  });
@@ -1921,7 +1964,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1921
1964
  return;
1922
1965
  } else if (event === 'markFinalVersion' || event === 'duplicateVersion' || event === 'deleteVersion' || event === 'renameVersion') {
1923
1966
  this.setState({ popoverVisible: false });
1924
- if ((event !== 'deleteVersion' && !this.props.isNewVersionFlow) || ((event === 'deleteVersion') && this.props.schema.channel.toUpperCase() === 'EMAIL')) {
1967
+ if ((event !== 'deleteVersion' && !this.props.isNewVersionFlow) || ((event === 'deleteVersion') && this.props.schema.channel && this.props.schema.channel.toUpperCase() === 'EMAIL')) {
1925
1968
  val.injectedEvents[event].call(this.props.parent, data, this.state.currentTab);
1926
1969
  } else {
1927
1970
  this.setState({currentEvent: val.injectedEvents[event], currentEventData: data});
@@ -2100,8 +2143,8 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2100
2143
  img.src = _URL.createObjectURL(file);
2101
2144
  img.onload = () => {
2102
2145
  const fileParams = {
2103
- width: this.width,
2104
- height: this.height,
2146
+ width: this.width || img.width,
2147
+ height: this.height || img.height,
2105
2148
  error: file.size / (1e+6) > 3,
2106
2149
  };
2107
2150
  this.callChildEvent({file, type: 'image', fileParams}, val, val.submitAction);
@@ -2154,7 +2197,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2154
2197
  //
2155
2198
  const imgSrc = template && template.versions && template.versions.base ? template.versions.base.preview_http_url : '';
2156
2199
  // const ifPreviewGenerated = template && template.versions && template.versions.base ? template.versions.base.isPreviewGenerated : 0;
2157
- const content = <img src={imgSrc || ''} alt="" />;
2200
+ const content = <CapImage src={imgSrc || ''} alt="" />;
2158
2201
 
2159
2202
  temp.content = (
2160
2203
  <div
@@ -2339,8 +2382,10 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2339
2382
  content={content}
2340
2383
  charCounterEnabled={val.charCounterEnabled}
2341
2384
  unicodeEnabled={unicodeEnabled}
2342
- >
2343
- </TemplatePreview>
2385
+ showTestAndPreviewIcon
2386
+ onPreviewContentClicked={this.props.onPreviewContentClicked}
2387
+ onTestContentClicked={this.props.onTestContentClicked}
2388
+ />
2344
2389
  </CapColumn>
2345
2390
  );
2346
2391
  break;
@@ -2532,6 +2577,81 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2532
2577
  }
2533
2578
  }
2534
2579
 
2580
+ onGalleryClick = (event) => {
2581
+ event.stopPropagation();
2582
+ this.props.setDrawerVisibility(true);
2583
+ }
2584
+
2585
+ onReUpload = () => {
2586
+ const { formData } = this.state;
2587
+ this.props.onChange({
2588
+ ...formData,
2589
+ 0: {
2590
+ ...formData[0],
2591
+ image: undefined,
2592
+ imagePreview: undefined,
2593
+ },
2594
+ base: {
2595
+ ...formData.base,
2596
+ image: undefined,
2597
+ imagePreview: undefined,
2598
+ },
2599
+ reUpload: true,
2600
+ });
2601
+ }
2602
+
2603
+ getUploadVariants = (isImage, val) => {
2604
+ if (this.props.schema && this.props.schema.channel === 'LINE') {
2605
+ if (!isImage) {
2606
+ return (
2607
+ <>
2608
+ <CapUploader.CapDragger
2609
+ customRequest={(data) => this.capUploaderCustomRequest(data, val)}
2610
+ {...val.componentProps}
2611
+ className="form-builder-dragger"
2612
+ >
2613
+ <CapHeading className="dragger-title" type="h7">
2614
+ <FormattedMessage {...messages.dragAndDrop} />
2615
+ </CapHeading>
2616
+ <CapHeading className="dragger-or" type="label6">
2617
+ <FormattedMessage {...messages.or} />
2618
+ </CapHeading>
2619
+ <CapButton className="dragger-button" type="secondary" style={{marginRight: CAP_SPACE_08}}>
2620
+ <FormattedMessage {...messages.uploadComputer} />
2621
+ </CapButton>
2622
+ <CapButton
2623
+ className="dragger-button"
2624
+ type="secondary"
2625
+ style={{marginLeft: CAP_SPACE_08}}
2626
+ onClick={this.onGalleryClick}
2627
+ >
2628
+ <FormattedMessage {...messages.uploadGallery} />
2629
+ </CapButton>
2630
+ </CapUploader.CapDragger>
2631
+ <CapHeading type="h6" style={{marginTop: CAP_SPACE_12 }}>
2632
+ <FormattedMessage {...messages.imageDimenstionDescription} />
2633
+ </CapHeading>
2634
+ </>
2635
+ );
2636
+ }
2637
+ return (
2638
+ <CapButton
2639
+ className="dragger-button"
2640
+ type="flat"
2641
+ style={{top: 0, position: 'absolute', right: 0, color: FONT_COLOR_05 }}
2642
+ onClick={this.onReUpload}
2643
+ >
2644
+ <FormattedMessage {...messages.imageReUpload} />
2645
+ </CapButton>
2646
+ );
2647
+ }
2648
+ return (
2649
+ <CapButton disabled={val.disabled ? val.disabled : false} type="flat" prefix={<CapIcon size="s" type="add-photo" />} onClick={(e) => this.openFileDialog(e, val.id)} style={{float: 'right', color: `${val.disabled ? FONT_COLOR_04 : FONT_COLOR_05}`}}>
2650
+ {val.label}
2651
+ </CapButton>
2652
+ );
2653
+ }
2654
+
2535
2655
  renderMultiColSection(section, childIndex) {
2536
2656
  const fields = [];
2537
2657
  let contentSections = [];
@@ -2578,7 +2698,6 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2578
2698
  );
2579
2699
  return true;
2580
2700
  }
2581
-
2582
2701
  switch (type) {
2583
2702
  case "input":
2584
2703
  ifError = this.state.checkValidation && (isVersionEnable ? this.state.errorData[`${this.state.currentTab - 1}`][val.id] : this.state.errorData[val.id]);
@@ -2706,7 +2825,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2706
2825
  <div>
2707
2826
  <div className={`image-container ${ifError ? 'error' : ''}`}>
2708
2827
  {self.state && !!self.state.formData[`${self.state.currentTab - 1}`].image ?
2709
- <img src={self.state.formData[`${self.state.currentTab - 1}`].image} alt={val.alt} style={val.style}/>
2828
+ <CapImage src={self.state.formData[`${self.state.currentTab - 1}`].image} alt={val.alt} style={val.style}/>
2710
2829
  :
2711
2830
  <div style={{width: "100%", textAlign: "center"}}><span className="image-placeholder">{val.placeholder}</span></div>
2712
2831
  }
@@ -2717,13 +2836,22 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2717
2836
  );
2718
2837
  break;
2719
2838
  case 'upload':
2839
+ const {
2840
+ formData: {
2841
+ [`${self.state.currentTab - 1}`]: {
2842
+ image,
2843
+ } = {},
2844
+ } = {},
2845
+ } = self.state;
2846
+ const isImage = !!image;
2720
2847
  ifError = (this.state.checkValidation || this.props.startValidation) && (isVersionEnable ? this.state.errorData[`${this.state.currentTab - 1}`][val.id] : this.state.errorData[val.id]);
2721
2848
  const ImageComponent = (props) => (
2722
2849
  <div key={`${val.id}-${this.state.currentTab}`}>
2723
2850
  <div className={`image-container ${props.ifError ? 'error' : ''}`}>
2724
- {self.state && !!self.state.formData[`${self.state.currentTab - 1}`].image ?
2725
- <img src={self.state.formData[`${self.state.currentTab - 1}`].image} alt={props.alt} style={props.style}/>
2726
- :
2851
+
2852
+ {isImage ?
2853
+ <CapImage src={self.state.formData[`${self.state.currentTab - 1}`].image} alt={props.alt} style={props.style}/>
2854
+ :
2727
2855
  <div style={{width: "100%", textAlign: "center"}}><span className="image-placeholder">{props.placeholder}</span></div>
2728
2856
  }
2729
2857
  </div>
@@ -2736,9 +2864,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2736
2864
  {val.showPreview && <WithLabel key={`${val.id}-with-label`} {...rest} errorMessage={ifError && errorMessage} ifError={ifError}/>}
2737
2865
  <form encType="multipart/form-data" id={val.id}>
2738
2866
  <input key={val.id} style={{ display: 'none'}} id="fileName" type="file" onChange={(e) => this.uploadImages(e, {files: e.target.files}, val)} accept={val.supportedExtensions ? val.supportedExtensions : "image/*"} />
2739
- <CapButton disabled={val.disabled ? val.disabled : false} type="flat" prefix={<CapIcon size="s" type="add-photo" />} onClick={(e) => this.openFileDialog(e, val.id)} style={{float: 'right', color: `${val.disabled ? '#b3bac5' : '#2466ea'}`}}>
2740
- {val.label}
2741
- </CapButton>
2867
+ {this.getUploadVariants(isImage, val)}
2742
2868
  </form>
2743
2869
  </CapColumn>
2744
2870
  );
@@ -2783,11 +2909,16 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2783
2909
  );
2784
2910
  break;
2785
2911
  case "tag-list":
2912
+ let moduleFilterEnabled = this.props.location && this.props.location.query && this.props.location.query.type !== 'embedded';
2913
+ const channel = _.get(this.props, 'schema.channel', "");
2914
+ if (channel === 'EMAIL') {
2915
+ moduleFilterEnabled = this.props.isFullMode;
2916
+ }
2786
2917
  columns.push(
2787
2918
  <CapColumn key={`input-${val.id}`} offset={val.offset} span={val.width ? val.width : ''} style={val.style ? val.style : {marginBottom: '16px'}}>
2788
2919
  <TagList
2789
2920
  key={`input-${val.id}`}
2790
- moduleFilterEnabled={this.props.location && this.props.location.query && this.props.location.query.type !== 'embedded'}
2921
+ moduleFilterEnabled={moduleFilterEnabled}
2791
2922
  label={val.label ? val.label : ''}
2792
2923
  onTagSelect={(data) => this.callChildEvent(data, val, 'onTagSelect')}
2793
2924
  onContextChange={this.props.onContextChange}
@@ -2810,7 +2941,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2810
2941
  type={val.buttonType}
2811
2942
  icon={val.icon}
2812
2943
  disabled={val.disabled ? val.disabled : false}
2813
- onClick={(data) => this.callChildEvent(data, val, val.submitAction)}>
2944
+ onClick={(data) => val.id === 'save-button' ? this.saveForm() : this.callChildEvent(data, val, val.submitAction)}>
2814
2945
  {val.value}
2815
2946
  </CapButton>
2816
2947
  </CapColumn>
@@ -2834,6 +2965,9 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2834
2965
  content={content}
2835
2966
  charCounterEnabled={val.charCounterEnabled}
2836
2967
  unicodeEnabled={unicodeEnabled}
2968
+ showTestAndPreviewIcon
2969
+ onPreviewContentClicked={this.props.onPreviewContentClicked}
2970
+ onTestContentClicked={this.props.onTestContentClicked}
2837
2971
  >
2838
2972
  </TemplatePreview>
2839
2973
  </CapColumn>
@@ -2883,6 +3017,10 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2883
3017
  ],
2884
3018
  appName: val.content.appName,
2885
3019
  }}
3020
+ showTestAndPreviewIcon
3021
+ onPreviewContentClicked={this.props.onPreviewContentClicked}
3022
+ onTestContentClicked={this.props.onTestContentClicked}
3023
+ templateDataRaw={this.props.templateData}
2886
3024
  >
2887
3025
  </TemplatePreview>
2888
3026
  </CapColumn>
@@ -3296,6 +3434,16 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3296
3434
  loadingText={this.props.intl.formatMessage(messages.loadingEDMTemplates)}
3297
3435
  isLoading={this.props.getCmsTemplatesInProgress}
3298
3436
  />
3437
+ {
3438
+ this.props.capDrawerContent && (
3439
+ <CapDrawer
3440
+ content={this.props.capDrawerContent}
3441
+ visible={this.state.isDrawerVisible}
3442
+ width={380}
3443
+ onClose={() => this.props.setDrawerVisibility(false)}
3444
+ />
3445
+ )
3446
+ }
3299
3447
  </CapRow>
3300
3448
  );
3301
3449
  }
@@ -3346,6 +3494,9 @@ FormBuilder.propTypes = {
3346
3494
  handleDelete: PropTypes.func,
3347
3495
  intl: intlShape.isRequired,
3348
3496
  selectedOfferDetails: PropTypes.array,
3497
+ setDrawerVisibility: PropTypes.bool,
3498
+ capDrawerContent: PropTypes.array,
3499
+ isFullMode: PropTypes.bool,
3349
3500
  };
3350
3501
 
3351
3502
  export default injectIntl(FormBuilder);
@@ -58,4 +58,20 @@ export default defineMessages({
58
58
  id: 'creatives.componentsV2.FormBuilder.loadingEDMTemplates',
59
59
  defaultMessage: 'Loading EDM Templates',
60
60
  },
61
+ uploadComputer: {
62
+ id: 'creatives.componentsV2.FormBuilder.uploadComputer',
63
+ defaultMessage: 'Your computer',
64
+ },
65
+ uploadGallery: {
66
+ id: 'creatives.componentsV2.FormBuilder.uploadGallery',
67
+ defaultMessage: 'Gallery',
68
+ },
69
+ imageDimenstionDescription: {
70
+ id: 'creatives.componentsV2.FormBuilder.imageDimenstionDescription',
71
+ defaultMessage: 'Dimensions: 300px x 400px Size: 30mb',
72
+ },
73
+ imageReUpload: {
74
+ id: 'creatives.componentsV2.FormBuilder.imageReUpload',
75
+ defaultMessage: 'Re upload',
76
+ },
61
77
  });
@@ -7,16 +7,10 @@
7
7
  import PropTypes from 'prop-types';
8
8
 
9
9
  import React from 'react';
10
- import { CapButton } from '@capillarytech/cap-ui-library';
11
- // import styled from 'styled-components';
12
-
13
- import { FormattedMessage } from 'react-intl';
14
- import { Button } from 'antd';
10
+ import { CapTab, CapIcon } from '@capillarytech/cap-ui-library';
15
11
  import { get, map, isEmpty} from 'lodash';
16
12
  import TemplatePreview from '../TemplatePreview';
17
13
  import '../PreviewSideBar/_previewsidebar.scss';
18
- import messages from './messages';
19
- const ButtonGroup = Button.Group;
20
14
 
21
15
  class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react/prefer-stateless-function
22
16
  constructor(props) {
@@ -24,8 +18,11 @@ class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react
24
18
  this.goToEdit = this.goToEdit.bind(this);
25
19
  this.goToDuplicate = this.goToDuplicate.bind(this);
26
20
  this.changeDevice = this.changeDevice.bind(this);
27
- const hasAndroid = get(props, 'templateData.versions.base.ANDROID') || get(props, 'templateData.androidContent');
28
- const hasIos = get(props, 'templateData.versions.base.IOS') || get(props, 'templateData.iosContent');
21
+ this.getPreview = this.getPreview.bind(this);
22
+ this.setContent = this.setContent.bind(this);
23
+ this.goToDuplicate = this.goToDuplicate.bind(this);
24
+ const hasAndroid = get(props, 'templateData.versions.base.ANDROID') || get(props, 'templateData.androidContent.title');
25
+ const hasIos = get(props, 'templateData.versions.base.IOS') || get(props, 'templateData.iosContent.title');
29
26
  let device = "android";
30
27
  if (hasAndroid) {
31
28
  device = 'android';
@@ -38,7 +35,7 @@ class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react
38
35
  };
39
36
  }
40
37
 
41
- setContent = (templateData, device) => {
38
+ setContent(templateData, device) {
42
39
  const androidContent = get(templateData, 'versions.base.ANDROID') || get(templateData, 'androidContent');
43
40
  const iosContent = get(templateData, 'versions.base.IOS') || get(templateData, 'iosContent');
44
41
 
@@ -59,12 +56,21 @@ class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react
59
56
  }
60
57
  return content;
61
58
  }
59
+ getPreview(device) {
60
+ return (
61
+ <TemplatePreview
62
+ device={device}
63
+ channel={this.props.channel}
64
+ content={this.state.content || ''}
65
+ templateData={this.props.templateData}
66
+ />
67
+ );
68
+ }
62
69
  goToDuplicate() {
63
70
  this.props.onDuplicateClick(this.props.templateData);
64
71
  this.props.handleClose();
65
72
  }
66
- changeDevice(ev) {
67
- const device = ev.target.value;
73
+ changeDevice(device) {
68
74
  const content = this.setContent(this.props.templateData, device);
69
75
  this.setState({device, content });
70
76
  }
@@ -72,38 +78,40 @@ class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react
72
78
  this.props.onEditClick(e, this.props.templateData._id, this.props.templateData.modeType, path);
73
79
  }
74
80
  render() {
75
- const {templateData, channel} = this.props;
76
-
77
- const hasAndroid = get(templateData, 'versions.base.ANDROID') || get(templateData, 'androidContent');
78
- const hasIos = get(templateData, 'versions.base.IOS') || get(templateData, 'iosContent');
79
-
80
- const {device, content} = this.state;
81
+ const {templateData} = this.props;
82
+ const hasAndroid = get(templateData, 'versions.base.ANDROID') || get(templateData, 'androidContent.title');
83
+ const hasIos = get(templateData, 'versions.base.IOS') || get(templateData, 'iosContent.title');
84
+ const hasBothAndroidAndIos = hasAndroid && hasIos;
81
85
 
82
86
  return (
83
-
84
87
  <div>
85
88
  <div className="devices">
86
- {!isEmpty(templateData) && hasAndroid && hasIos &&
87
- <ButtonGroup onClick={this.changeDevice}>
88
- <CapButton type={device === "android" ? "primary" : "secondary"} value={"android"}><FormattedMessage {...messages.android} /></CapButton>
89
- <CapButton type={device === "iphone" ? "primary" : "secondary"} value={"iphone"}><FormattedMessage {...messages.ios} /></CapButton>
90
- </ButtonGroup>}
89
+ {!isEmpty(templateData) &&
90
+ ( hasBothAndroidAndIos ? (
91
+ <CapTab
92
+ panes={[
93
+ {
94
+ content: this.getPreview('android'),
95
+ tab: <CapIcon type="android" size="m" />,
96
+ key: 'android',
97
+ },
98
+ {
99
+ content: this.getPreview('iphone'),
100
+ tab: <CapIcon type="ios" size="m" />,
101
+ key: 'iphone',
102
+ },
103
+ ]}
104
+ onChange={(activeKey) => this.changeDevice(activeKey)}
105
+ tabBarStyle={{margin: 'auto', width: '38%'}}
106
+ />
107
+ ) : (
108
+ (hasAndroid || hasIos) && this.getPreview(hasAndroid ? 'android' : 'ios')
109
+ ))
110
+ }
91
111
  </div>
92
- <TemplatePreview
93
- device={device === "android" ? "android" : "iphone"}
94
- channel={channel}
95
- content={content || ''}
96
- templateData={templateData}
97
- >
98
- </TemplatePreview>
99
-
100
-
101
112
  </div>
102
-
103
-
104
113
  );
105
114
  }
106
-
107
115
  }
108
116
 
109
117
  MobilePushPreviewV2.propTypes = {
@@ -10,12 +10,4 @@ export default defineMessages({
10
10
  id: 'creatives.componentsv2.MobilePushPreviewV2.header',
11
11
  defaultMessage: 'This is the MobilePushPreviewV2 component !',
12
12
  },
13
- android: {
14
- id: 'creatives.componentsv2.MobilePushPreviewV2.android',
15
- defaultMessage: 'Android',
16
- },
17
- ios: {
18
- id: 'creatives.componentsv2.MobilePushPreviewV2.ios',
19
- defaultMessage: 'IOS',
20
- },
21
13
  });
@@ -1,5 +1,69 @@
1
1
  @import '~@capillarytech/cap-ui-library/styles/_variables.scss';
2
2
 
3
+ .shell-lock-screen-android .main-screen-preview .wechatMsgContainer{
4
+ position: absolute;
5
+ left: 53.5%;
6
+ top:28%;
7
+ background: white;
8
+ width: 19.5%;
9
+ text-align: left;
10
+ height: fit-content;
11
+ border-radius: 0.285rem;
12
+ }
13
+
14
+ .shell-lock-screen-android .lock-screen-preview{
15
+ .wechat-android-sender-id{
16
+ position: absolute;
17
+ top: 46%;
18
+ font-size: 10px;
19
+ left: 28%;
20
+ }
21
+ .wechat-android-title{
22
+ position: absolute;
23
+ top: 49%;
24
+ font-size: 10px;
25
+ left: 28%;
26
+ color: #5e6c84;
27
+ }
28
+ .wechat-android-action-buttons{
29
+ position: absolute;
30
+ left: 28%;
31
+ top: 53%;
32
+ font-size: 10px;
33
+ color: #3861ca;
34
+ font-weight: 500;
35
+ }
36
+ .wechat-ios-sender-id{
37
+ position: absolute;
38
+ top: 44%;
39
+ font-size: 10px;
40
+ left: 28.5%;
41
+ }
42
+ .wechat-ios-title{
43
+ position: absolute;
44
+ top: 47%;
45
+ font-size: 10px;
46
+ left: 28.5%;
47
+ color: #5e6c84;
48
+ }
49
+ .wechat-ios-action-reply{
50
+ position: absolute;
51
+ left: 35%;
52
+ top: 59%;
53
+ font-size: 12px;
54
+ color: #3861ca;
55
+ font-weight: 500;
56
+ }
57
+ .wechat-ios-action-cancel{
58
+ position: absolute;
59
+ left: 34.5%;
60
+ top: 66%;
61
+ font-size: 12px;
62
+ color: #3861ca;
63
+ font-weight: 500;
64
+ }
65
+ }
66
+
3
67
  .wechatMsgContainer{
4
68
  position: absolute;
5
69
  left: 30%;