@capillarytech/creatives-library 7.2.1 → 7.3.1

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.
@@ -20,6 +20,10 @@ export const TRACK_CREATE_WECHAT = 'createWeChat';
20
20
  export const TRACK_CREATE_IMAGE = 'createImage';
21
21
  export const TRACK_CREATE_LINE = 'createLine';
22
22
 
23
+ export const CREATE = 'create';
24
+ export const EDIT = 'edit';
25
+ export const PREVIEW = 'preview';
26
+
23
27
  export const VIBER = 'viber';
24
28
  export const TRACK_EDIT_SMS = 'editSms';
25
29
  export const TRACK_EDIT_EMAIL = 'editEmail';
@@ -47,5 +51,5 @@ export const CHANNEL_EDIT_TRACK_MAPPING = {
47
51
  };
48
52
  export const GTM_TRACKING_ID = 'UA-110024621-2';
49
53
  export const BEE_PLUGIN = 'BEE_PLUGIN';
50
-
54
+ export const NO_COMMUNICATION = 'NO_COMMUNICATION';
51
55
  export const CREATIVES_UI_VIEW = 'CREATIVES_UI_VIEW';
@@ -19,6 +19,7 @@ import CallTask from '../CallTask';
19
19
  import MobliPushEdit from '../MobilePush/Edit';
20
20
  import * as constants from './constants';
21
21
  import LineContainer from '../Line/Container';
22
+ import FTP from '../FTP';
22
23
  import Viber from '../Viber';
23
24
  const CreativesWrapper = styled.div`
24
25
  .ant-popover,
@@ -134,6 +135,7 @@ function SlideBoxContent(props) {
134
135
  selectedAccount,
135
136
  onShowTemplates,
136
137
  handleClose,
138
+ onFTPSubmit,
137
139
  } = props;
138
140
  const type = (messageDetails.type || '').toLowerCase(); // type is context in get tags values : outbound | dvs | referral | loyalty | coupons
139
141
  const query = { type: !isFullMode && 'embedded', module: isFullMode ? 'default' : 'library', isEditFromCampaigns: (templateData || {}).isEditFromCampaigns};
@@ -173,6 +175,7 @@ function SlideBoxContent(props) {
173
175
  let isEditCallTask = false;
174
176
  let isEditMPush = false;
175
177
  let isEditFacebook = false;
178
+ let isEditFTP = false;
176
179
  const isEmailCreate = slidBoxContent === 'createTemplate' && channel === constants.EMAIL;
177
180
  if (templateData && channel) {
178
181
  channel = templateData.type;// for edit mode with template data
@@ -185,6 +188,7 @@ function SlideBoxContent(props) {
185
188
  isPreview = slidBoxContent === 'preview' && (channel === constants.SMS || channel === constants.LINE || channel === constants.VIBER);
186
189
  isEmailPreview = slidBoxContent === 'preview' && channel === constants.EMAIL;
187
190
  isMpushPreview = slidBoxContent === 'preview' && channel === constants.MOBILE_PUSH;
191
+ isEditFTP = slidBoxContent === 'editTemplate' && [constants.NO_COMMUNICATION, constants.FTP].includes(channel);
188
192
  }
189
193
 
190
194
  const getChannelPreviewContent = (templateDataObject) => {
@@ -263,7 +267,6 @@ function SlideBoxContent(props) {
263
267
  return get(templateDataObject, `versions.base.content`);
264
268
  }
265
269
  };
266
-
267
270
  return (
268
271
  <CreativesWrapper>
269
272
  {!isFullMode && slidBoxContent === 'templates' && (
@@ -286,6 +289,10 @@ function SlideBoxContent(props) {
286
289
  onCreateComplete={onCreateComplete}
287
290
  getFormSubscriptionData={getFormData}
288
291
  handleClose={handleClose}
292
+ onFTPSubmit={onFTPSubmit}
293
+ slidBoxContent={slidBoxContent}
294
+ FTPMode="create"
295
+ selectedOfferDetails={selectedOfferDetails}
289
296
  />
290
297
  )}
291
298
  {isPreview && (
@@ -354,6 +361,14 @@ function SlideBoxContent(props) {
354
361
  onTestContentClicked={onTestContentClicked}
355
362
  />
356
363
  )}
364
+ {isEditFTP && (
365
+ <FTP
366
+ mode="edit"
367
+ onFTPSubmit={onFTPSubmit}
368
+ messageDetails={messageDetails}
369
+ selectedOfferDetails={selectedOfferDetails}
370
+ />
371
+ )}
357
372
  {
358
373
  isEditCallTask &&
359
374
  <CallTask
@@ -608,5 +623,6 @@ SlideBoxContent.propTypes = {
608
623
  onCreateComplete: PropTypes.func,
609
624
  saveMessage: PropTypes.func,
610
625
  selectedAccount: PropTypes.object,
626
+ onFTPSubmit: PropTypes.func,
611
627
  };
612
628
  export default SlideBoxContent;
@@ -6,6 +6,7 @@ import moment from 'moment';
6
6
  import PropTypes from 'prop-types';
7
7
  import messages from './messages';
8
8
  import { MAP_TEMPLATE } from '../WeChat/Wrapper/constants';
9
+ import { NO_COMMUNICATION, FTP } from '../App/constants';
9
10
  const PrefixWrapper = styled.div`
