@capillarytech/creatives-library 6.13.1 → 6.13.3

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