@capillarytech/creatives-library 7.6.12 → 7.6.13

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 (47) hide show
  1. package/app.js +5 -0
  2. package/index.html +2 -2
  3. package/package.json +2 -2
  4. package/services/api.js +2 -0
  5. package/utils/gtmTrackers/gtmEvents/creativeDetails.js +41 -0
  6. package/utils/gtmTrackers/index.js +17 -0
  7. package/v2Components/TemplatePreview/assets/images/mobile.svg +24 -0
  8. package/v2Containers/App/constants.js +11 -0
  9. package/v2Containers/Cap/index.js +23 -29
  10. package/v2Containers/Email/index.js +14 -3
  11. package/v2Containers/EmailWrapper/index.js +10 -3
  12. package/v2Containers/Line/Container/index.js +32 -4
  13. package/v2Containers/Line/Create/_lineCreate.scss +64 -0
  14. package/v2Containers/Line/Create/actions.js +94 -0
  15. package/v2Containers/Line/Create/constants.js +43 -0
  16. package/v2Containers/Line/Create/index.js +1132 -0
  17. package/v2Containers/Line/Create/initialSchema.js +378 -0
  18. package/v2Containers/Line/Create/messages.js +229 -0
  19. package/v2Containers/Line/Create/reducer.js +99 -0
  20. package/v2Containers/Line/Create/sagas.js +113 -0
  21. package/v2Containers/Line/Create/selectors.js +30 -0
  22. package/v2Containers/Line/CreateWrapper/constants.js +2 -0
  23. package/v2Containers/Line/CreateWrapper/index.js +117 -0
  24. package/v2Containers/Line/CreateWrapper/messages.js +55 -0
  25. package/v2Containers/Line/Edit/_lineEdit.scss +23 -0
  26. package/v2Containers/Line/Edit/actions.js +79 -0
  27. package/v2Containers/Line/Edit/constants.js +27 -0
  28. package/v2Containers/Line/Edit/index.js +1051 -0
  29. package/v2Containers/Line/Edit/messages.js +173 -0
  30. package/v2Containers/Line/Edit/reducer.js +83 -0
  31. package/v2Containers/Line/Edit/sagas.js +81 -0
  32. package/v2Containers/Line/Edit/selectors.js +29 -0
  33. package/v2Containers/Line/Edit/tests/actions.test.js +18 -0
  34. package/v2Containers/Line/Edit/tests/index.test.js +10 -0
  35. package/v2Containers/Line/Edit/tests/reducer.test.js +9 -0
  36. package/v2Containers/Line/Edit/tests/sagas.test.js +15 -0
  37. package/v2Containers/Line/Edit/tests/selectors.test.js +10 -0
  38. package/v2Containers/MobilePush/Create/index.js +25 -4
  39. package/v2Containers/MobilePush/Edit/index.js +27 -5
  40. package/v2Containers/MobilePush/Edit/sagas.js +1 -1
  41. package/v2Containers/MobilePush/commonMethods.js +19 -1
  42. package/v2Containers/Sms/Create/index.js +14 -2
  43. package/v2Containers/Sms/Edit/index.js +15 -2
  44. package/v2Containers/Templates/index.js +7 -4
  45. package/v2Containers/Viber/index.js +19 -3
  46. package/v2Containers/WeChat/MapTemplates/index.js +12 -3
  47. package/v2Containers/WeChat/RichmediaTemplates/Create/index.js +11 -2
