@capillarytech/creatives-library 6.10.5 → 6.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.
@@ -2912,7 +2912,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2912
2912
  langIndex = parseInt(val.id.replace('template-content', ''), 10) - 1;
2913
2913
  }
2914
2914
 
2915
- const currentLang = (!_.isEmpty(this.state.formData) && !_.isEmpty(this.state.formData[`${this.state.currentTab - 1}`]) && !_.isEmpty(this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages) && this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages[langIndex]) ? this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages[langIndex] : this.props.baseLanguage;
2915
+ const currentLang = ((!_.isEmpty(this.state.formData) && !_.isEmpty(this.state.formData[`${this.state.currentTab - 1}`]) && !_.isEmpty(this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages) && this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages[langIndex]) ? this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages[langIndex] : this.props.baseLanguage) || 'en';
2916
2916
  const content = (!_.isEmpty(this.state.formData) && this.state.formData[`${this.state.currentTab - 1}`][currentLang]['template-content'] ? this.state.formData[`${this.state.currentTab - 1}`][currentLang]['template-content'] : '');
2917
2917
 
2918
2918
  if (this.state.formData[`${this.state.currentTab - 1}`][currentLang].is_drag_drop) {
@@ -2942,14 +2942,14 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2942
2942
  langTab = val.id.charAt(9);
2943
2943
  }
2944
2944
  }
2945
- const supportedLanguages = this.state.formData[this.state.currentTab - 1].selectedLanguages;
2945
+ const supportedLanguages = (this.state.formData[this.state.currentTab - 1] || {}).selectedLanguages;
2946
2946
  // let langIndex = 0;
2947
2947
  // if (val.id.indexOf('edmeditor') > -1 && val.id !== 'edmeditorsrc') {
2948
2948
  // const test = val.id.replace('src', '');
2949
2949
  // langIndex = parseInt(test.replace('edmeditor', ''), 10) - 1;
2950
2950
  // }
2951
2951
  // const currentLang = (!_.isEmpty(this.state.formData) && !_.isEmpty(this.state.formData[`${this.state.currentTab - 1}`]) && !_.isEmpty(this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages) && this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages[langIndex]) ? this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages[langIndex] : this.props.baseLanguage;
2952
- const currentLang = supportedLanguages[langTab - 1];
2952
+ const currentLang = supportedLanguages && supportedLanguages[langTab - 1];
2953
2953
  const edmSrc = this.state.formData[`${this.state.currentTab - 1}`][currentLang] && this.state.formData[`${this.state.currentTab - 1}`][currentLang][`edmeditor${this.state.currentTab > 1 ? this.state.currentTab : ''}src`];
2954
2954
 
2955
2955
 
@@ -871,7 +871,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
871
871
  const schema = _.cloneDeep(this.state.schema);
872
872
  const langIndex = formData[this.state.currentTab - 1].selectedLanguages.indexOf(langId);
873
873
  console.log('edm trying to set data', langIndex, langId, formData[this.state.currentTab - 1].activeTab, apiLangId);
