@capillarytech/creatives-library 3.10.0 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/assets/lineImageTemplate.png +0 -0
  2. package/components/TemplatePreview/WechatRichmediaTemplatePreview/index.js +7 -7
  3. package/components/TemplatePreview/_templatePreview.scss +287 -20
  4. package/components/TemplatePreview/assets/images/home-screen-android.svg +21 -0
  5. package/components/TemplatePreview/assets/images/home-screen-ios.svg +16 -0
  6. package/components/TemplatePreview/assets/images/sms_mobile_android.svg +22 -0
  7. package/components/TemplatePreview/assets/images/sms_mobile_ios.svg +16 -0
  8. package/components/TemplatePreview/assets/images/wechat_mobile_android.svg +20 -0
  9. package/components/TemplatePreview/index.js +203 -31
  10. package/components/TemplatePreview/messages.js +21 -0
  11. package/containers/Assets/Gallery/index.js +53 -59
  12. package/containers/Cap/index.js +1 -0
  13. package/index.js +6 -0
  14. package/package.json +1 -1
  15. package/routes.js +5 -0
  16. package/services/getSchema.js +4 -1
  17. package/translations/en.json +40 -4
  18. package/translations/zh.json +39 -3
  19. package/v2Components/FormBuilder/index.js +188 -37
  20. package/v2Components/FormBuilder/messages.js +16 -0
  21. package/v2Components/MobilePushPreviewV2/index.js +44 -36
  22. package/v2Components/MobilePushPreviewV2/messages.js +0 -8
  23. package/v2Components/TemplatePreview/WechatRichmediaTemplatePreview/_wechatRichmediaTemplatePrev.scss +64 -0
  24. package/v2Components/TemplatePreview/WechatRichmediaTemplatePreview/index.js +100 -18
  25. package/v2Components/TemplatePreview/WechatRichmediaTemplatePreview/messages.js +12 -0
  26. package/v2Components/TemplatePreview/_templatePreview.scss +24 -4
  27. package/v2Components/TemplatePreview/assets/images/home-screen-android.svg +21 -0
  28. package/v2Components/TemplatePreview/assets/images/home-screen-ios.svg +16 -0
  29. package/v2Components/TemplatePreview/assets/images/sms_mobile_android.svg +22 -0
  30. package/v2Components/TemplatePreview/assets/images/wechat-home-screen-android.svg +21 -0
  31. package/v2Components/TemplatePreview/assets/images/wechat_mobile_android.svg +20 -0
  32. package/v2Components/TemplatePreview/index.js +162 -23
  33. package/v2Components/TemplatePreview/messages.js +8 -0
  34. package/v2Containers/Assets/Gallery/index.js +54 -48
  35. package/v2Containers/CreativesContainer/SlideBoxContent.js +87 -4
  36. package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -1
  37. package/v2Containers/CreativesContainer/index.js +58 -2
  38. package/v2Containers/CreativesContainer/messages.js +2 -2
  39. package/v2Containers/Email/_email.scss +7 -1
  40. package/v2Containers/Email/index.js +40 -14
  41. package/v2Containers/Email/messages.js +4 -0
  42. package/v2Containers/Email/reducer.js +1 -0
  43. package/v2Containers/EmailWrapper/index.js +7 -5
  44. package/v2Containers/Line/Create/_lineCreate.scss +40 -19
  45. package/v2Containers/Line/Create/actions.js +13 -9
  46. package/v2Containers/Line/Create/index.js +498 -237
  47. package/v2Containers/Line/Create/initialSchema.js +378 -0
  48. package/v2Containers/Line/Create/messages.js +42 -2
  49. package/v2Containers/Line/Create/sagas.js +10 -4
  50. package/v2Containers/Line/Create/selectors.js +3 -9
  51. package/v2Containers/Line/CreateWrapper/constants.js +2 -0
  52. package/v2Containers/Line/CreateWrapper/index.js +117 -0
  53. package/v2Containers/Line/CreateWrapper/messages.js +55 -0
  54. package/v2Containers/MobilePush/Create/index.js +5 -0
  55. package/v2Containers/MobilePush/Edit/index.js +5 -0
  56. package/v2Containers/MobilepushWrapper/index.js +4 -1
  57. package/v2Containers/Sms/Create/index.js +2 -1
  58. package/v2Containers/Sms/Edit/index.js +2 -0
  59. package/v2Containers/Templates/_templates.scss +24 -1
  60. package/v2Containers/Templates/actions.js +7 -0
  61. package/v2Containers/Templates/constants.js +2 -0
  62. package/v2Containers/Templates/index.js +118 -15
  63. package/v2Containers/Templates/messages.js +8 -0
  64. package/v2Containers/Templates/reducer.js +2 -0
  65. package/v2Containers/TemplatesV2/index.js +5 -4
  66. package/v2Containers/TemplatesV2/messages.js +4 -0
@@ -10,17 +10,114 @@ import React from 'react';
10
10
  import _ from 'lodash';
11
11
  import { injectIntl, FormattedMessage, intlShape } from 'react-intl';
12
12
  // import styled from 'styled-components';