10
11
  margin-right: 16px;
11
12
  `;
@@ -15,6 +16,8 @@ function getChannelLabel(channel = '') {
15
16
  email: 'Email',
16
17
  mobilepush: 'Push notification',
17
18
  wechat: 'Wechat',
19
+ no_communication: 'NO_COMMUNICATION',
20
+ ftp: 'FTP',
18
21
  };
19
22
  return labels[channel.toLowerCase()];
20
23
  }
@@ -27,7 +30,7 @@ function SlideBoxHeader(props) {
27
30
  {slidBoxContent === 'templates' && !showTemplateNameHeader && (
28
31
  <CapHeader
29
32
  title={<FormattedMessage {...messages.creativeTemplates} />}
30
- description={
33
+ description={![NO_COMMUNICATION, FTP].includes(channel) &&
31
34
  <FormattedMessage {...messages.creativeTemplatesDesc} />
32
35
  }
33
36
  />
@@ -13,6 +13,8 @@ export const CALL_TASK = "CALL_TASK";
13
13
  export const MOBILE_PUSH = "MOBILEPUSH";
14
14
  export const WECHAT = "WECHAT";
15
15
  export const FACEBOOK = "FACEBOOK";
16
+ export const FTP = "FTP";
17
+ export const NO_COMMUNICATION = "NO_COMMUNICATION";
16
18
  export const VIBER = "VIBER";
17
19
 
18
20
  export const SHOW_CONTANER_LOADER = "app/CreativesContainer/SHOW_CONTANER_LOADER";
@@ -142,6 +142,13 @@ class Creatives extends React.Component {
142
142
  const {channel} = templateData;
143
143
  let creativesTemplateData = {type: channel };
144
144
  switch (channel) {
145
+ case constants.NO_COMMUNICATION: {
146
+ creativesTemplateData = {
147
+ type: channel,
148
+ ...templateData,
149
+ };
150
+ break;
151
+ }
145
152
  case constants.SMS: {
146
153
  const formData = {
147
154
  "sms-editor": templateData.messageBody,
@@ -641,6 +648,7 @@ class Creatives extends React.Component {
641
648
  selectedAccount={this.props.selectedAccount}
642
649
  onShowTemplates={this.onShowTemplates}
643
650
  handleClose={this.handleCloseSlideBox}
651
+ onFTPSubmit={getCreativesData}
644
652
  editor={editor}
645
653
  />
646
654
  }
@@ -2358,6 +2358,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
2358
2358
  const response = {
2359
2359
  action: "getFormData",
2360
2360
  postAction: this.state.getFormDataValue || 'next',
2361
+ id : _.get(this.props, 'Email.templateDetails._id', ''),
2361
2362
  value: this.transformFormData(passedData),
2362
2363
  validity: this.state.isFormValid,
2363
2364
  type: 'EMAIL',
@@ -61,7 +61,8 @@
61
61
  }
62
62
  .scrollable-section{
63
63
  height: calc(100vh - 220px);
64
- overflow-y: auto;
64
+ overflow-y: auto;
65
+ margin-bottom: $CAP_SPACE_08;
65
66
  }
66
67
  .FTP-tagList {
67
68
  position: absolute;
@@ -82,8 +83,13 @@
82
83
  }
83
84
  .ftp-preview-message-content{
84
85
  max-width: 450px;
85
- margin-top: 4px;
86
- color: $FONT_COLOR_02;
86
+ margin-top: 4px;
87
+ color: $FONT_COLOR_02;
88
+ .ant-input[disabled]{
89
+ background-color: $CAP_WHITE;
90
+ color: $FONT_COLOR_01;
91
+ cursor: default;
92
+ }
87
93
  }
88
94
  .ftp-preview-data-title{
89
95
  margin-top: $CAP_SPACE_40;
@@ -100,4 +106,9 @@
100
106
  .manage-ftp-setting-div{
101
107
  display: flex;
102
108
  align-items: baseline;
109
+ }
110
+
111
+ .configure-ftp-setting-div{
112
+ text-align: center;
113
+ align-items: baseline;
103
114
  }
@@ -19,7 +19,7 @@ import {
19
19
  CapTreeSelect,
20
20
  CapDivider,
21
21
  } from '@capillarytech/cap-ui-library';
22
- import { find, cloneDeep, findIndex, isEmpty, isEqual, filter } from 'lodash';
22
+ import { find, cloneDeep, findIndex, isEmpty, isEqual, filter, flattenDeep } from 'lodash';
23
23
  import * as actions from './actions';
24
24
  import { makeSelectFTP, makeSelectMetaEntities } from './selectors';
25
25
  import withCreatives from '../../hoc/withCreatives';
@@ -140,24 +140,35 @@ export class FTP extends React.Component {
140
140
  >
141
141
  {formatMessage(messages.ftpServer)}
142
142
  </CapHeading>
143
- <CapHeading type="h6" className="manage-ftp-setting-div">
143
+ {serverOptions.length && <CapHeading type="h6" className="manage-ftp-setting-div">
144
144
  {formatMessage(messages.ftpServerDesc)}
145
145
  <CapLink
146
146
  title={formatMessage(messages.manageFTPSettings)}
147
147
  className="select-server"
148
148
  onClick={this.handleManageFTPSettings}
149
149
  />
150
- </CapHeading>
151
- <CapRadioCard
152
- className="select-account"
153
- onChange={this.onChangeFTPServer}
154
- panes={serverOptions}
155
- cardHeight="48px"
156
- cardWidth="276px"
157
- size="small"
158
- defaultValue={selectedServer}
159
- selected={selectedServer}
160
- />
150
+ </CapHeading>}
151
+ {serverOptions.length ? (
152
+ <CapRadioCard
153
+ className="select-account"
154
+ onChange={this.onChangeFTPServer}
155
+ panes={serverOptions}
156
+ cardHeight="48px"
157
+ cardWidth="276px"
158
+ size="small"
159
+ defaultValue={selectedServer}
160
+ selected={selectedServer}
161
+ />
162
+ ) : (
163
+ <CapHeading type="h6" className="configure-ftp-setting-div">
164
+ {formatMessage(messages.selectFtpServerDesc)}
165
+ <CapLink
166
+ title={formatMessage(messages.manageFTPSettings)}
167
+ className="select-server"
168
+ onClick={this.handleManageFTPSettings}
169
+ />
170
+ </CapHeading>
171
+ )}
161
172
  </CapSpin>
162
173
  );
163
174
  };
@@ -176,11 +187,61 @@ export class FTP extends React.Component {
176
187
  }));
177
188
  };
178
189
 
190
+ getFlatTags = (tags) => {
191
+ const flatTags = [];
192
+ tags.forEach(tag => {
193
+ if ((tag.children || []).length) {
194
+ const innerTags = this.getFlatTags(tag.children);
195
+ flatTags.push(innerTags);
196
+ } else {
197
+ flatTags.push(tag.value);
198
+ }
199
+ });
200
+
201
+ return flattenDeep(flatTags);
202
+ };
203
+
204
+ validateTags(content, tagsParam) {
205
+ const tags = tagsParam;
206
+ const response = {};
207
+ response.valid = true;
208
+ response.unsupportedTags = [];
209
+ const flatTags = this.getFlatTags(tags);
210
+ if (flatTags && flatTags.length) {
211
+ const regex = /{{[(A-Z\w+(\s\w+)*$\(\)@!#$%^&*~.,/\\]+}}/g;
212
+ const matchedTags = [...content.matchAll(regex)];
213
+ matchedTags.forEach((tag) => {
214
+ let ifSupported = !!flatTags.find((t) => t === tag[0]);
215
+ if (!ifSupported) {
216
+ const tagValue = tag[0].substring(this.indexOfEnd(tag[0], '{{'), tag[0].indexOf('}}'));
217
+ response.unsupportedTags.push(tagValue);
218
+ response.valid = false;
219
+ }
220
+ if (response.unsupportedTags.length === 0) {
221
+ response.valid = true;
222
+ }
223
+ });
224
+ }
225
+ return response;
226
+ }
227
+
228
+ indexOfEnd(targetString, string) {
229
+ const io = targetString.indexOf(string);
230
+ return io == -1 ? -1 : io + string.length;
231
+ }
232
+
179
233
  getMessageContent = () => {
180
- const { messageContent } = this.state;
234
+ const { messageContent, tagsTree = []} = this.state;
181
235
  const { formatMessage } = this.props.intl;
182
236
  const { metaEntities, selectedOfferDetails } = this.props;
183
237
  const tagsRaw = metaEntities && metaEntities.tags ? metaEntities.tags.standard : [];
238
+ const validateTagResponse = this.validateTags(messageContent, tagsTree);
239
+ let unsupportedTags = null;
240
+ let errorMessageText = '';
241
+ if (!validateTagResponse.valid) {
242
+ unsupportedTags = validateTagResponse.unsupportedTags.join(', ').toString();
243
+ errorMessageText = formatMessage(messages.unsupportedTagsValidationError, {unsupportedTags})
244
+ }
184
245
  return (
185
246
  <CapRow>
186
247
  <CapColumn span={11}>
@@ -197,6 +258,7 @@ export class FTP extends React.Component {
197
258
  label={formatMessage(messages.messageHeader)}
198
259
  onChange={this.updateMessageBody}
199
260
  value={messageContent}
261
+ errorMessage={errorMessageText}
200
262
  />
201
263
  </div>
202
264
  </CapColumn>
@@ -341,9 +403,11 @@ export class FTP extends React.Component {
341
403
  <CapHeading className="ftp-preview-message-title" type="h3">
342
404
  <FormattedMessage {...messages.messageContent}/>
343
405
  </CapHeading>
344
- <CapLabel type="label2" className="ftp-preview-message-content">
345
- {messageBody}
346
- </CapLabel>
406
+ <CapInput.TextArea
407
+ value={messageBody}
408
+ disabled
409
+ className="ftp-preview-message-content"
410
+ />
347
411
  <CapHeading className="ftp-preview-data-title" type="h3">
348
412
  <FormattedMessage {...messages.dataPreview}/>
349
413
  </CapHeading>
@@ -353,7 +417,7 @@ export class FTP extends React.Component {
353
417
  };
354
418
 
355
419
  showAccountSelection = () => {
356
- this.setState({ viewMode: UIView.serverSelection, selectedServer: null, headerTagList: [], messageContent: ''});
420
+ this.setState({ viewMode: UIView.serverSelection, selectedServer: null});
357
421
  };
358
422
 
359
423
  selectCsvColumn = (option, label, index) => {
@@ -5,6 +5,10 @@ export default defineMessages({
5
5
  id: 'creatives.containersV2.FTP.ftpServerDesc',
6
6
  defaultMessage: 'Select the FTP server to send the message data. To add another FTP location, ',
7
7
  },
8
+ selectFtpServerDesc: {
9
+ id: 'creatives.containersV2.FTP.selectFtpServerDesc',
10
+ defaultMessage: 'FTP not configured for this org. Please add FTP server ',
11
+ },
8
12
  ftpServer: {
9
13
  id: 'creatives.containersV2.FTP.ftpServer',
10
14
  defaultMessage: 'FTP Server',
@@ -17,6 +21,10 @@ export default defineMessages({
17
21
  id: 'creatives.containersV2.FTP.addColumn',
18
22
  defaultMessage: 'Add column',
19
23
  },
24
+ unsupportedTagsValidationError: {
25
+ id: 'creatives.containersV2.FTP.unsupportedTagsValidationError',
26
+ defaultMessage: 'Unsupported tags: {unsupportedTags}. Please remove them from this message.',
27
+ },
20
28
  selectTag: {
21
29
  id: 'creatives.containersV2.FTP.selectTag',
22
30
  defaultMessage: 'Select tag',