874
- const temp = schema.containers[this.state.currentTab - 1];
874
+ const temp = (schema.containers || {})[this.state.currentTab - 1];
875
875
  if (baseLanguage === langId && (apiLangId === "undefined" || apiLangId === formData[this.state.currentTab - 1].activeTab)) {
876
876
  temp.tabBarExtraContent.sections[0].inputFields[0].cols[4].content.sections[0].inputFields[2].cols[0].style = {display: "none"};
877
877
  } else if (apiLangId === "undefined" || apiLangId === formData[this.state.currentTab - 1].activeTab) {
@@ -191,8 +191,8 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
191
191
  this.setState({ channel }, () => {
192
192
  if (this.state.channel.toLowerCase() === 'line' || this.state.channel.toLowerCase() === 'sms' || this.state.channel.toLowerCase() === 'email' || this.state.channel.toLowerCase() === 'ebill' || (this.state.channel.toLowerCase() === 'wechat' && !_.isEmpty(nextProps.Templates.selectedWeChatAccount))) {
193
193
  if (this.state.channel.toLowerCase() === 'wechat' && !_.isEmpty(nextProps.Templates.selectedWeChatAccount)) {
194
- params.wecrmId = nextProps.Templates.selectedWeChatAccount.configs.wecrm_app_id;
195
- params.wecrmToken = nextProps.Templates.selectedWeChatAccount.configs.wecrm_token;
194
+ params.wecrmId = (nextProps.Templates.selectedWeChatAccount.configs || {}).wecrm_app_id;
195
+ params.wecrmToken = (nextProps.Templates.selectedWeChatAccount.configs || {}).wecrm_token;
196
196
  params.originalId = nextProps.Templates.selectedWeChatAccount.sourceAccountIdentifier;
197
197
  }
198
198
  if (this.state.channel.toLowerCase() === "mobilepush" && !_.isEmpty(nextProps.Templates.selectedWeChatAccount)) {
@@ -203,8 +203,8 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
203
203
  });
204
204
  }
205
205
  if (this.state.channel.toLowerCase() === 'wechat' && nextProps.Templates.selectedWeChatAccount) {
206
- params.wecrmId = nextProps.Templates.selectedWeChatAccount.configs.wecrm_app_id;
207
- params.wecrmToken = nextProps.Templates.selectedWeChatAccount.configs.wecrm_token;
206
+ params.wecrmId = (nextProps.Templates.selectedWeChatAccount.configs || {}).wecrm_app_id;
207
+ params.wecrmToken = (nextProps.Templates.selectedWeChatAccount.configs || {}).wecrm_token;
208
208
  params.originalId = nextProps.Templates.selectedWeChatAccount.sourceAccountIdentifier;
209
209
  }
210
210
  if (this.state.channel.toLowerCase() === "mobilepush" && nextProps.Templates.selectedWeChatAccount) {
@@ -1536,7 +1536,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1536
1536
  if (this.state.channel.toLowerCase() === 'ebill') {
1537
1537
  htmlPreviewContent = this.state.previewTemplate && this.state.previewTemplate.versions && this.state.previewTemplate.versions.base && this.state.previewTemplate.versions.base['ebill-editor'];
1538
1538
  } else if (this.state.channel.toLowerCase() === 'email') {
1539
- htmlPreviewContent = this.state.previewTemplate && this.state.previewTemplate.versions && this.state.previewTemplate.versions.base && this.state.previewTemplate.versions.base[this.props.Global.currentOrgDetails.basic_details.base_language ? this.props.Global.currentOrgDetails.basic_details.base_language : 'en']['template-content'];
1539
+ htmlPreviewContent = this.state.previewTemplate && this.state.previewTemplate.versions && this.state.previewTemplate.versions.base && (this.state.previewTemplate.versions.base[this.props.Global.currentOrgDetails.basic_details.base_language ? this.props.Global.currentOrgDetails.basic_details.base_language : 'en'] || {})['template-content'];
1540
1540
  }
1541
1541
 
1542
1542
  const templateList = this.populateTemplatesList(this.props.TemplatesList, true);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "6.10.5",
4
+ "version": "6.11.0",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
package/reducers.js CHANGED
@@ -8,6 +8,7 @@ import { fromJS } from 'immutable';
8
8
  import { LOCATION_CHANGE } from 'react-router-redux';
9
9
 
10
10
  import languageProviderReducer from 'v2Containers/LanguageProvider/reducer';
11
+ import beeEditorReducer from 'v2Containers/BeeEditor/reducer';
11
12
  import capReducer from 'containers/Cap/reducer';
12
13
  import appReducer from 'containers/App/reducer';
13
14
  import createSmsReducer from 'containers/Sms/Create/reducer';
@@ -60,6 +61,7 @@ export default function createReducer(asyncReducers) {
60
61
  tagList: tagsReducer,
61
62
  email: emailReducer,
62
63
  ebill: ebillReducer,
64
+ beeEditor: beeEditorReducer,
63
65
  ...asyncReducers,
64
66
  });
65
67
  }
package/routes.js CHANGED
@@ -12,6 +12,7 @@ import * as emailSagas from 'containers/Email/sagas';
12
12
  import * as templateSagas from 'containers/Templates/sagas';
13
13
  import * as lineSagas from 'containers/Line/Create/sagas';
14
14
  import * as languageSaga from './v2Containers/LanguageProvider/sagas';
15
+
15
16
  import {updateCharCount} from './utils/smsCharCountV2';
16
17
  const errorLoading = (err) => {
17
18
  console.error('Dynamic page loading failed', err); // eslint-disable-line no-console
@@ -614,6 +615,7 @@ export default function createRoutes(store) {
614
615
  import('v2Containers/Sms/Edit/sagas'),
615
616
  import('v2Containers/Email/reducer'),
616
617
  import('v2Containers/Email/sagas'),
618
+ import('v2Containers/BeeEditor/sagas'),
617
619
  import('v2Containers/CallTask/reducer'),
618
620
  import('v2Containers/CallTask/sagas'),
619
621
  import('v2Containers/MobilePush/Create/sagas'),
@@ -642,6 +644,7 @@ export default function createRoutes(store) {
642
644
  creativesContainerReducer,
643
645
  smsCreateReducer, smsCreateSaga, smsEditReducer, smsEditSaga,
644
646
  emailReducer, emailSaga,
647
+ BeeEditorSaga,
645
648
  callTaskReducer, callTaskSagas,
646
649
  mpushCreateSagas, mpushCreateReducer,
647
650
  mpushEditSagas, mpushEditReducer,
@@ -673,6 +676,7 @@ export default function createRoutes(store) {
673
676
  injectSagas(smsCreateSaga.default);
674
677
  injectSagas(smsEditSaga.default);
675
678
  injectSagas(emailSaga.default);
679
+ injectSagas(BeeEditorSaga.default);
676
680
  injectSagas(callTaskSagas.default);
677
681
  injectSagas(mpushCreateSagas.default);
678
682
  injectSagas(mpushEditSagas.default);
package/services/api.js CHANGED
@@ -386,3 +386,9 @@ export const getMarketingObjectives = (channel) =>
386
386
 
387
387
  export const getAllLineStickers = () =>
388
388
  request(`${API_ENDPOINT}/meta/sticker`, getAPICallObject('GET'));
389
+
390
+
391
+ export const createCustomRow = (data) => {
392
+ const url = `${API_ENDPOINT}/cms/saveRows`;
393
+ return request(url, getAPICallObject('POST', data));
394
+ };
@@ -86,6 +86,21 @@
86
86
  "creatives.components.WechatRichmediaTemplatePreview.header": "This is the WechatRichmediaTemplatePreview component !",
87
87
  "creatives.components.WechatRichmediaTemplatePreview.reply": "Reply",
88
88
  "creatives.components.WechatRichmediaTemplatePreview.select": "Select",
89
+ "creatives.componentsV2.BeeEditor.addLabel": "Add label",
90
+ "creatives.componentsV2.BeeEditor.cancel": "Cancel",
91
+ "creatives.componentsV2.BeeEditor.cta": "CTA",
92
+ "creatives.componentsV2.BeeEditor.customRows": "Custom rows",
93
+ "creatives.componentsV2.BeeEditor.footer": "Footer",
94
+ "creatives.componentsV2.BeeEditor.header": "Header",
95
+ "creatives.componentsV2.BeeEditor.others": "Others",
96
+ "creatives.componentsV2.BeeEditor.rowName": "Row name",
97
+ "creatives.componentsV2.BeeEditor.rowPlaceHolder": "Enter Row name",
98
+ "creatives.componentsV2.BeeEditor.save": "Save",
99
+ "creatives.componentsV2.BeeEditor.select": "Select",
100
+ "creatives.componentsV2.BeeEditor.selectCategoyPlaceholder": "Select category",
101
+ "creatives.componentsV2.BeeEditor.socialPlatform": "Social platform",
102
+ "creatives.componentsV2.BeeEditor.tagPlaceHolder": "Enter tags",
103
+ "creatives.componentsV2.BeeEditor.tags": "Tags (optional)",
89
104
  "creatives.componentsV2.BreadCrumbs.header": "This is the BreadCrumbs component !",
90
105
  "creatives.componentsV2.CallTaskPreview.header": "This is the CallTaskPreview component !",
91
106
  "creatives.componentsV2.CapTagList.Cancel": "Cancel",
@@ -1452,8 +1467,10 @@
1452
1467
  "creatives.containersV2.Templates.creativesTemplatesSave": "Done",
1453
1468
  "creatives.containersV2.Templates.deleteButton": "Delete",
1454
1469
  "creatives.containersV2.Templates.deletedSuccssfully": "Template deleted successfully",
1470
+ "creatives.containersV2.Templates.deletingTemplate": "Deleting template...",
1455
1471
  "creatives.containersV2.Templates.deletionFailed": "Template deletion failed",
1456
1472
  "creatives.containersV2.Templates.duplicateButton": "Duplicate",
1473
+ "creatives.containersV2.Templates.duplicatingTemplate": "Duplicating template...",
1457
1474
  "creatives.containersV2.Templates.ebillHeader": "Ebill",
1458
1475
  "creatives.containersV2.Templates.ebillPreview": "Ebill preview",
1459
1476
  "creatives.containersV2.Templates.editButton": "Edit",
@@ -86,6 +86,21 @@
86
86
  "creatives.components.WechatRichmediaTemplatePreview.header": "",
87
87
  "creatives.components.WechatRichmediaTemplatePreview.reply": "",
88
88
  "creatives.components.WechatRichmediaTemplatePreview.select": "",
89
+ "creatives.componentsV2.BeeEditor.addLabel": "",
90
+ "creatives.componentsV2.BeeEditor.cancel": "",
91
+ "creatives.componentsV2.BeeEditor.cta": "",
92
+ "creatives.componentsV2.BeeEditor.customRows": "",
93
+ "creatives.componentsV2.BeeEditor.footer": "",
94
+ "creatives.componentsV2.BeeEditor.header": "",
95
+ "creatives.componentsV2.BeeEditor.others": "",
96
+ "creatives.componentsV2.BeeEditor.rowName": "",
97
+ "creatives.componentsV2.BeeEditor.rowPlaceHolder": "",
98
+ "creatives.componentsV2.BeeEditor.save": "",
99
+ "creatives.componentsV2.BeeEditor.select": "",
100
+ "creatives.componentsV2.BeeEditor.selectCategoyPlaceholder": "",
101
+ "creatives.componentsV2.BeeEditor.socialPlatform": "",
102
+ "creatives.componentsV2.BeeEditor.tagPlaceHolder": "",
103
+ "creatives.componentsV2.BeeEditor.tags": "",
89
104
  "creatives.componentsV2.BreadCrumbs.header": "",
90
105
  "creatives.componentsV2.CallTaskPreview.header": "",
91
106
  "creatives.componentsV2.CapTagList.Cancel": "",
@@ -1452,8 +1467,10 @@
1452
1467
  "creatives.containersV2.Templates.creativesTemplatesSave": "",
1453
1468
  "creatives.containersV2.Templates.deleteButton": "",
1454
1469
  "creatives.containersV2.Templates.deletedSuccssfully": "",
1470
+ "creatives.containersV2.Templates.deletingTemplate": "",
1455
1471
  "creatives.containersV2.Templates.deletionFailed": "",
1456
1472
  "creatives.containersV2.Templates.duplicateButton": "",
1473
+ "creatives.containersV2.Templates.duplicatingTemplate": "",
1457
1474
  "creatives.containersV2.Templates.ebillHeader": "",
1458
1475
  "creatives.containersV2.Templates.ebillPreview": "",
1459
1476
  "creatives.containersV2.Templates.editButton": "",
@@ -1,9 +1,6 @@
1
1
  .modal-emailPreivew-wrapper {
2
2
  width: 100vw;
3
3
  height: 100vh;
4
- position: fixed;
5
- top: 0;
6
- left: 0;
7
4
  background: rgba(0,0,0,0.56);
8
5
  z-index: 10002;
9
6
 
@@ -21,7 +21,7 @@ import SlideBox from '../SlideBox';
21
21
  import CardGrid from '../CardGrid';
22
22
  import CKEditor from "../Ckeditor/";
23
23
  import EDMEditor from "../Edmeditor";
24
- import BeeEditor from '../BeeEditor';
24
+ import BeeEditor from '../../v2Containers/BeeEditor';
25
25
  import CustomPopOver from '../CustomPopOver';
26
26
  import messages from './messages';
27
27
  import './_formBuilder.scss';
@@ -3178,7 +3178,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3178
3178
  langIndex = parseInt(val.id.replace('template-content', ''), 10) - 1;
3179
3179
  }
3180
3180
  console.log('CKEditor Data 2', this.state.formData, this.state.formData[`${this.state.currentTab - 1}`], val, this.state.currentTab, this.state.currentLangTab, langIndex);
3181
- const currentLang = (!_.isEmpty(this.state.formData) && !_.isEmpty(this.state.formData[`${this.state.currentTab - 1}`]) && !_.isEmpty(this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages) && this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages[langIndex]) ? this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages[langIndex] : this.props.baseLanguage;
3181
+ const currentLang = ((!_.isEmpty(this.state.formData) && !_.isEmpty(this.state.formData[`${this.state.currentTab - 1}`]) && !_.isEmpty(this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages) && this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages[langIndex]) ? this.state.formData[`${this.state.currentTab - 1}`].selectedLanguages[langIndex] : this.props.baseLanguage) || 'en';
3182
3182
  const content = (!_.isEmpty(this.state.formData) && this.state.formData[`${this.state.currentTab - 1}`][currentLang]['template-content'] ? this.state.formData[`${this.state.currentTab - 1}`][currentLang]['template-content'] : '');
3183
3183
  console.log('ckeditor current lang', currentLang, content);
3184
3184
  if (this.state.formData[`${this.state.currentTab - 1}`][currentLang].is_drag_drop) {
@@ -3330,9 +3330,8 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3330
3330
  if (columns.length) {
3331
3331
  fields.push(row);
3332
3332
  }
3333
-
3334
3333
  });
3335
- if(!this.props.isEmailLoading && this.props.schema.channel.toUpperCase() === 'EMAIL' && !fields.length) {
3334
+ if (!this.props.isEmailLoading && this.props.schema.channel.toUpperCase() === 'EMAIL' && !fields.length) {
3336
3335
  return (
3337
3336
  <div style={{ textAlign: 'center' }}>
3338
3337
  <CapSpin spinning />
@@ -0,0 +1,12 @@
1
+ import {
2
+ CREATE_CUSTOM_ROW_REQUEST,
3
+ } from './constants';
4
+
5
+ export function createCustomRow(data, callback) {
6
+ return {
7
+ type: CREATE_CUSTOM_ROW_REQUEST,
8
+ data,
9
+ callback,
10
+ };
11
+ }
12
+
@@ -0,0 +1,5 @@
1
+ const prefix = 'APP/V2CONTAINER/BEEEDITOR';
2
+ export const CREATE_CUSTOM_ROW_REQUEST = `${prefix}/CREATE_CUSTOM_ROW_REQUEST`;
3
+ export const CREATE_CUSTOM_ROW_SUCCESS = `${prefix}/CREATE_CUSTOM_ROW_SUCCESS`;
4
+ export const CREATE_CUSTOM_ROW_FAILURE = `${prefix}/CREATE_CUSTOM_ROW_FAILURE`;
5
+
@@ -0,0 +1,329 @@
1
+ /**
2
+ *
3
+ * Beeeditor
4
+ *
5
+ */
6
+ import React, { useEffect, useState, useRef, useCallback } from 'react';
7
+ import PropTypes from 'prop-types';
8
+ import { injectIntl, intlShape, FormattedMessage } from 'react-intl';
9
+ import { connect } from 'react-redux';
10
+ import TagList from '../TagList';
11
+ import { bindActionCreators } from 'redux';
12
+ import { createStructuredSelector } from 'reselect';
13
+ import makeSelectBEE from './selectors';
14
+ import { UserIsAuthenticated } from '../../utils/authWrapper';
15
+ import config from '../../config/app';
16
+ import { loadItem } from 'services/localStorageApi';
17
+ import './index.scss';
18
+ import {
19
+ CapModal,
20
+ CapButton,
21
+ CapInput,
22
+ CapSelect,
23
+ CapSpin,
24
+ CapNotification,
25
+ }
26
+ from '@capillarytech/cap-ui-library';
27
+ import messages from './messages';
28
+ import * as beeActions from './actions';
29
+ function BeeEditor(props) {
30
+ const {
31
+ uid,
32
+ beeJson,
33
+ tokenData,
34
+ id,
35
+ location = {},
36
+ moduleFilterEnabled,
37
+ label,
38
+ className,
39
+ userLocale,
40
+ selectedOfferDetails,
41
+ tags,
42
+ injectedTags,
43
+ saveBeeInstance,
44
+ saveBeeData,
45
+ intl,
46
+ onContextChange,
47
+ actions,
48
+ BEESelect,
49
+ } = props;
50
+ const { saveRowRequest } = BEESelect;
51
+ const {formatMessage} = intl;
52
+ const UNSUBSCRIBE = 'unsubscribe';
53
+ let beePluginInstance = null;
54
+ const categoryOptions = [{key: 'cta', value: 'cta', label: formatMessage(messages.cta)},
55
+ {key: 'footer', value: 'footer', label: formatMessage(messages.footer)},
56
+ {key: 'header', value: 'header', label: formatMessage(messages.header)},
57
+ {key: 'sp', value: 'sp', label: formatMessage(messages.socialPlatform)},
58
+ {key: 'others', value: 'others', label: formatMessage(messages.others)},
59
+ ];
60
+ const [visibleTaglist, setVisibleTaglist] = useState(false);
61
+ const [showRowMetaModal, setRowMetaModal] = useState(false);
62
+ const [selectedTag, setSelectedTag] = useState({});
63
+ const [rowMetaInfo, setRowMetaInfo] = useState({});
64
+ const [rowName, setRowName] = useState('');
65
+ const [rowCategory, setRowCategory] = useState('');
66
+ let API_ENDPOINT = config.development.api_endpoint;
67
+ if (process.env.NODE_ENV === 'production') {
68
+ API_ENDPOINT = `${window.location.origin}${config.production.api_endpoint}`;
69
+ }
70
+ const savedCallback = useRef();
71
+ const filteredTags = (tags || []).filter((obj) => obj.definition.value !== UNSUBSCRIBE);
72
+ let intervalTimer;
73
+
74
+ const DEFAULT_LOCALE = 'en';
75
+ const MAPPED_LOCALE = {
76
+ 'en': 'en',
77
+ 'zh-cn': 'zh',
78
+ 'zh': 'zh',
79
+ };
80
+ const user = localStorage.getItem('user');
81
+ let locale = 'en';
82
+ if (user && JSON.parse(user).lang) {
83
+ locale = JSON.parse(user).lang;
84
+ }
85
+ const defaultFormattedUrl = locale !== DEFAULT_LOCALE && ['zh-cn', 'zh'].includes(locale)
86
+ ? `${API_ENDPOINT}/common/getBEECustomLangunage?langid=${MAPPED_LOCALE[locale]}`
87
+ : "";
88
+ useEffect(() => {
89
+ savedCallback.current = Object.keys(selectedTag).length > 0 ? selectedTag : rowMetaInfo;
90
+ }, [selectedTag, rowMetaInfo]);
91
+
92
+ const getExternalContentURLs = () => {
93
+ const externalContentURLs = categoryOptions.map((obj) => ({name: obj.label, value: `${API_ENDPOINT}/common/getCustomRows?category=${obj.value}&orgid=${loadItem('orgID')}`}));
94
+ return externalContentURLs;
95
+ };
96
+ useEffect(() => {
97
+ const beeConfig = {
98
+ uid,
99
+ container: 'bee-plugin-container',
100
+ translationsUrl: defaultFormattedUrl,
101
+ rowsConfiguration: {
102
+ emptyRows: true,
103
+ defaultRows: true,
104
+ externalContentURLs: getExternalContentURLs(),
105
+ },
106
+ contentDialog: {
107
+ specialLinks: {
108
+ label: UNSUBSCRIBE,
109
+ handler(resolve) {
110
+ resolve({
111
+ type: 'custom',
112
+ label: UNSUBSCRIBE,
113
+ link: `{{${UNSUBSCRIBE}}}`,
114
+ });
115
+ },
116
+ },
117
+ mergeTags: {
118
+ label: formatMessage(messages.addLabel),
119
+ handler: async (resolve, reject) => {
120
+ // this will open tag modal
121
+ await setVisibleTaglist(true);
122
+ // until tag modal will not open promise will not execute
123
+ // once tag modal is opened it will start 2 sec interval to wait use has selected any tag or cancel the tag selection
124
+ const promise = new Promise((resolveP) => {
125
+ intervalTimer = setInterval(() => {
126
+ // this will execute, if user cancel the tag selection
127
+ if ((savedCallback.current || {}).close === true) {
128
+ reject();
129
+ clearInterval(intervalTimer);
130
+ return;
131
+ }
132
+ // this block is checking use has selected any tag or not
133
+ if (Object.keys(savedCallback.current || {}).length > 0) {
134
+ resolveP(savedCallback.current);
135
+ setSelectedTag({});
136
+ clearInterval(intervalTimer);
137
+ }
138
+ }, 2000);
139
+ });
140
+ // once prmise will resolve , pass the resolve data to handler to show tags in bee edior
141
+ const result = await promise;
142
+ resolve(result);
143
+ },
144
+ },
145
+ saveRow: {
146
+ handler: async (resolve, reject) => {
147
+ await setRowMetaModal(true);
148
+ const promise = new Promise((resolveP) => {
149
+ intervalTimer = setInterval(() => {
150
+ if ((savedCallback.current || {}).close === true) {
151
+ reject();
152
+ clearInterval(intervalTimer);
153
+ setRowMetaInfo({});
154
+ setRowName('');
155
+ setRowCategory('');
156
+ return;
157
+ }
158
+ if (Object.keys(savedCallback.current || {}).length > 0) {
159
+ resolveP(savedCallback.current);
160
+ }
161
+ }, 2000);
162
+ });
163
+ const result = await promise;
164
+ resolve(result); // "done!"
165
+ setRowMetaInfo({});
166
+ setRowName('');
167
+ setRowCategory('');
168
+ clearInterval(intervalTimer);
169
+ },
170
+ },
171
+ },
172
+ onSave: (jsonFile, htmlFile) => {
173
+ saveBeeData(jsonFile, htmlFile);
174
+ },
175
+ onSaveRow: (rowJSON) => {
176
+ actions.createCustomRow(JSON.parse(rowJSON), callbackSaveRow);
177
+ },
178
+ };
179
+ window.BeePlugin.create(tokenData, beeConfig, (instance) => {
180
+ beePluginInstance = instance;
181
+ const parseJson = JSON.parse(beeJson);
182
+ beePluginInstance.start(parseJson);
183
+ saveBeeInstance(beePluginInstance);
184
+ });
185
+ return () => clearInterval(intervalTimer);
186
+ }, []);
187
+ const callbackSaveRow = (status, errorMsg) => {
188
+ if (status === 'success') {
189
+ CapNotification.success({message: formatMessage(messages.rowCreationSuccessMgs), key: 'create-custom-row-success'});
190
+ } else {
191
+ CapNotification.error({message: errorMsg || formatMessage(messages.rowCreationFailureMgs), key: 'create-custom-row-failure'});
192
+ }
193
+ };
194
+
195
+ const onTagSelect = (result) => {
196
+ const msg = {
197
+ name: result,
198
+ value: `{{${result}}}`,
199
+ };
200
+ setSelectedTag(msg);
201
+ setVisibleTaglist(false);
202
+ };
203
+
204
+ const onCancelTagList = () => {
205
+ setVisibleTaglist(false);
206
+ setSelectedTag({close: true});
207
+ };
208
+
209
+ const onCustomRowCancel = () => {
210
+ setRowMetaModal(false);
211
+ setRowCategory('');
212
+ setRowName('');
213
+ setRowMetaInfo({close: true});
214
+ };
215
+
216
+ const onCustomRowSave = () => {
217
+ const rowInfo = {};
218
+ if (rowCategory !== '') {
219
+ rowInfo.category = rowCategory;
220
+ }
221
+ setRowMetaInfo({
222
+ name: rowName,
223
+ ...rowInfo,
224
+ });
225
+ setRowMetaModal(false);
226
+ setRowCategory('');
227
+ setRowName('');
228
+ };
229
+
230
+ const isDisableSave = () => rowName === '' || rowCategory === '';
231
+
232
+ const onRowChange = useCallback((e) => {
233
+ setRowName(e.target.value);
234
+ });
235
+ const onChangeCategoy = (e) => {
236
+ setRowCategory(e);
237
+ };
238
+ const contentSection = <>
239
+ <CapInput
240
+ label={<FormattedMessage {...messages.rowName} />}
241
+ placeholder={formatMessage(messages.rowPlaceHolder)}
242
+ onChange={onRowChange}
243
+ value={rowName}
244
+ maxLength={50}
245
+ style={{ width: 324, paddingBottom: 21 }}
246
+ />
247
+ <CapSelect
248
+ label="Category"
249
+ style={{ width: 324, paddingBottom: 24}}
250
+ options={categoryOptions}
251
+ value={rowCategory || undefined}
252
+ placeholder={<FormattedMessage {...messages.selectCategoyPlaceholder} />}
253
+ onChange={onChangeCategoy}
254
+ />
255
+
256
+ </>;
257
+ return (
258
+ <CapSpin spinning={saveRowRequest || false}>
259
+ <div id="bee-plugin-container" style={{ height: '500px'}}>
260
+ </div>
261
+ <TagList
262
+ moduleFilterEnabled={moduleFilterEnabled}
263
+ label={label}
264
+ onTagSelect={onTagSelect}
265
+ location={location}
266
+ tags={filteredTags}
267
+ injectedTags={injectedTags}
268
+ className={className}
269
+ id={id}
270
+ userLocale={userLocale}
271
+ selectedOfferDetails={selectedOfferDetails}
272
+ visibleTaglist={visibleTaglist}
273
+ hidePopover
274
+ modalProps={{
275
+ onCancel: onCancelTagList,
276
+ style: { left: 135, top: 250 },
277
+ className: "bee-editor-tag-list",
278
+ }}
279
+ onContextChange={onContextChange}
280
+ />
281
+ <CapModal
282
+ className="custom-row-modal"
283
+ visible={showRowMetaModal}
284
+ onCancel={onCustomRowCancel}
285
+ title={formatMessage(messages.customRows)}
286
+ style={{width: 372, height: 296, left: 135, top: 300}}
287
+ footer={[
288
+ <CapButton key="submit" type="primary" id="delete-version" onClick={onCustomRowSave} disabled={isDisableSave()}>
289
+ {formatMessage(messages.done)}
290
+ </CapButton>,
291
+ ]}
292
+ >
293
+ {contentSection}
294
+ </CapModal>
295
+ </CapSpin>
296
+ );
297
+ }
298
+
299
+ BeeEditor.propTypes = {
300
+ beeJson: PropTypes.object.isRequired,
301
+ tokenData: PropTypes.object.isRequired,
302
+ uid: PropTypes.string.isRequired,
303
+ intl: intlShape.isRequired,
304
+ actions: PropTypes.object.isRequired,
305
+ BEESelect: PropTypes.object,
306
+ id: PropTypes.string,
307
+ location: PropTypes.object,
308
+ moduleFilterEnabled: PropTypes.bool,
309
+ label: PropTypes.string,
310
+ className: PropTypes.string,
311
+ tags: PropTypes.array,
312
+ saveBeeData: PropTypes.func,
313
+ saveBeeInstance: PropTypes.func,
314
+ injectedTags: PropTypes.object,
315
+ onContextChange: PropTypes.func,
316
+ userLocale: PropTypes.string,
317
+ };
318
+
319
+ const mapStateToProps = () => createStructuredSelector({
320
+ BEESelect: makeSelectBEE(),
321
+ });
322
+
323
+ function mapDispatchToProps(dispatch) {
324
+ return {
325
+ actions: bindActionCreators(beeActions, dispatch),
326
+ };
327
+ }
328
+
329
+ export default UserIsAuthenticated(connect(mapStateToProps, mapDispatchToProps)(injectIntl(BeeEditor)));
@@ -0,0 +1,6 @@
1
+ .custom-row-modal {
2
+ .ant-modal-footer {
3
+ text-align: left;
4
+ padding-left: 24px;
5
+ }
6
+ }
@@ -0,0 +1,67 @@
1
+ /*
2
+ * BeeEditor Messages
3
+ *
4
+ * This contains all the text for the BeeEditor component.
5
+ */
6
+ import { defineMessages } from 'react-intl';
7
+
8
+ const prefix = 'creatives.containersV2.BeeEditor';
9
+
10
+ export default defineMessages({
11
+ done: {
12
+ id: `${prefix}.done`,
13
+ defaultMessage: 'Done',
14
+ },
15
+ rowPlaceHolder: {
16
+ id: `${prefix}.rowPlaceHolder`,
17
+ defaultMessage: 'Enter Row name',
18
+ },
19
+ rowName: {
20
+ id: `${prefix}.rowName`,
21
+ defaultMessage: 'Row name',
22
+ },
23
+ select: {
24
+ id: `${prefix}.select`,
25
+ defaultMessage: 'Select',
26
+ },
27
+ customRows: {
28
+ id: `${prefix}.customRows`,
29
+ defaultMessage: 'Create new row',
30
+ },
31
+ selectCategoyPlaceholder: {
32
+ id: `${prefix}.selectCategoyPlaceholder`,
33
+ defaultMessage: 'Select category',
34
+ },
35
+ addLabel: {
36
+ id: `${prefix}.addLabel`,
37
+ defaultMessage: 'Add label',
38
+ },
39
+ cta: {
40
+ id: `${prefix}.cta`,
41
+ defaultMessage: 'CTA',
42
+ },
43
+ header: {
44
+ id: `${prefix}.header`,
45
+ defaultMessage: 'Header',
46
+ },
47
+ footer: {
48
+ id: `${prefix}.footer`,
49
+ defaultMessage: 'Footer',
50
+ },
51
+ others: {
52
+ id: `${prefix}.others`,
53
+ defaultMessage: 'Others',
54
+ },
55
+ socialPlatform: {
56
+ id: `${prefix}.socialPlatform`,
57
+ defaultMessage: 'Social platform',
58
+ },
59
+ rowCreationSuccessMgs: {
60
+ id: `${prefix}.rowCreationSuccessMgs`,
61
+ defaultMessage: 'Row created successfully',
62
+ },
63
+ rowCreationFailureMgs: {
64
+ id: `${prefix}.rowCreationFailureMgs`,
65
+ defaultMessage: 'Error in row creation',
66
+ },
67
+ });
@@ -0,0 +1,25 @@
1
+ import { fromJS } from 'immutable';
2
+ import {
3
+ CREATE_CUSTOM_ROW_REQUEST,
4
+ CREATE_CUSTOM_ROW_SUCCESS,
5
+ CREATE_CUSTOM_ROW_FAILURE,
6
+ } from './constants';
7
+
8
+ const initialState = fromJS({
9
+ saveRowRequest: false,
10
+ });
11
+
12
+ function beeEditorReducer(state = initialState, action) {
13
+ switch (action.type) {
14
+ case CREATE_CUSTOM_ROW_REQUEST:
15
+ return state.set('saveRowRequest', true);
16
+ case CREATE_CUSTOM_ROW_SUCCESS:
17
+ return state.set('saveRowRequest', false);
18
+ case CREATE_CUSTOM_ROW_FAILURE:
19
+ return state.set('saveRowRequest', false);
20
+ default:
21
+ return state;
22
+ }
23
+ }
24
+
25
+ export default beeEditorReducer;
@@ -0,0 +1,33 @@
1
+ import { take, cancel, call, put, takeLatest } from 'redux-saga/effects';
2
+ import { LOCATION_CHANGE } from 'react-router-redux';
3
+ import * as Api from '../../services/api';
4
+ import * as types from './constants';
5
+
6
+ export function* createCustomRow({data, callback}) {
7
+ let errorMsg;
8
+ try {
9
+ const result = yield call(Api.createCustomRow, data);
10
+ const code = result.status ? result.status.code : '';
11
+ if (!result.success || code === 500) {
12
+ errorMsg = result.message;
13
+ yield put({ type: types.CREATE_CUSTOM_ROW_FAILURE, errorMsg });
14
+ callback('failed', code !== 500 ? errorMsg : '');
15
+ } else {
16
+ yield put({ type: types.CREATE_CUSTOM_ROW_SUCCESS, data: result.response, statusCode: code, errorMsg });
17
+ callback('success');
18
+ }
19
+ } catch (error) {
20
+ yield put({ type: types.CREATE_CUSTOM_ROW_FAILURE, error, errorMsg });
21
+ }
22
+ }
23
+
24
+ function* watchCreateCustomRow() {
25
+ const watcher = yield takeLatest(types.CREATE_CUSTOM_ROW_REQUEST, createCustomRow);
26
+ yield take(LOCATION_CHANGE);
27
+ yield cancel(watcher);
28
+ }
29
+
30
+ // All sagas to be loaded
31
+ export default [
32
+ watchCreateCustomRow,
33
+ ];
@@ -0,0 +1,17 @@
1
+ import { createSelector } from 'reselect';
2
+ import { fromJS } from 'immutable';
3
+ /**
4
+ * Direct selector to the email state domain
5
+ */
6
+ const selectBEEDomain = () => (state) => state.get('beeEditor');
7
+
8
+ /**
9
+ * Default selector used by beeEditor
10
+ */
11
+
12
+ const makeSelectBEE = () => createSelector(
13
+ selectBEEDomain(),
14
+ (substate = fromJS({})) => substate.toJS()
15
+ );
16
+
17
+ export default makeSelectBEE;
@@ -0,0 +1,10 @@
1
+ // import React from 'react';
2
+ // import { shallow } from 'enzyme';
3
+
4
+ // import Beeeditor from '../index';
5
+
6
+ describe('<Beeeditor />', () => {
7
+ it('Expect to have unit tests specified', () => {
8
+ expect(true).toEqual(false);
9
+ });
10
+ });
@@ -224,12 +224,10 @@ class Creatives extends React.Component {
224
224
  const { messages = '[]' } = additionalProperties;
225
225
  const messagesDefinition = JSON.parse(messages);
226
226
  let lineContent = JSON.parse(messageBody || '{}').messages || [{}];
227
- lineContent = lineContent.map((content, index) => {
228
- return {
227
+ lineContent = lineContent.map((content, index) => ({
229
228
  ...content,
230
229
  ...(messagesDefinition[index] || {})
231
- };
232
- })
230
+ }));
233
231
  creativesTemplateData = {
234
232
  type: constants.LINE,
235
233
  isDefault,
@@ -318,10 +316,10 @@ class Creatives extends React.Component {
318
316
  if (template.value) {
319
317
  const { versions } = template.value;
320
318
  const { Templates, templateData: templateDataProps } = this.props;
321
- const { accountDetails: selectedAccountDetails } = templateDataProps || {};
319
+ const { accountDetails: selectedAccountDetails, accountId: selectedAccountId } = templateDataProps || {};
322
320
  const selectedLineAccount = Templates && Templates.selectedLineAccount;
323
- const accountDetails = !!selectedLineAccount ? JSON.stringify(selectedLineAccount) : (selectedAccountDetails || '');
324
- const accountId = !!selectedLineAccount ? selectedLineAccount.id : '';
321
+ const accountDetails = selectedAccountDetails || (selectedLineAccount ? JSON.stringify(selectedLineAccount) : '');
322
+ const accountId = selectedAccountId || (selectedLineAccount ? selectedLineAccount.id : '');
325
323
  templateData = {
326
324
  channel,
327
325
  accountId,
@@ -346,7 +346,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
346
346
  const schema = _.cloneDeep(this.state.schema);
347
347
  const langIndex = formData[this.state.currentTab - 1].selectedLanguages.indexOf(langId);
348
348
 
349
- const temp = schema.containers[this.state.currentTab - 1];
349
+ const temp = (schema.containers || {})[this.state.currentTab - 1];
350
350
 
351
351
  const { currentTab } = this.state;
352
352
  if (nextProps.Email.CmsSettings.isDragDrop) {
@@ -696,10 +696,10 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
696
696
  getValidationData = () => {
697
697
  const that = this;
698
698
  let id = _.get(this.props, 'Email.templateDetails._id', '') || _.get(this.props, 'Templates.BEETemplate._id', '');
699
+ const formData = _.cloneDeep(this.state.formData);
699
700
  if (!id) {
700
701
  id = _.get(formData, `base[${formData.base.activeTab}].id`, '');
701
702
  }
702
- const formData = _.cloneDeep(this.state.formData);
703
703
  if (!this.props.Email.fetchingCmsData) {
704
704
  // checking wheather getCmsData in progress or not cuz getValidationData gets called multiple times from handleEdmSave
705
705
  _.forEach(formData, (val, index) => {
@@ -1851,7 +1851,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
1851
1851
  action: "showNext",
1852
1852
  value: true,
1853
1853
  };
1854
-
1855
1854
  }
1856
1855
 
1857
1856
  moveToTemplates = () => {
@@ -2745,7 +2744,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
2745
2744
  isLoading={this.props.Email.fetchingAllAssets}
2746
2745
  size="size-xl"
2747
2746
  />
2748
- {/* <div id="bee-plugin-container" style={{ height: '600px'}}></div> */}
2749
2747
  {this.state.showConfirmationModal && this.renderConfirmationModal()}
2750
2748
  </div>
2751
2749
  );
@@ -248,8 +248,8 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
248
248
  this.setState({ channel }, () => {
249
249
  if ((this.state.channel.toLowerCase() === 'line' || this.state.channel.toLowerCase() === 'sms' || this.state.channel.toLowerCase() === 'email' || this.state.channel.toLowerCase() === 'ebill') || (this.state.channel.toLowerCase() === 'wechat' && !isEmpty(nextProps.Templates.selectedWeChatAccount))) {
250
250
  if (this.state.channel.toLowerCase() === 'wechat' && !isEmpty(nextProps.Templates.selectedWeChatAccount)) {
251
- params.wecrmId = nextProps.Templates.selectedWeChatAccount.configs.wecrm_app_id;
252
- params.wecrmToken = nextProps.Templates.selectedWeChatAccount.configs.wecrm_token;
251
+ params.wecrmId = (nextProps.Templates.selectedWeChatAccount.configs || {}).wecrm_app_id;
252
+ params.wecrmToken = (nextProps.Templates.selectedWeChatAccount.configs || {}).wecrm_token;
253
253
  params.originalId = nextProps.Templates.selectedWeChatAccount.sourceAccountIdentifier;
254
254
  }
255
255
  if (this.state.channel.toLowerCase() === "mobilepush" && !isEmpty(nextProps.Templates.selectedWeChatAccount)) {
@@ -260,8 +260,8 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
260
260
  });
261
261
  }
262
262
  if ((this.state.channel || '').toLowerCase() === 'wechat' && nextProps.Templates.selectedWeChatAccount) {
263
- params.wecrmId = nextProps.Templates.selectedWeChatAccount.configs.wecrm_app_id;
264
- params.wecrmToken = nextProps.Templates.selectedWeChatAccount.configs.wecrm_token;
263
+ params.wecrmId = (nextProps.Templates.selectedWeChatAccount.configs || {}).wecrm_app_id;
264
+ params.wecrmToken = (nextProps.Templates.selectedWeChatAccount.configs || {}).wecrm_token;
265
265
  params.originalId = nextProps.Templates.selectedWeChatAccount.sourceAccountIdentifier;
266
266
  }
267
267
  if ((this.state.channel || '').toLowerCase() === "mobilepush" && nextProps.Templates.selectedWeChatAccount) {
@@ -1855,7 +1855,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1855
1855
  if (this.state.channel.toLowerCase() === 'ebill') {
1856
1856
  htmlPreviewContent = this.state.previewTemplate && this.state.previewTemplate.versions && this.state.previewTemplate.versions.base && this.state.previewTemplate.versions.base['ebill-editor'];
1857
1857
  } else if (this.state.channel.toLowerCase() === 'email') {
1858
- htmlPreviewContent = this.state.previewTemplate && this.state.previewTemplate.versions && this.state.previewTemplate.versions.base && this.state.previewTemplate.versions.base[this.props.Global.currentOrgDetails.basic_details.base_language ? this.props.Global.currentOrgDetails.basic_details.base_language : 'en']['template-content'];
1858
+ htmlPreviewContent = this.state.previewTemplate && this.state.previewTemplate.versions && this.state.previewTemplate.versions.base && (this.state.previewTemplate.versions.base[this.props.Global.currentOrgDetails.basic_details.base_language ? this.props.Global.currentOrgDetails.basic_details.base_language : 'en'] || {})['template-content'];
1859
1859
  }
1860
1860
 
1861
1861