13
- import {CapColumn, CapRow, CapHeading} from '@capillarytech/cap-ui-library';
13
+ import {CapColumn, CapRow, CapHeading, CapIcon, CapButton, CapImage} from '@capillarytech/cap-ui-library';
14
14
  import './_templatePreview.scss';
15
15
  import {updateCharCount} from '../../utils/smsCharCountV2';
16
16
  import messages from './messages';
17
- const smsIcon = require('./assets/images/user-icon.svg');
18
- const wechatBody = require('./assets/images/WECHAT_5x.png');
19
- const smsBody = require('./assets/images/mobile.svg');
17
+ import { WECHAT } from '../../v2Containers/CreativesContainer/constants';
18
+ const wechatBodyNew = require('./assets/images/wechat_mobile_android.svg');
19
+ const smsMobileAndroid = require('./assets/images/sms_mobile_android.svg');
20
20
  const androidPushMessagePhone = require('./assets/images/androidPushMessage.svg');
21
21
  const iPhonePushMessagePhone = require('./assets/images/iPhonePushMessage.svg');
22
22
 
23
23
  class TemplatePreview extends React.Component { // eslint-disable-line react/prefer-stateless-function
24
+ onPreviewContentClicked = (channel) => {
25
+ const IOSContent = (this.props.templateDataRaw && this.props.templateDataRaw.versions.base.IOS) ||
26
+ ((this.props.device === 'iphone' || this.props.device === 'ios') && this.props.content);
27
+ const ANDROIDContent = (this.props.templateDataRaw && this.props.templateDataRaw.versions.base.ANDROID) ||
28
+ (this.props.device === 'android' && this.props.content);
29
+ const mobilePushPreviewContent = [];
30
+ if (this.props.channel === 'MOBILEPUSH') {
31
+ const previewObj = {
32
+ channel: this.props.channel,
33
+ accountId: this.props.templateDataRaw && this.props.templateDataRaw.definition.accountId,
34
+ messageSubject: this.props.templateDataRaw && this.props.templateDataRaw.name,
35
+ id: 'message_content_id_1',
36
+ };
37
+ if (IOSContent) {
38
+ previewObj.iosContent = {
39
+ title: IOSContent.title || IOSContent.header,
40
+ message: IOSContent.message || IOSContent.bodyText,
41
+ deviceType: "IOS",
42
+ expandableDetails: IOSContent.expandableDetails ||
43
+ {
44
+ style: "BIG_PICTURE",
45
+ image: this.props.content.bodyImage,
46
+ message: this.props.content.bodyText,
47
+ },
48
+ };
49
+ }
50
+ if (ANDROIDContent) {
51
+ previewObj.androidContent = {
52
+ title: ANDROIDContent.title || ANDROIDContent.header,
53
+ message: ANDROIDContent.message || ANDROIDContent.bodyText,
54
+ deviceType: "ANDROID",
55
+ expandableDetails: ANDROIDContent.expandableDetails ||
56
+ {
57
+ style: "BIG_PICTURE",
58
+ image: this.props.content.bodyImage,
59
+ message: this.props.content.bodyText,
60
+ },
61
+ };
62
+ }
63
+ mobilePushPreviewContent.push(previewObj);
64
+ }
65
+ const previewContent = this.props.channel === 'MOBILEPUSH' ? mobilePushPreviewContent : this.props.content;
66
+ const params = {
67
+ content: previewContent,
68
+ channel,
69
+ };
70
+ this.props.onPreviewContentClicked(params);
71
+ };
72
+
73
+ onTestContentClicked = (channel) => {
74
+ let mobilePushPreviewContent = {};
75
+ const IOSContent = (this.props.templateDataRaw && this.props.templateDataRaw.versions.base.IOS) ||
76
+ ((this.props.device === 'iphone' || this.props.device === 'ios') && this.props.content);
77
+ const ANDROIDContent = (this.props.templateDataRaw && this.props.templateDataRaw.versions.base.ANDROID) ||
78
+ (this.props.device === 'android' && this.props.content);
79
+ if (this.props.channel === 'MOBILEPUSH') {
80
+ mobilePushPreviewContent = {
81
+ channel: this.props.channel,
82
+ accountId: this.props.templateDataRaw && this.props.templateDataRaw.definition.accountId,
83
+ messageSubject: this.props.templateDataRaw && this.props.templateDataRaw.name,
84
+ id: 'message_content_id_1',
85
+ };
86
+ if (ANDROIDContent) {
87
+ mobilePushPreviewContent.androidContent = {
88
+ title: ANDROIDContent.title || ANDROIDContent.header,
89
+ message: ANDROIDContent.message || ANDROIDContent.bodyText,
90
+ deviceType: "ANDROID",
91
+ expandableDetails: ANDROIDContent.expandableDetails ||
92
+ {
93
+ style: "BIG_PICTURE",
94
+ image: this.props.content.bodyImage,
95
+ message: this.props.content.bodyText,
96
+ },
97
+ };
98
+ }
99
+ if (IOSContent) {
100
+ mobilePushPreviewContent.iosContent = {
101
+ title: IOSContent.title || IOSContent.header,
102
+ message: IOSContent.message || IOSContent.bodyText,
103
+ deviceType: "IOS",
104
+ expandableDetails: IOSContent.expandableDetails ||
105
+ {
106
+ style: "BIG_PICTURE",
107
+ image: this.props.content.bodyImage,
108
+ message: this.props.content.bodyText,
109
+ },
110
+ };
111
+ }
112
+ }
113
+ const previewContent = this.props.channel === 'MOBILEPUSH' ? mobilePushPreviewContent : this.props.content;
114
+ const params = {
115
+ content: previewContent,
116
+ channel,
117
+ };
118
+ this.props.onTestContentClicked(params);
119
+ };
120
+
24
121
  render() {
25
122
  let content = channel && channel.toLowerCase() === 'sms' ? [this.props.content] : this.props.content;
26
123
  const channel = this.props.channel;
@@ -50,6 +147,7 @@ class TemplatePreview extends React.Component { // eslint-disable-line react/pre
50
147
  return undefined;
51
148
  });
52
149
  }
