@capillarytech/creatives-library 6.10.4 → 6.10.6

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "6.10.4",
4
+ "version": "6.10.6",
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": "",
@@ -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';
@@ -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
+ });
@@ -318,10 +318,10 @@ class Creatives extends React.Component {
318
318
  if (template.value) {
319
319
  const { versions } = template.value;
320
320
  const { Templates, templateData: templateDataProps } = this.props;
321
- const { accountDetails: selectedAccountDetails } = templateDataProps || {};
321
+ const { accountDetails: selectedAccountDetails, accountId: selectedAccountId } = templateDataProps || {};
322
322
  const selectedLineAccount = Templates && Templates.selectedLineAccount;
323
- const accountDetails = !!selectedLineAccount ? JSON.stringify(selectedLineAccount) : (selectedAccountDetails || '');
324
- const accountId = !!selectedLineAccount ? selectedLineAccount.id : '';
323
+ const accountDetails = selectedAccountDetails || (!!selectedLineAccount ? JSON.stringify(selectedLineAccount) : '');
324
+ const accountId = selectedAccountId || (!!selectedLineAccount ? selectedLineAccount.id : '');
325
325
  templateData = {
326
326
  channel,
327
327
  accountId,
@@ -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) => {