@@ -0,0 +1,1132 @@
1
+ import PropTypes from 'prop-types';
2
+ import React, { Component } from 'react';
3
+ import get from 'lodash/get';
4
+ import set from 'lodash/set';
5
+ import { bindActionCreators } from 'redux';
6
+ import { intlShape } from 'react-intl';
7
+ import { createStructuredSelector } from 'reselect';
8
+ import _ from 'lodash';
9
+ import { CapSpin, CapHeading, CapRow, CapColumn, CapNotification } from '@capillarytech/cap-ui-library';
10
+ import { GA } from '@capillarytech/cap-ui-utils';
11
+ import messages from './messages';
12
+ import * as actions from './actions';
13
+ import Gallery from '../../Assets/Gallery';
14
+ import FormBuilder from '../../../v2Components/FormBuilder';
15
+ //import { makeSelectCreate, makeSelectCreateResponse, makeSelectEdit, makeSelectEditResponse, makeSelectTemplateDetailsResponse } from './selectors';
16
+ import {makeSelectCreateLine, makeSelectLine} from './selectors';
17
+ import { makeSelectMetaEntities, setInjectedTags } from '../../Cap/selectors';
18
+ import {getMessageObject} from '../../../utils/messageUtils';
19
+ import { makeSelectTemplates } from '../../Templates/selectors';
20
+ import './_lineCreate.scss';
21
+ import withCreatives from '../../../hoc/withCreatives';
22
+ import {
23
+ LINE_IMG_HEIGHT,
24
+ LINE_IMG_WIDTH,
25
+ LINE_IMG_SIZE,
26
+ } from './constants';
27
+ import { TRACK_CREATE_LINE, TRACK_EDIT_LINE } from '../../App/constants';
28
+
29
+ export class Line extends Component {
30
+ constructor(props) {
31
+ super(props);
32
+ const map = {
33
+ 'save-button': {
34
+ saveFormData: this.saveFormData,
35
+ },
36
+ 'template-name': {
37
+ onChange: this.onTemplateNameChange,
38
+ },
39
+ 'discard-button': {
40
+ discardValues: this.discardValues,
41
+ },
42
+ 'message-editor': {
43
+ onChange: this.onTemplateContentChange,
44
+ },
45
+ 'message-editor2': {
46
+ onChange: this.onTemplateContentChange,
47
+ },
48
+ 'message-tagList': {
49
+ onTagSelect: this.onTagSelect,
50
+ },
51
+ 'title-tagList': {
52
+ onTagSelect: this.onTagSelectTitle,
53
+ },
54
+ 'pane': {
55
+ onTabChange: this.onTabChange,
56
+ },
57
+ 'line-template': {
58
+ onSelect: this.onTemplateChange,
59
+ },
60
+ 'image-upload-line': {
61
+ onUpload: this.uploadImage,
62
+ },
63
+ 'tagList': {
64
+ onTagSelect: this.onTagSelect,
65
+ },
66
+ 'line-editor': {
67
+ onChange: this.onTemplateContentChange,
68
+ },
69
+ };
70
+
71
+ this.state = {
72
+ schema: {},
73
+ isSchemaChanged: false,
74
+ formData: {},
75
+ tabCount: 1,
76
+ currentTab: 1,
77
+ loading: false,
78
+ isFormValid: true,
79
+ tabKey: '',
80
+ checkValidation: false,
81
+ eventsMap: map,
82
+ errorData: {},
83
+ displayProps: {},
84
+ modalContent: {
85
+ title: this.props.intl.formatMessage(messages.alertMessage),
86
+ body: this.props.intl.formatMessage(
87
+ messages.templateNotConfigured
88
+ ),
89
+ type: 'confirm',
90
+ },
91
+ injectedTags: {},
92
+ isEdit: false,
93
+ isEdited: false,
94
+ editTemplateData: {},
95
+ isReady: false,
96
+ modeType: null,
97
+ isDrawerRequired: false,
98
+ startValidation: false,
99
+ };
100
+ }
101
+
102
+ componentWillMount() {
103
+ if (this.props.params.id) {
104
+ const editTemplateId = this.props.params.id;
105
+ this.props.actions.getTemplateDetails(editTemplateId, 'LINE');
106
+ this.setState({ isEdit: true });
107
+ }
108
+ }
109
+
110
+ componentDidMount() {
111
+ const getSchemaQuery = {
112
+ layout: 'LINE',
113
+ type: 'LAYOUT',
114
+ version: 'v2',
115
+ };
116
+ this.props.globalActions.fetchSchemaForEntity(getSchemaQuery);
117
+ }
118
+
119
+ componentWillReceiveProps(nextProps) {
120
+ //// Create template logic ////
121
+
122
+ let modeType;
123
+ const { layouts, tags } = nextProps.metaEntities;
124
+ const isSchemaReady = layouts !== undefined && layouts.length > 0;
125
+ const editModeType = nextProps.route.name;
126
+ if (
127
+ nextProps.params.mode === 'text' ||
128
+ nextProps.route.name === 'edit_text'
129
+ ) {
130
+ modeType = 'text';
131
+ } else {
132
+ modeType = 'image';
133
+ }
134
+ if (modeType) {
135
+ this.setState({ modeType, schema: {} });
136
+ }
137
+ const {
138
+ isGetFormData,
139
+ templateData,
140
+ } = nextProps;
141
+ if (isGetFormData) {
142
+ const {
143
+ lineData,
144
+ getFormSubscriptionData,
145
+ } = nextProps;
146
+ let selectedAccount = {};
147
+ if (lineData) {
148
+ const {
149
+ weCrmAccounts = [],
150
+ } = lineData;
151
+ selectedAccount = weCrmAccounts.filter((account) => account === selectedAccount);
152
+ }
153
+ getFormSubscriptionData({ ...this.getFormData(), accountDetails: selectedAccount, type: 'LINE' });
154
+ }
155
+ if (templateData && templateData.edit) {
156
+ this.setEditState(templateData);
157
+ }
158
+ if (isSchemaReady) {
159
+ // set schema value as per mode type. Supported mode (text & image)
160
+ const { textSchema, imageSchema } = this.updateSchemaWithLabels(
161
+ layouts[0].definition
162
+ );
163
+ const schema =
164
+ modeType === 'text' || editModeType === 'edit_text'
165
+ ? textSchema
166
+ : imageSchema;
167
+ this.setState({ schema }, () => {
168
+ // Once schema is ready and set, then inject the available events from the schema
169
+ if (!_.isEmpty(this.state.schema)) {
170
+ this.injectEvents(this.state.schema);
171
+ }
172
+ // Once schema is ready, then only get the tags.
173
+ const getTagsQuery = {
174
+ layout: 'LINE',
175
+ type: 'TAG',
176
+ context:
177
+ this.props.location.query.type === 'embedded'
178
+ ? 'outbound'
179
+ : 'default',
180
+ embedded:
181
+ this.props.location.query.type === 'embedded'
182
+ ? this.props.location.query.type
183
+ : 'full',
184
+ };
185
+ if (this.props.getDefaultTags) {
186
+ getTagsQuery.context = this.props.getDefaultTags;
187
+ }
188
+ if (!Object.keys(tags || {}).length && modeType !== 'image') {
189
+ this.props.globalActions.fetchSchemaForEntity(getTagsQuery);
190
+ } else {
191
+ this.setState({ isReady: true });
192
+ }
193
+ });
194
+ }
195
+
196
+ const lineTemplateId = get(nextProps, 'Line.response.templateId', '');
197
+ if (lineTemplateId) {
198
+ this.discardValues();
199
+ const message = getMessageObject(
200
+ 'success',
201
+ this.props.intl.formatMessage(
202
+ messages.lineTemplateCreatedSuccessfully
203
+ ),
204
+ true
205
+ );
206
+ this.props.globalActions.addMessageToQueue(message);
207
+ this.props.actions.clearCreateResponse();
208
+ }
209
+
210
+ if (
211
+ nextProps.Line.createTemplateError &&
212
+ !_.isEqual(
213
+ nextProps.Line.createTemplateError,
214
+ this.props.Line.createTemplateError
215
+ )
216
+ ) {
217
+ const {
218
+ Line: {
219
+ createTemplateErrorMessage,
220
+ },
221
+ } = nextProps;
222
+ const message = getMessageObject(
223
+ 'error',
224
+ createTemplateErrorMessage || this.props.intl.formatMessage(messages.somethingWentWrong),
225
+ true
226
+ );
227
+ this.props.globalActions.addMessageToQueue(message);
228
+ }
229
+
230
+ //// Edit Template Logic ////
231
+ const isEdit =
232
+ this.state.isEdit &&
233
+ this.props.params.id &&
234
+ (this.props.route.name === 'edit_text' ||
235
+ this.props.route.name === 'edit_image') &&
236
+ this.props.Line.templateDetails &&
237
+ this.props.Line.templateDetails.versions;
238
+ if (isEdit) {
239
+ const formData = this.getEditTransformedData(
240
+ this.props.Line.templateDetails
241
+ );
242
+ this.setState({
243
+ formData,
244
+ editTemplateData: this.props.Line.templateDetails,
245
+ });
246
+ this.props.actions.clearData();
247
+ }
248
+
249
+ if (
250
+ nextProps.Line.editTemplateError &&
251
+ !_.isEqual(
252
+ nextProps.Line.editTemplateError,
253
+ this.props.Line.editTemplateError
254
+ )
255
+ ) {
256
+ const message = getMessageObject(
257
+ 'error',
258
+ nextProps.Line.editTemplateErrorMessage &&
259
+ nextProps.Line.editTemplateErrorMessage !== ''
260
+ ? nextProps.Line.editTemplateErrorMessage
261
+ : this.props.intl.formatMessage(messages.somethingWentWrong),
262
+ true
263
+ );
264
+ this.props.globalActions.addMessageToQueue(message);
265
+ }
266
+
267
+ if (
268
+ nextProps.Line.uploadAssetSuccess &&
269
+ nextProps.Line.uploadedAssetData
270
+ ) {
271
+ const formData = _.cloneDeep(this.state.formData);
272
+ // TODO: if multiple image upload supports, change below accordingly.
273
+ formData[this.state.currentTab - 1].image =
274
+ nextProps.Line.uploadedAssetData.metaInfo.secure_file_path;
275
+ formData[this.state.currentTab - 1].imagePreview =
276
+ nextProps.Line.uploadedAssetData.metaInfo.secure_file_path_preview;
277
+ this.setState({ formData });
278
+ this.props.actions.clearAsset();
279
+ }
280
+ }
281
+
282
+ setEditSuccessMessage = () => {
283
+ this.setState({ formData: {} });
284
+ const message = getMessageObject(
285
+ 'success',
286
+ this.props.intl.formatMessage(
287
+ messages['Line Template Edited Successfully']
288
+ ),
289
+ true
290
+ );
291
+ this.props.globalActions.addMessageToQueue(message);
292
+ this.props.actions.clearEditResponse();
293
+ }
294
+
295
+ setEditState = (data) => {
296
+ const { formData: previousFormData } = this.state;
297
+ const { text, originalContentUrl, imagePreview, image, previewImageUrl } = get(data, "versions.base.content.messages[0]", {});
298
+ const retrievedData = {
299
+ ...previousFormData[0],
300
+ };
301
+ if (text) {
302
+ retrievedData["message-editor"] = text;
303
+ }
304
+ const lineImage = originalContentUrl || image;
305
+ if (lineImage) {
306
+ retrievedData.image = lineImage;
307
+ retrievedData.imagePreview = imagePreview || previewImageUrl;
308
+ }
309
+ const formData = {
310
+ 0: retrievedData,
311
+ base: retrievedData,
312
+ };
313
+ this.setState({ formData });
314
+ }
315
+
316
+ componentWillUnmount() {
317
+ window.removeEventListener('message', this.handleFrameTasks);
318
+ }
319
+
320
+ onTagSelect(data, currentTab) {
321
+ const editorId = 'message-editor';
322
+ this.insertAtCursor(
323
+ document.getElementById(editorId),
324
+ `{{${data}}}`,
325
+ currentTab
326
+ );
327
+ document.getElementById(editorId).focus();
328
+ }
329
+
330
+ onTagSelectTitle(data, currentTab) {
331
+ const editorId = 'message-title';
332
+ this.insertAtCursor(
333
+ document.getElementById(editorId),
334
+ `{{${data}}}`,
335
+ currentTab
336
+ );
337
+ document.getElementById(editorId).focus();
338
+ }
339
+
340
+ onFormDataChange = (formData, tabCount, currentTab) => {
341
+ this.setState({ formData: { ...formData } });
342
+ if (tabCount) {
343
+ this.setState({ tabCount });
344
+ }
345
+ if (currentTab) {
346
+ this.setState({ currentTab });
347
+ }
348
+ };
349
+
350
+ getTransformedData = (formData) => {
351
+ const modeType = this.state.modeType;
352
+ const obj = {};
353
+ const msgData = {};
354
+ obj.versions = {
355
+ base: {
356
+ content: {
357
+ to: '{{line_id}}',
358
+ messages: [],
359
+ },
360
+ },
361
+ };
362
+ obj.type = 'LINE';
363
+ obj.name = formData['template-name'];
364
+ obj.definition = {
365
+ mode: modeType,
366
+ };
367
+ if (modeType && modeType !== undefined) {
368
+ msgData.type = modeType;
369
+ }
370
+ if (modeType === 'text') {
371
+ if (this.state.isEdit) {
372
+ const editTemplateId = this.state.editTemplateData._id;
373
+ if (editTemplateId && editTemplateId !== undefined) {
374
+ obj._id = this.state.editTemplateData._id;
375
+ msgData.text = formData['0']['message-editor'];
376
+ }
377
+ } else {
378
+ msgData.text = formData.base['message-editor'];
379
+ }
380
+ } else if (modeType === 'image') {
381
+ const formImage = formData['0'].image;
382
+ if (formImage && formImage.length < 1) {
383
+ return 'IMAGE_ERROR';
384
+ }
385
+ if (this.state.isEdit) {
386
+ const editTemplateId = this.state.editTemplateData._id;
387
+ if (editTemplateId && editTemplateId !== undefined) {
388
+ obj._id = editTemplateId;
389
+ msgData.originalContentUrl = formData['0'].image;
390
+ msgData.previewImageUrl = formData['0'].imagePreview;
391
+ }
392
+ } else {
393
+ msgData.originalContentUrl = formData['0'].image;
394
+ msgData.previewImageUrl = formData['0'].imagePreview;
395
+ }
396
+ }
397
+ obj.versions.base.content.messages.push(msgData);
398
+ return obj;
399
+ };
400
+
401
+ getEditTransformedData = ({ name, versions }) => {
402
+ const modeType = this.state.modeType;
403
+ const obj = {};
404
+ obj['0'] = {};
405
+ obj.base = {
406
+ base: true,
407
+ };
408
+ obj['template-name'] = name;
409
+ if (modeType === 'text') {
410
+ obj.base['message-editor'] =
411
+ versions.base.content.messages[0].text;
412
+ obj['0']['message-editor'] =
413
+ versions.base.content.messages[0].text;
414
+ } else if (modeType === 'image') {
415
+ const {
416
+ base: {
417
+ content: {
418
+ messages: [{
419
+ originalContentUrl,
420
+ previewImageUrl,
421
+ }],
422
+ },
423
+ },
424
+ } = versions;
425
+ obj.base.image = originalContentUrl;
426
+ obj['0'].image = originalContentUrl;
427
+ obj['0'].imagePreview = previewImageUrl;
428
+ obj.base.imagePreview = previewImageUrl;
429
+ }
430
+ return obj;
431
+ };
432
+
433
+ setFormValidity = (isFormValid) => {
434
+ this.setState({ isFormValid });
435
+ };
436
+
437
+ getMappedEvent = (id, event) => {
438
+ const map = this.state.eventsMap;
439
+ return map[id][event];
440
+ };
441
+
442
+ getCurrentWindow(e) {
443
+ const response = {
444
+ action: e.action,
445
+ value: 'edit',
446
+ direction: e.value,
447
+ };
448
+ parent.postMessage(JSON.stringify(response), '*');
449
+ }
450
+
451
+ getFormData = (e) => {
452
+ const response = {
453
+ action: 'getFormData',
454
+ value: this.getTransformedData(this.state.formData),
455
+ validity: this.state.isFormValid,
456
+ };
457
+ this.setState({ checkValidation: true });
458
+ if (e) {
459
+ e.source.postMessage(JSON.stringify(response), e.origin);
460
+ }
461
+ return response;
462
+ };
463
+
464
+ injectEvents = (schema) => {
465
+ const temp = schema;
466
+ if (temp.standalone) {
467
+ temp.standalone.sections = this.injectSections(
468
+ temp.standalone.sections
469
+ );
470
+ }
471
+ _.forEach(temp.containers, (container) => {
472
+ let tempContainer = container;
473
+ tempContainer = this.injectContainer(tempContainer);
474
+ return tempContainer;
475
+ });
476
+ this.setState({ schema, isSchemaChanged: true }, () => {
477
+ this.removeStandAlone();
478
+ });
479
+ return schema;
480
+ };
481
+
482
+ saveFormData = () => {
483
+ const obj = this.getTransformedData(this.state.formData);
484
+ if (obj === 'IMAGE_ERROR') {
485
+ const message = getMessageObject(
486
+ 'error',
487
+ this.props.intl.formatMessage(
488
+ messages['Please upload an image to proceed']
489
+ ),
490
+ true
491
+ );
492
+ this.props.globalActions.addMessageToQueue(message);
493
+ return;
494
+ }
495
+ if (
496
+ obj !== 'IMAGE_ERROR' &&
497
+ obj.versions.base.content.messages[0].type === 'text'
498
+ ) {
499
+ const text = obj.versions.base.content.messages[0].text;
500
+ const charCount = text ? text.length : 0;
501
+ if (charCount > 1600) {
502
+ const message = getMessageObject(
503
+ 'error',
504
+ this.props.intl.formatMessage(
505
+ messages['Maximum characters length exceeds']
506
+ ),
507
+ true
508
+ );
509
+ this.props.globalActions.addMessageToQueue(message);
510
+ return;
511
+ }
512
+ }
513
+ if (!this.state.startValidation) {
514
+ this.setState({
515
+ startValidation: true,
516
+ });
517
+ } else {
518
+ const {
519
+ isFullMode,
520
+ saveMessage,
521
+ actions,
522
+ onCreateComplete,
523
+ } = this.props;
524
+ const { text, originalContentUrl, image } = get(obj, "versions.base.content.messages[0]", {});
525
+ const { name } = obj || {};
526
+ const {stopTimer} = GA.timeTracker;
527
+ const modeType = obj.definition.mode;
528
+ const type = this.state.isEdit ? TRACK_EDIT_LINE : TRACK_CREATE_LINE;
529
+ if ((text || originalContentUrl || image) && (isFullMode ? name : true)) {
530
+ if (!isFullMode) {
531
+ saveMessage();
532
+ } else if (this.state.isEdit) {
533
+ actions.editTemplate(obj, () => {
534
+ // stop timer for edit line
535
+ stopTimer(type, {
536
+ category: 'Creatives',
537
+ action: type,
538
+ label: modeType,
539
+ });
540
+ this.setEditSuccessMessage();
541
+ onCreateComplete();
542
+ });
543
+ } else {
544
+ actions.createTemplate(
545
+ obj,
546
+ () => {
547
+ // stop timer for create line
548
+ stopTimer(type, {
549
+ category: 'Creatives',
550
+ action: type,
551
+ label: modeType,
552
+ });
553
+ this.setEditSuccessMessage();
554
+ onCreateComplete();
555
+ }
556
+ );
557
+ }
558
+ }
559
+ }
560
+ };
561
+
562
+ injectSections = (sections) => {
563
+ _.forEach(sections, (section) => {
564
+ let temp = section;
565
+ if (temp.type === 'col-label') {
566
+ temp = this.injectColLabelSection(temp);
567
+ } else if (section.type === 'multicols') {
568
+ temp = this.injectMultiColSection(temp);
569
+ } else if (section.type === 'parent') {
570
+ temp = this.injectSections(temp.childSections);
571
+ }
572
+ });
573
+ return sections;
574
+ };
575
+
576
+ injectMultiColSection = (section) => {
577
+ _.forEach(section.inputFields, (inputField) => {
578
+ _.forEach(inputField.cols, (col) => {
579
+ const temp = col;
580
+ if (temp.type === 'popover') {
581
+ temp.content.sections = this.injectSections(
582
+ temp.content.sections
583
+ );
584
+ temp.value.sections = this.injectSections(temp.value.sections);
585
+ return true;
586
+ }
587
+ if (temp.id === 'discard-button') {
588
+ temp.colStyle = { ...temp.colStyle, display: 'none' };
589
+ }
590
+ if (temp.id === 'cancel-button') {
591
+ temp.offset = 11;
592
+ }
593
+ if (temp.id === 'line-push-preview') {
594
+ temp.content.appName = this.props.Templates.selectedWeChatAccount.name;
595
+ }
596
+ temp.injectedEvents = {};
597
+
598
+ _.forEach(col.supportedEvents, (event) => {
599
+ temp.injectedEvents[event] = this.getMappedEvent(
600
+ col.id,
601
+ event
602
+ );
603
+ });
604
+ return true;
605
+ });
606
+ });
607
+ _.forEach(section.actionFields, (actionField) => {
608
+ _.forEach(actionField.cols, (col) => {
609
+ const temp = col;
610
+ if (temp.type === 'popover') {
611
+ temp.content.sections = this.injectSections(
612
+ temp.content.sections
613
+ );
614
+ temp.value.sections = this.injectSections(temp.value.sections);
615
+ return true;
616
+ }
617
+ temp.injectedEvents = {};
618
+ _.forEach(col.supportedEvents, (event) => {
619
+ temp.injectedEvents[event] = this.getMappedEvent(
620
+ col.id,
621
+ event
622
+ );
623
+ });
624
+ return true;
625
+ });
626
+ });
627
+ return section;
628
+ };
629
+
630
+ injectColLabelSection = (section) => {
631
+ _.forEach(section.inputFields, (inputField) => {
632
+ const temp = inputField;
633
+ if (temp.type === 'popover') {
634
+ temp.content.sections = this.injectSections(
635
+ temp.content.sections
636
+ );
637
+ temp.value.sections = this.injectSections(temp.value.sections);
638
+ return true;
639
+ }
640
+ temp.injectedEvents = {};
641
+ _.forEach(inputField.supportedEvents, (event) => {
642
+ temp.injectedEvents[event] = this.getMappedEvent(
643
+ inputField.id,
644
+ event
645
+ );
646
+ });
647
+ return true;
648
+ });
649
+ _.forEach(section.actionFields, (actionField) => {
650
+ const temp = actionField;
651
+ if (temp.type === 'popover') {
652
+ temp.content.sections = this.injectSections(
653
+ temp.content.sections
654
+ );
655
+ temp.value.sections = this.injectSections(temp.value.sections);
656
+ return true;
657
+ }
658
+ temp.injectedEvents = {};
659
+ _.forEach(actionField.supportedEvents, (event) => {
660
+ temp.injectedEvents[event] = this.getMappedEvent(
661
+ actionField.id,
662
+ event
663
+ );
664
+ });
665
+ return true;
666
+ });
667
+ return section;
668
+ };
669
+
670
+ injectParentSection = (section) => {
671
+ _.forEach(section.childSections, (childSection) => {
672
+ let temp = childSection;
673
+ if (temp.type === 'col-label') {
674
+ temp = this.injectColLabelSection(temp);
675
+ } else if (section.type === 'multicols') {
676
+ temp = this.injectMultiColSection(temp);
677
+ } else if (section.type === 'parent') {
678
+ temp = this.injectParentSection(temp);
679
+ }
680
+ });
681
+ return section;
682
+ };
683
+
684
+ insertAtCursor = (field, myValue, currentTab) => {
685
+ //IE support
686
+ const myField = field;
687
+ if (document.selection) {
688
+ myField.focus();
689
+ const sel = document.selection.createRange();
690
+ sel.text = myValue;
691
+ } else if (
692
+ myField.selectionStart ||
693
+ myField.selectionStart === '0'
694
+ ) {
695
+ //MOZILLA and others
696
+ const startPos = myField.selectionStart;
697
+ const endPos = myField.selectionEnd;
698
+ myField.value =
699
+ myField.value.substring(0, startPos) +
700
+ myValue +
701
+ myField.value.substring(endPos, myField.value.length);
702
+ myField.selectionStart = startPos + myValue.length;
703
+ myField.selectionEnd = startPos + myValue.length;
704
+ } else {
705
+ myField.value += myValue;
706
+ }
707
+ const formData = _.cloneDeep(this.state.formData);
708
+ formData[currentTab - 1][field.id] = myField.value;
709
+ this.setState({ formData });
710
+ };
711
+
712
+ startTemplateCreation = (data) => {
713
+ const getSchemaQuery = {
714
+ layout: 'LINE',
715
+ type: 'LAYOUT',
716
+ };
717
+ this.props.globalActions.fetchSchemaForEntity(getSchemaQuery);
718
+ const content = data.content;
719
+ const obj = {};
720
+ obj['0'] = {};
721
+ obj.base = {
722
+ base: true,
723
+ };
724
+ if (data.type === 'text') {
725
+ obj.base['message-editor'] = content;
726
+ obj['0']['message-editor'] = content;
727
+ } else {
728
+ obj.base.image = content;
729
+ obj['0'].image = content;
730
+ }
731
+ this.setState({
732
+ formData: obj,
733
+ loading: false,
734
+ injectedTags: data.tags,
735
+ });
736
+ this.props.globalActions.setInjectedTags(data.tags);
737
+ };
738
+
739
+ startLoading = (ifEdit) => {
740
+ if (ifEdit) {
741
+ this.setState({ loading: true });
742
+ }
743
+ };
744
+
745
+ injectContainer = (container) => {
746
+ const temp = container;
747
+ if (temp.type === 'tabs') {
748
+ temp.injectedEvents = {};
749
+ _.forEach(temp.supportedEvents, (event) => {
750
+ temp.injectedEvents[event] = this.getMappedEvent(temp.id, event);
751
+ });
752
+ _.forEach(temp.panes, (pane) => {
753
+ const tempPane = pane;
754
+ tempPane.sectionsHeaders = this.injectSections(
755
+ tempPane.sectionsHeaders
756
+ );
757
+ tempPane.sections = this.injectSections(tempPane.sections);
758
+ });
759
+ }
760
+ return temp;
761
+ };
762
+
763
+ resetSchema = () => {
764
+ this.setState({
765
+ schema: this.state.initialState
766
+ ? this.state.initialState
767
+ : this.state.schema,
768
+ });
769
+ };
770
+
771
+ resetState = () => {
772
+ this.setState({
773
+ formData: {},
774
+ tabCount: 1,
775
+ currentTab: 1,
776
+ });
777
+ };
778
+
779
+ discardValues = () => {
780
+ this.resetSchema();
781
+ this.resetState();
782
+ };
783
+
784
+ moveToTemplates() {
785
+ const modalContent = {
786
+ title: this.props.intl.formatMessage(messages.alertMessage),
787
+ body: this.props.intl.formatMessage(messages.goBackTemporaryLost),
788
+ type: 'confirm',
789
+ id: 'template-back-confirm-modal',
790
+ show: true,
791
+ };
792
+ this.setState({ modalContent, showModal: true });
793
+ }
794
+
795
+ showNext() {
796
+ const response = {
797
+ action: 'showNext',
798
+ value: true,
799
+ };
800
+ parent.postMessage(JSON.stringify(response), '*');
801
+ }
802
+
803
+ discardValues = () => {
804
+ this.resetSchema();
805
+ this.resetState();
806
+ };
807
+
808
+ handleFrameTasks = (e) => {
809
+ const type = e.data;
810
+ if (typeof type === 'object') {
811
+ const action = type.action;
812
+ switch (action) {
813
+ case 'startTemplateCreation':
814
+ this.startTemplateCreation(type.value);
815
+ break;
816
+ case 'startLoading':
817
+ this.startLoading(type.edit);
818
+ break;
819
+ case 'getCurrentWindow':
820
+ this.getCurrentWindow(type);
821
+ break;
822
+ default:
823
+ break;
824
+ }
825
+ } else {
826
+ switch (type) {
827
+ case 'getFormData':
828
+ this.getFormData(e);
829
+ break;
830
+ case 'startTemplateCreation':
831
+ //this.getFormData(e);
832
+ break;
833
+ case 'moveToTemplates':
834
+ this.moveToTemplates();
835
+ break;
836
+ case 'validateContent':
837
+ this.validateContent(e);
838
+ break;
839
+ default:
840
+ break;
841
+ }
842
+ }
843
+ };
844
+
845
+ removeStandAlone = () => {
846
+ const schema = _.cloneDeep(this.state.schema);
847
+ const {
848
+ location: {
849
+ query: {
850
+ type,
851
+ mode,
852
+ module,
853
+ },
854
+ },
855
+ } = this.props;
856
+ if (type === 'embedded' && module === 'loyalty') {
857
+ schema.standalone.sections.splice(0, 1);
858
+ } else if (type === 'embedded' && typeof mode !== 'undefined') {
859
+ delete schema.standalone;
860
+ } else if (!this.props.isFullMode) {
861
+ const childSections = get(schema, 'standalone.sections[0].childSections');
862
+ const fields = get(childSections, '[1].childSections[0].childSections');//removing template name section
863
+ fields.splice(0, 1);
864
+ set(childSections, '[1].childSections[0].childSections', fields);
865
+ } else {
866
+ schema.standalone.sections.splice(1, 1);
867
+ }
868
+ this.setState({ schema });
869
+ };
870
+
871
+ validateContent = (e) => {
872
+ const response = {
873
+ action: 'validateContent',
874
+ value: this.state.isFormValid,
875
+ };
876
+ e.source.postMessage(JSON.stringify(response), e.origin);
877
+ };
878
+
879
+ handleOnTagsContextChange = (data) => {
880
+ const query = {
881
+ layout: 'LINE',
882
+ type: 'TAG',
883
+ context:
884
+ (data || '').toLowerCase() === 'all' ? 'default' : (data || '').toLowerCase(),
885
+ embedded:
886
+ this.props.location.query.type === 'embedded'
887
+ ? this.props.location.query.type
888
+ : 'full',
889
+ };
890
+ this.props.globalActions.fetchSchemaForEntity(query);
891
+ };
892
+
893
+ uploadImage = (pearmData) => {
894
+ const data = pearmData;
895
+ const {
896
+ file: {
897
+ size,
898
+ },
899
+ fileParams: {
900
+ height,
901
+ width,
902
+ },
903
+ type,
904
+ } = pearmData;
905
+ if (type === "wrong file" || size > LINE_IMG_SIZE || height > LINE_IMG_HEIGHT || width > LINE_IMG_WIDTH) {
906
+ CapNotification.error({
907
+ message: this.props.intl.formatMessage(
908
+ messages.lineImageIncorrectSize
909
+ ),
910
+ });
911
+ } else {
912
+ data.fileParams.isGeneratePreview = true;
913
+ this.props.actions.uploadAsset(
914
+ data.file,
915
+ data.type,
916
+ data.fileParams,
917
+ );
918
+ }
919
+ };
920
+
921
+ onGalleryImageSelect = (imageTemplate) => {
922
+ const { formData } = this.state;
923
+ const image = get(imageTemplate, 'metaInfo.secure_file_path');
924
+ const imagePreview = get(imageTemplate, 'metaInfo.secure_file_path_preview');
925
+ this.setState({
926
+ isDrawerRequired: false,
927
+ formData: {
928
+ ...formData,
929
+ 0: {
930
+ ...formData[0],
931
+ image,
932
+ imagePreview,
933
+ },
934
+ base: {
935
+ ...formData.base,
936
+ image,
937
+ imagePreview,
938
+ },
939
+ },
940
+ });
941
+ }
942
+
943
+ getGalleryDrawerContent = () => {
944
+ const location = {
945
+ pathname: `/assets`,
946
+ search: '',
947
+ query: !this.props.isFullMode ? {type: 'embedded', module: 'library'} : {},
948
+ };
949
+ const content = (
950
+ <Gallery
951
+ location={location}
952
+ isFullMode={this.props.isFullMode}
953
+ isLineAsset
954
+ onGalleryImageSelect={this.onGalleryImageSelect}
955
+ />);
956
+ return (
957
+ <>
958
+ <CapHeading type="h3">
959
+ {this.props.intl.formatMessage(messages.imageGallery)}
960
+ </CapHeading>
961
+ {content}
962
+ </>
963
+ );
964
+ };
965
+
966
+ updateSchemaWithLabels = (schema) => {
967
+ /* eslint-disable no-param-reassign */
968
+ schema.textSchema.standalone.sections[0].childSections[1].childSections[0].childSections[0].inputFields[0].cols[0].placeholder = this.props.intl.formatMessage(
969
+ messages.templatePlaceholder
970
+ );
971
+ schema.textSchema.standalone.sections[0].childSections[1].childSections[0].childSections[0].inputFields[0].cols[0].errorMessage = this.props.intl.formatMessage(
972
+ messages.templateNameErrorPlaceholder
973
+ );
974
+ schema.textSchema.standalone.sections[0].childSections[1].childSections[0].childSections[1].inputFields[0].cols[0].label = this.props.intl.formatMessage(
975
+ messages.templateAddTag
976
+ );
977
+ schema.textSchema.standalone.sections[0].childSections[1].childSections[0].childSections[2].inputFields[0].cols[0].placeholder = this.props.intl.formatMessage(
978
+ messages.templateMessagePlaceholder
979
+ );
980
+ schema.textSchema.standalone.sections[0].childSections[1].childSections[0].childSections[2].inputFields[0].cols[0].errorMessage = this.props.intl.formatMessage(
981
+ messages.templateMessageError
982
+ );
983
+ schema.imageSchema.standalone.sections[0].childSections[1].childSections[0].childSections[0].inputFields[0].cols[0].placeholder = this.props.intl.formatMessage(
984
+ messages.templatePlaceholder
985
+ );
986
+ schema.imageSchema.standalone.sections[0].childSections[1].childSections[0].childSections[0].inputFields[0].cols[0].errorMessage = this.props.intl.formatMessage(
987
+ messages.templateNameErrorPlaceholder
988
+ );
989
+ schema.imageSchema.standalone.sections[0].childSections[1].childSections[0].childSections[1].inputFields[0].cols[0].previewProps.label = this.props.intl.formatMessage(
990
+ messages.templateMessagePreviewPropsLabel
991
+ );
992
+ schema.imageSchema.standalone.sections[0].childSections[1].childSections[0].childSections[1].inputFields[0].cols[0].previewProps.inductiveText = this.props.intl.formatMessage(
993
+ messages.templateMessagePreviewPropsInductiveText
994
+ );
995
+ schema.imageSchema.standalone.sections[0].childSections[1].childSections[0].childSections[1].inputFields[0].cols[0].previewProps.errorMessage = this.props.intl.formatMessage(
996
+ messages.templateMessagePreviewPropsError
997
+ );
998
+ return schema;
999
+ };
1000
+
1001
+ stopValidation = () => {
1002
+ this.setState({
1003
+ startValidation: false,
1004
+ })
1005
+ }
1006
+
1007
+ render() {
1008
+ const {
1009
+ Line: {
1010
+ createTemplateInProgress,
1011
+ assetUploading,
1012
+ } = {},
1013
+ templateData,
1014
+ params: {
1015
+ id,
1016
+ } = {},
1017
+ isFullMode,
1018
+ } = this.props;
1019
+ const {
1020
+ edit,
1021
+ mode,
1022
+ orgId,
1023
+ isDefault,
1024
+ } = templateData || {};
1025
+ let loading = createTemplateInProgress || false;
1026
+ loading = !!assetUploading;
1027
+ if (!isDefault && (edit || mode === 'edit' || (orgId && id))) {
1028
+ const {
1029
+ base: {
1030
+ 'message-editor': msgEditor,
1031
+ image: uploadedAsset,
1032
+ } = {},
1033
+ reUpload,
1034
+ } = this.state.formData;
1035
+ loading = typeof reUpload === 'undefined' ? !(msgEditor || uploadedAsset) : !reUpload;
1036
+ if (templateData && !isFullMode) {
1037
+ const { text, originalContentUrl } = get(templateData, "versions.base.content.messages[0]", {});
1038
+ loading = !(text || originalContentUrl);
1039
+ }
1040
+ }
1041
+ let tags =
1042
+ this.props.metaEntities && this.props.metaEntities.tags
1043
+ ? this.props.metaEntities.tags.standard
1044
+ : [];
1045
+ if (this.props.supportedTags) {
1046
+ tags = this.props.supportedTags;
1047
+ }
1048
+ return (
1049
+ <CapSpin spinning={loading}>
1050
+ <CapRow>
1051
+ <CapColumn>
1052
+ <FormBuilder
1053
+ key={'form builder'}
1054
+ schema={this.state.schema}
1055
+ onSubmit={this.saveFormData}
1056
+ onChange={this.onFormDataChange}
1057
+ currentTab={this.state.currentTab}
1058
+ parent={this}
1059
+ formData={_.cloneDeep(this.state.formData)}
1060
+ location={this.props.location}
1061
+ tags={tags}
1062
+ injectedTags={
1063
+ this.props.injectedTags ? this.props.injectedTags : {}
1064
+ }
1065
+ onFormValidityChange={this.setFormValidity}
1066
+ usingTabContainer
1067
+ checkValidation={this.state.checkValidation}
1068
+ tabKey={this.state.tabKey}
1069
+ tabCount={2}
1070
+ showModal={this.state.showModal}
1071
+ isSchemaChanged={this.state.isSchemaChanged}
1072
+ modal={this.state.modalContent}
1073
+ handleCancelModal={this.handleCancelModal}
1074
+ iframeParent={parent}
1075
+ router={this.props.router}
1076
+ onContextChange={this.handleOnTagsContextChange}
1077
+ setModalContent={this.setModalContent}
1078
+ capDrawerContent={this.getGalleryDrawerContent()}
1079
+ isDrawerRequired={this.state.isDrawerRequired}
1080
+ setDrawerVisibility={(drawervisibleFlag) =>
1081
+ this.setState({ isDrawerRequired: drawervisibleFlag })
1082
+ }
1083
+ startValidation={this.state.startValidation}
1084
+ stopValidation={this.stopValidation}
1085
+ />
1086
+ </CapColumn>
1087
+ </CapRow>
1088
+ </CapSpin>
1089
+ );
1090
+ }
1091
+ }
1092
+
1093
+ Line.propTypes = {
1094
+ actions: PropTypes.object.isRequired,
1095
+ globalActions: PropTypes.object,
1096
+ Templates: PropTypes.object,
1097
+ location: PropTypes.object,
1098
+ router: PropTypes.object,
1099
+ params: PropTypes.object,
1100
+ metaEntities: PropTypes.object,
1101
+ intl: intlShape.isRequired,
1102
+ route: PropTypes.object,
1103
+ Line: PropTypes.object,
1104
+ supportedTags: PropTypes.any,
1105
+ getDefaultTags: PropTypes.string,
1106
+ injectedTags: PropTypes.object,
1107
+ onCreateComplete: PropTypes.func,
1108
+ isFullMode: PropTypes.bool,
1109
+ saveMessage: PropTypes.func,
1110
+ templateData: PropTypes.object,
1111
+ };
1112
+
1113
+ const mapStateToProps = createStructuredSelector({
1114
+ Line: makeSelectCreateLine(),
1115
+ lineData: makeSelectLine(),
1116
+ Templates: makeSelectTemplates(),
1117
+ metaEntities: makeSelectMetaEntities(),
1118
+ injectedTags: setInjectedTags(),
1119
+ });
1120
+
1121
+ function mapDispatchToProps(dispatch) {
1122
+ return {
1123
+ actions: bindActionCreators(actions, dispatch),
1124
+ };
1125
+ }
1126
+
1127
+ export default withCreatives({
1128
+ WrappedComponent: Line,
1129
+ mapStateToProps,
1130
+ mapDispatchToProps,
1131
+ userAuth: true,
1132
+ });