150
+ const disablePreviewAndTest = this.props.channel === 'MOBILEPUSH' ? !this.props.content.header : (this.props.channel === 'SMS' ? !this.props.content : false);
53
151
  return (
54
152
  <CapRow>
55
153
  {this.props.showCount && <CapColumn span={16}>
@@ -64,16 +162,45 @@ class TemplatePreview extends React.Component { // eslint-disable-line react/pre
64
162
  </CapHeading>}
65
163
  </CapColumn>}
66
164
  <CapColumn span={this.props.showCount ? 8 : 24}>
165
+ {this.props.showTestAndPreviewIcon && this.props.channel !== WECHAT && (
166
+ <div className="test-and-preview-container">
167
+ <CapButton
168
+ style={{
169
+ color: '#2466ea',
170
+ display: 'inline-block',
171
+ padding: '0 6px',
172
+ marginTop: '12px',
173
+ }}
174
+ type="flat"
175
+ onClick={() => this.onPreviewContentClicked(this.props.channel)}
176
+ disabled={disablePreviewAndTest}
177
+ >
178
+ <CapIcon type="eye"/><FormattedMessage {...messages.preview} />
179
+ </CapButton>
180
+ <CapButton
181
+ style={{
182
+ color: '#2466ea',
183
+ display: 'inline-block',
184
+ padding: '0 6px',
185
+ marginTop: '12px',
186
+ }}
187
+ type="flat"
188
+ onClick={() => this.onTestContentClicked(this.props.channel)}
189
+ disabled={disablePreviewAndTest}
190
+ >
191
+ <CapIcon type="lab"/><FormattedMessage {...messages.testMessage} />
192
+ </CapButton>
193
+ </div>
194
+ )}
67
195
  <div className={`preview-container ${type === 'embedded' ? 'embedded-preview' : ''}`}>
68
196
  { channel && channel.toLowerCase() === 'sms' &&
69
197
  <div>
70
- <div className="shell align-center" id="sms-preview">
71
- <img className="preview-image sms" src={smsBody} alt="Preview is being generated"/>
198
+ <div className="shell-v2 align-center" id="sms-preview">
199
+ <CapImage className="preview-image sms" src={smsMobileAndroid} alt="Preview is being generated"/>
72
200
  <div className="msgContainer sms">
73
- <img className="sms-icon" src={smsIcon} alt="Sms icon" />
74
201
  <div className={"message-pop sms"}>
75
202
  {content && content.length && content.map((msg, index) =>
76
- <CapColumn key={`"message-pop-content-${index}`} className="message-pop-item align-left" style={{ background: '#3F51B5', color: '#ffffff'}}>
203
+ <CapColumn key={`"message-pop-content-${index}`} className="message-pop-item align-left" style={{ background: '#FFFFFF', color: '#091e42'}}>
77
204
  {msg}
78
205
  </CapColumn>)
79
206
  }
@@ -96,10 +223,9 @@ class TemplatePreview extends React.Component { // eslint-disable-line react/pre
96
223
  </div>
97
224
  }
98
225
  {channel && channel.toLowerCase() === 'wechat' ?
99
- ( <div className="shell align-center" id="sms-preview">
100
- <img className="preview-image" src={channel.toLowerCase() === 'wechat' ? wechatBody : smsBody} alt="Preview is being generated"/>
101
- <div className="msgContainer">
102
- {this.props.channel.toLowerCase() === 'wechat' ? <div className="sms-icon" style={{ width: '25px', height: '25px', background: '#2E89DF' }}></div> : <img className="sms-icon" src={smsIcon} alt={this.props.intl.formatMessage(messages.smsIcon)} />}
226
+ ( <div className="shell-v2 align-center" id="sms-preview">
227
+ <CapImage className="preview-image" src={channel.toLowerCase() === 'wechat' ? wechatBodyNew : smsMobileAndroid} alt="Preview is being generated"/>
228
+ <div className="msgContainer wechat">
103
229
  <div className="message-pop align-left" style={{ background: `${this.props.channel.toLowerCase() === 'wechat' ? '#ffffff' : '#3F51B5'}`, color: `${this.props.channel.toLowerCase() === 'wechat' ? '#333333' : '#ffffff'}`}}>{content}
104
230
  </div>
105
231
  </div>
@@ -107,10 +233,10 @@ class TemplatePreview extends React.Component { // eslint-disable-line react/pre
107
233
  ) : ''
108
234
  }
109
235
  { channel && (channel.toLowerCase() === 'mobilepush') &&
110
- (<div className="shell align-center" id="mobilepush-preview">
111
- <img className="preview-image" src={this.props.device === "android" ? androidPushMessagePhone : iPhonePushMessagePhone} alt={this.props.intl.formatMessage(messages.previewGenerated)}/>
236
+ (<div className="shell-v2 align-center" id="mobilepush-preview">
237
+ <CapImage className="preview-image" src={this.props.device === "android" ? androidPushMessagePhone : iPhonePushMessagePhone} alt={this.props.intl.formatMessage(messages.previewGenerated)}/>
112
238
  {(!!content.header || !!content.bodyText || !!content.bodyImage) &&
113
- <div className={`${this.props.device}-push-message-Container`}>
239
+ <div className={`${this.props.device === 'ios' ? 'iphone' : this.props.device}-push-message-Container`}>
114
240
  {this.props.device === "android" ?
115
241
  <div className="message-pop align-left">
116
242
  <div className="app-name">
@@ -123,7 +249,7 @@ class TemplatePreview extends React.Component { // eslint-disable-line react/pre
123
249
  {content.bodyText}
124
250
  </div>
125
251
  {content.bodyImage && <div className="body-image">
126
- <img src={content.bodyImage} alt="" />
252
+ <CapImage src={content.bodyImage} alt="" />
127
253
  </div>}
128
254
  {content.actions.filter((action) => action.label).length ?
129
255
  <div className="actions">
@@ -138,7 +264,7 @@ class TemplatePreview extends React.Component { // eslint-disable-line react/pre
138
264
  <span className="app-icon"></span>{content.appName ? content.appName : "App name"} <i className="material-icons">{this.props.intl.formatMessage(messages.close)}</i>
139
265
  </div>
140
266
  {content.bodyImage && <div className="body-image">
141
- <img src={content.bodyImage} alt=""/>
267
+ <CapImage src={content.bodyImage} alt=""/>
142
268
  </div>}
143
269
  <div className="title">
144
270
  {content.header}
@@ -156,13 +282,22 @@ class TemplatePreview extends React.Component { // eslint-disable-line react/pre
156
282
  }
157
283
  {
158
284
  channel && channel.toLowerCase() === 'line' ? (
159
- <div className="shell align-center" id="sms-preview">
160
- <img className="preview-image" src={wechatBody} alt={this.props.intl.formatMessage(messages.previewGenerated)}/>
161
- <div className="msgContainer">
162
- <div className="sms-icon" style={{ width: '25px', height: '25px', background: '#2E89DF' }}></div>
285
+ <div className="shell-v2 align-center" id="sms-preview">
286
+ <CapImage className="preview-image" src={wechatBodyNew} alt={this.props.intl.formatMessage(messages.previewGenerated)}/>
287
+ <div className="msgContainer line-preview">
288
+ <div className="sms-icon" style={{ left: 10, borderRadius: '50%', width: '20px', height: '20px', background: '#2E89DF' }}></div>
163
289
  <div className="message-pop align-left" style={{ background: '#ffffff', color: '#333333' }}>
164
- { (content && content.bodyImage) ? <img src={content.bodyImage} alt="ddd" style={{maxWidth: '100%'}}/> : '' }
165
- { (content && content.bodyText) ? content.bodyText : ''}
290
+ {
291
+ content && Object.keys(content).map((item) => {
292
+ if (item === 'bodyText' && content[item]) {
293
+ return content[item];
294
+ }
295
+ if (item === 'bodyImage' && content[item]) {
296
+ return <CapImage src={content[item]} alt="brand-name" style={{maxWidth: '100%'}}/>;
297
+ }
298
+ return null;
299
+ })
300
+ }
166
301
  </div>
167
302
  </div>
168
303
  { (content && content.bodyText) ? <p style={{fontSize: 16, fontWeight: "bold"}}>Chars Count: {content.bodyText.length} / (1600)</p> : '' }
@@ -189,6 +324,10 @@ TemplatePreview.propTypes = {
189
324
  unicodeEnabled: PropTypes.bool,
190
325
  showCount: PropTypes.bool,
191
326
  intl: intlShape.isRequired,
327
+ templateDataRaw: PropTypes.object,
328
+ onPreviewContentClicked: PropTypes.func,
329
+ onTestContentClicked: PropTypes.func,
330
+ showTestAndPreviewIcon: PropTypes.bool,
192
331
  };
193
332
 
194
333
  export default (injectIntl(TemplatePreview));
@@ -50,4 +50,12 @@ export default defineMessages({
50
50
  id: 'creatives.componentsV2.TemplatePreview.smsIcon',
51
51
  defaultMessage: 'Sms Icon',
52
52
  },
53
+ preview: {
54
+ id: 'creatives.componentsV2.TemplatePreview.preview',
55
+ defaultMessage: 'Preview',
56
+ },
57
+ testMessage: {
58
+ id: 'creatives.componentsV2.TemplatePreview.testMessage',
59
+ defaultMessage: 'Test Message',
60
+ },
53
61
  });
@@ -81,7 +81,7 @@ export class Gallery extends React.Component { // eslint-disable-line react/pref
81
81
  const params = {
82
82
  name: this.state.searchText,
83
83
  };
84
- this.getAllAssets({params});
84
+ this.getAllAssets({params, resetPage: true});
85
85
  }
86
86
  if (!this.props.Gallery.fetchingAllAssets && !_.isEmpty(this.props.Gallery.assetList) && this.props.Gallery.assetList[0] && this.props.Gallery.assetList[0].totalCount && this.state.totalCount === 0) {
87
87
  this.setState({totalCount: this.props.Gallery.assetList[0].totalCount});
@@ -98,19 +98,12 @@ export class Gallery extends React.Component { // eslint-disable-line react/pref
98
98
  name: this.state.searchText,
99
99
  sortBy: 'Most Recent',
100
100
  };
101
- this.getAllAssets({params});
101
+ this.getAllAssets({params, resetPage: true});
102
102
  }
103
103
  if (!nextProps.Gallery.deletingAsset && nextProps.Gallery.assetDeleteError && !_.isEqual(nextProps.Gallery.deletingAsset, this.props.Gallery.deletingAsset)) {
104
104
  const message = getMessageObject('error', this.props.intl.formatMessage(messages.assetDeleteFailed), true);
105
105
  this.props.globalActions.addMessageToQueue(message);
106
106
  }
107
- if ( nextProps.Gallery.itemDeleted || !nextProps.Gallery.assetUploading) {
108
- const params = {
109
- name: this.state.searchText,
110
- sortBy: 'Most Recent',
111
- };
112
- this.getAllAssets({params}, true);
113
- }
114
107
  }
115
108
 
116
109
  componentWillUnmount() {
@@ -236,18 +229,20 @@ export class Gallery extends React.Component { // eslint-disable-line react/pref
236
229
  uploadImages(e, {files}) {
237
230
  e.preventDefault();
238
231
  const _URL = window.URL || window.webkitURL;
239
- //const file = files[0];
240
232
  for (const file in files) {
241
- const img = new Image();
242
- const that = this;
243
- img.src = _URL.createObjectURL(files[file]);
244
- img.onload = function () {
245
- const fileParams = {
246
- width: this.width,
247
- height: this.height,
233
+ if (files.hasOwnProperty(file)) {
234
+ const img = new Image();
235
+ const that = this;
236
+ img.src = _URL.createObjectURL(files[file]);
237
+ img.onload = function () {
238
+ const fileParams = {
239
+ width: this.width,
240
+ height: this.height,
241
+ isGeneratePreview: true,
242
+ };
243
+ that.props.actions.uploadAsset(files[file], 'image', fileParams);
248
244
  };
249
- that.props.actions.uploadAsset(files[file], 'image', fileParams);
250
- };
245
+ }
251
246
  }
252
247
  }
253
248
  getIllustrationProps={
@@ -316,29 +311,34 @@ export class Gallery extends React.Component { // eslint-disable-line react/pref
316
311
  {
317
312
  key: `${currentChannel}-card-${template.name}`,
318
313
  title: <span title={template.name} >{template.name}</span>,
319
- extra: [
320
- <CapIcon
321
- className="view-gallery"
322
- style={{marginRight: '16px'}}
323
- type="eye"
324
- onClick={() => { this.openPreviewMode(template); }}
325
- />,
326
- <CapDropdown
327
- overlay={
328
- <CapMenu>
329
- <CapMenu.Item className="delete-gallery" onClick={() => this.deleteAsset(template)}>
330
- <FormattedMessage {...messages.delete} />
331
- </CapMenu.Item>
332
- </CapMenu>
333
- }
334
- >
335
- <CapIcon type="more" />
336
- </CapDropdown>,
337
- ],
338
314
  };
315
+ if (!this.props.isLineAsset) {
316
+ templateData.extra = [
317
+ <CapIcon
318
+ className="view-gallery"
319
+ style={{marginRight: '16px'}}
320
+ type="eye"
321
+ onClick={() => { this.openPreviewMode(template); }}
322
+ />,
323
+ <CapDropdown
324
+ overlay={
325
+ <CapMenu>
326
+ <CapMenu.Item className="delete-gallery" onClick={() => this.deleteAsset(template)}>
327
+ <FormattedMessage {...messages.delete} />
328
+ </CapMenu.Item>
329
+ </CapMenu>
330
+ }
331
+ >
332
+ <CapIcon type="more" />
333
+ </CapDropdown>,
334
+ ];
335
+ }
339
336
  if (!this.props.isFullMode) {
340
337
  templateData.hoverOption = <CapButton onClick={(e) => handlers.selectAsset(e, template._id)}><FormattedMessage {...messages.select} /></CapButton>;
341
338
  }
339
+ if (this.props.isLineAsset) {
340
+ templateData.hoverOption = <CapButton onClick={() => this.props.onGalleryImageSelect(template)}><FormattedMessage {...messages.select} /></CapButton>;
341
+ }
342
342
  const secureFilePath = _.get(template, 'metaInfo.secure_file_path');
343
343
  templateData.url = secureFilePath || _.get(template, 'metaInfo.public_url');
344
344
  return templateData;
@@ -347,7 +347,7 @@ export class Gallery extends React.Component { // eslint-disable-line react/pref
347
347
  {filterContent}
348
348
  <CapSpin spinning={isLoading} tip={loadingTip} style={{width: "100%"}}>
349
349
  {!isLoading && <div>
350
- {!_.isEmpty(templates) || !_.isEmpty(searchText) ? <div className="pagination-container">
350
+ {!_.isEmpty(templates) || !_.isEmpty(searchText) ? <div className={`pagination-container ${this.props.isLineAsset ? 'gallery-upload' : ''}`}>
351
351
  <CapCustomCardList key={`${currentChannel}-card-list`} cardList={cardDataList} type={'Email'} />
352
352
  {!_.isEmpty(searchText) && _.isEmpty(templates) && (
353
353
  <div style={{ height: '65vh', textAlign: 'center', lineHeight: '65vh'}}>
@@ -421,21 +421,25 @@ export class Gallery extends React.Component { // eslint-disable-line react/pref
421
421
  <div style={{ marginTop: '8px', width: '50%'}}>
422
422
  <CapInput.Search
423
423
  className="search-text"
424
- style={{width: '210px'}}
424
+ style={{width: `${this.props.isLineAsset ? '324px' : '210px'}`}}
425
425
  placeholder={this.props.intl.formatMessage(messages.search)}
426
426
  value={this.state.searchText}
427
427
  onChange={(e) => this.searchAsset(e.target.value)}
428
428
  onClear={() => this.searchAsset('')}
429
429
  />
430
430
  </div>
431
- <div style={{ textAlign: 'right', marginTop: '16px', width: '50%'}}>
432
- <form encType="multipart/form-data" id="myForm">
433
- <input style={{ display: 'none'}} id="fileName" type="file" onChange={(e) => this.uploadImages(e, {files: e.target.files})} accept="image/*" multiple/>
434
- <CapButton className="upload-image-gallery" type={this.props.location.query.type !== 'embedded' ? 'primary' : 'secondary'} onClick={(e) => this.openFileDialog(e)} style={{float: 'right'}}>
435
- <FormattedMessage {...messages.upload} />
436
- </CapButton>
437
- </form>
438
- </div>
431
+ {
432
+ !this.props.isLineAsset && (
433
+ <div style={{ textAlign: 'right', marginTop: '16px', width: '50%'}}>
434
+ <form encType="multipart/form-data" id="myForm">
435
+ <input style={{ display: 'none'}} id="fileName" type="file" onChange={(e) => this.uploadImages(e, {files: e.target.files})} accept="image/*" multiple/>
436
+ <CapButton className="upload-image-gallery" type={this.props.location.query.type !== 'embedded' ? 'primary' : 'secondary'} onClick={(e) => this.openFileDialog(e)} style={{float: 'right'}}>
437
+ <FormattedMessage {...messages.upload} />
438
+ </CapButton>
439
+ </form>
440
+ </div>
441
+ )
442
+ }
439
443
  </div>
440
444
  ) : <input style={{ display: 'none'}} id="fileName" type="file" onChange={(e) => this.uploadImages(e, {files: e.target.files})} accept="image/*" multiple/>;
441
445
  const isLoading = this.props.Gallery.assetUploading || this.props.Gallery.fetchingAllAssets;
@@ -496,6 +500,8 @@ Gallery.propTypes = {
496
500
  location: PropTypes.object,
497
501
  intl: intlShape.isRequired,
498
502
  isFullMode: PropTypes.bool,
503
+ isLineAsset: PropTypes.bool,
504
+ onGalleryImageSelect: PropTypes.func,
499
505
  };
500
506
 
501
507
  const mapStateToProps = createStructuredSelector({
@@ -11,12 +11,14 @@ import EmailWrapper from '../EmailWrapper';
11
11
  import MobilepushWrapper from '../MobilepushWrapper';
12
12
  import EmailPreviewV2 from '../../v2Components/EmailPreviewV2';
13
13
  import MobilePushPreview from '../../v2Components/MobilePushPreviewV2';
14
+ import LineEdit from '../Line/Create';
14
15
  import WechatWrapper from '../WeChat/Wrapper';
15
16
  import Facebook from '../Facebook';
16
17
  import { RICH_MEDIA, MAP_TEMPLATE, CREATE } from '../WeChat/Wrapper/constants';
17
18
  import CallTask from '../CallTask';
18
19
  import MobliPushEdit from '../MobilePush/Edit';
19
20
  import * as constants from './constants';
21
+ import CreateLineWrapper from '../Line/CreateWrapper';
20
22
  const CreativesWrapper = styled.div`
21
23
  .ant-popover,
22
24
  .ant-notification,
@@ -41,6 +43,7 @@ function SlideBoxContent(props) {
41
43
  location,
42
44
  isGetFormData,
43
45
  getFormData,
46
+ onCreateComplete,
44
47
  messageDetails,
45
48
  onCreateNew,
46
49
  currentChannel,
@@ -69,7 +72,11 @@ function SlideBoxContent(props) {
69
72
  selectedWeChatAccount,
70
73
  weChatMaptemplateStep,
71
74
  onWeChatMaptemplateStepChange,
75
+ onTestContentClicked,
76
+ onPreviewContentClicked,
72
77
  onFacebookSubmit,
78
+ saveMessage,
79
+ selectedAccount,
73
80
  } = props;
74
81
  const type = messageDetails.type.toLowerCase(); // type is context in get tags values : outbound | dvs | referral | loyalty | coupons
75
82
  const query = { type: !isFullMode && 'embedded', module: isFullMode ? 'default' : 'library', isEditFromCampaigns: (templateData || {}).isEditFromCampaigns};
@@ -80,9 +87,11 @@ function SlideBoxContent(props) {
80
87
  };
81
88
  let channel = currentChannel;//for create mode
82
89
  const isCreateSms = slidBoxContent === 'createTemplate' && channel === constants.SMS;
90
+ const isCreateLine = slidBoxContent === 'createTemplate' && channel === constants.LINE;
83
91
  const isCreateMPush = slidBoxContent === 'createTemplate' && channel === constants.MOBILE_PUSH;
84
92
  const isCreateCallTask = slidBoxContent === 'createTemplate' && channel === constants.CALL_TASK;
85
93
  let isEditSms = false;
94
+ let isEditLine = false;
86
95
  let isEditEmailWithId = false;
87
96
  let isEmailEditWithContent = false;
88
97
  let isPreview = false;
@@ -95,16 +104,42 @@ function SlideBoxContent(props) {
95
104
  if (templateData && channel) {
96
105
  channel = templateData.type;// for edit mode with template data
97
106
  isEditSms = slidBoxContent === 'editTemplate' && channel === constants.SMS;
107
+ isEditLine = slidBoxContent === 'editTemplate' && channel === constants.LINE;
98
108
  isEditCallTask = slidBoxContent === 'editTemplate' && channel === constants.CALL_TASK;
99
109
  isEditMPush = slidBoxContent === 'editTemplate' && channel === constants.MOBILE_PUSH;
100
110
  isEditEmailWithId = slidBoxContent === 'editTemplate' && channel === constants.EMAIL && templateData._id;
101
111
  isEmailEditWithContent = slidBoxContent === 'editTemplate' && channel === constants.EMAIL && !templateData._id;
102
112
  isEditFacebook = slidBoxContent === 'editTemplate' && channel === constants.FACEBOOK;
103
- isPreview = slidBoxContent === 'preview' && channel === constants.SMS;
113
+ isPreview = slidBoxContent === 'preview' && (channel === constants.SMS || channel === constants.LINE);
104
114
  isEmailPreview = slidBoxContent === 'preview' && channel === constants.EMAIL;
105
115
  isMpushPreview = slidBoxContent === 'preview' && channel === constants.MOBILE_PUSH;
106
116
  }
107
117
 
118
+ const getChannelPreviewContent = (templateDataObject) => {
119
+ switch (templateDataObject.type.toUpperCase()) {
120
+ case constants.SMS:
121
+ return get(templateDataObject, `versions.base['sms-editor']`);
122
+ case constants.LINE: {
123
+ const content = get(templateDataObject, `versions.base.content.messages[0]`, {});
124
+ let previewContent = {};
125
+ if (content.text) {
126
+ previewContent = {
127
+ bodyText: content.text,
128
+ };
129
+ }
130
+ if (content.originalContentUrl) {
131
+ previewContent = {
132
+ ...previewContent,
133
+ bodyImage: content.previewImageUrl,
134
+ };
135
+ }
136
+ return previewContent;
137
+ }
138
+ default:
139
+ return get(templateDataObject, `versions.base.content`);
140
+ }
141
+ };
142
+
108
143
  return (
109
144
  <CreativesWrapper>
110
145
  {!isFullMode && slidBoxContent === 'templates' && (
@@ -127,10 +162,10 @@ function SlideBoxContent(props) {
127
162
  )}
128
163
  {isPreview && (
129
164
  <TemplatePreview
130
- content={templateData.type.toUpperCase() === constants.SMS ? get(templateData, `versions.base['sms-editor']`) : get(templateData, `versions.base.content`)}
165
+ content={getChannelPreviewContent(templateData)}
131
166
  unicodeEnabled={get(templateData, `versions.base['unicode-validity']`)}
132
167
  channel={templateData.type.toLowerCase()}
133
- charCounterEnabled
168
+ charCounterEnabled={channel === constants.SMS}
134
169
  templateData={templateData}
135
170
  showCount
136
171
  forwardedTags={forwardedTags}
@@ -185,6 +220,8 @@ function SlideBoxContent(props) {
185
220
  templateData={templateData}
186
221
  forwardedTags={forwardedTags}
187
222
  selectedOfferDetails={selectedOfferDetails}
223
+ onPreviewContentClicked={onPreviewContentClicked}
224
+ onTestContentClicked={onTestContentClicked}
188
225
  />
189
226
  )}
190
227
  {
@@ -218,6 +255,8 @@ function SlideBoxContent(props) {
218
255
  isFullMode={isFullMode}
219
256
  forwardedTags={forwardedTags}
220
257
  selectedOfferDetails={selectedOfferDetails}
258
+ onPreviewContentClicked={onPreviewContentClicked}
259
+ onTestContentClicked={onTestContentClicked}
221
260
  />
222
261
  )}
223
262
  {isEmailCreate && (
@@ -240,6 +279,8 @@ function SlideBoxContent(props) {
240
279
  onValidationFail={onValidationFail}
241
280
  forwardedTags={forwardedTags}
242
281
  selectedOfferDetails={selectedOfferDetails}
282
+ onPreviewContentClicked={onPreviewContentClicked}
283
+ onTestContentClicked={onTestContentClicked}
243
284
  />
244
285
  )}
245
286
  {(isEditEmailWithId || isEmailEditWithContent) && (
@@ -263,6 +304,8 @@ function SlideBoxContent(props) {
263
304
  onValidationFail={onValidationFail}
264
305
  forwardedTags={forwardedTags}
265
306
  selectedOfferDetails={selectedOfferDetails}
307
+ onPreviewContentClicked={onPreviewContentClicked}
308
+ onTestContentClicked={onTestContentClicked}
266
309
  />
267
310
  )}
268
311
  {isEditMPush &&
@@ -283,6 +326,8 @@ function SlideBoxContent(props) {
283
326
  onValidationFail={onValidationFail}
284
327
  forwardedTags={forwardedTags}
285
328
  selectedOfferDetails={selectedOfferDetails}
329
+ onPreviewContentClicked={onPreviewContentClicked}
330
+ onTestContentClicked={onTestContentClicked}
286
331
  />
287
332
  }
288
333
  {isCreateMPush &&
@@ -307,7 +352,9 @@ function SlideBoxContent(props) {
307
352
  query={query}
308
353
  forwardedTags={forwardedTags}
309
354
  onValidationFail={onValidationFail}
310
- selectedOfferDetails={selectedOfferDetails}/>
355
+ selectedOfferDetails={selectedOfferDetails}
356
+ onPreviewContentClicked={onPreviewContentClicked}
357
+ onTestContentClicked={onTestContentClicked}/>
311
358
  }
312
359
  {
313
360
  isEditFacebook && (
@@ -319,6 +366,39 @@ function SlideBoxContent(props) {
319
366
  />
320
367
  )
321
368
  }
369
+ {
370
+ isEditLine && (
371
+ <LineEdit
372
+ location={creativesLocationProps}
373
+ params={{
374
+ id: templateData._id,
375
+ mode: templateData.modeType || (templateData.definition && templateData.definition.mode),
376
+ }}
377
+ route={{ name: (templateData.modeType || (templateData.definition && templateData.definition.mode)) === 'image' ? 'edit_image' : 'edit_text' }}
378
+ onCreateComplete={onCreateComplete}
379
+ isFullMode={isFullMode}
380
+ saveMessage={saveMessage}
381
+ getFormSubscriptionData={getFormData}
382
+ isGetFormData={isGetFormData}
383
+ templateData={templateData}
384
+ selectedAccount={selectedAccount}
385
+ />
386
+ )
387
+ }
388
+ {
389
+ isCreateLine && (
390
+ <CreateLineWrapper
391
+ location={creativesLocationProps}
392
+ onCreateComplete={onCreateComplete}
393
+ isFullMode={isFullMode}
394
+ isGetFormData={isGetFormData}
395
+ saveMessage={saveMessage}
396
+ selectedAccount={selectedAccount}
397
+ templateData={templateData}
398
+ getFormSubscriptionData={getFormData}
399
+ />
400
+ )
401
+ }
322
402
  </CreativesWrapper>
323
403
  );
324
404
  }
@@ -359,5 +439,8 @@ SlideBoxContent.propTypes = {
359
439
  onWeChatMaptemplateStepChange: PropTypes.func,
360
440
  weChatMaptemplateStep: PropTypes.string,
361
441
  onFacebookSubmit: PropTypes.func,
442
+ onCreateComplete: PropTypes.func,
443
+ saveMessage: PropTypes.func,
444
+ selectedAccount: PropTypes.object,
362
445
  };
363
446
  export default SlideBoxContent;
@@ -48,7 +48,7 @@ function SlideBoxHeader(props) {
48
48
  )}
49
49
  {!showTemplateNameHeader && slidBoxContent === 'editTemplate' && (
50
50
  <CapHeader
51
- title={<FormattedMessage {...messages.editMessageContent} />}
51
+ title={<FormattedMessage {...messages.editMessageContent} values={{channel: getChannelLabel(channel)}}/>}
52
52
  prefix={creativesMode !== 'edit' && !isFullMode && showPrefix &&
53
53
  <PrefixWrapper>
54
54
  <CapIcons.backIcon onClick={onShowTemplates} />