@capillarytech/creatives-library 3.0.29 → 3.0.30

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 (37) hide show
  1. package/components/FormBuilder/index.js +2 -2
  2. package/components/TemplatePreview/index.js +5 -0
  3. package/components/TemplatePreview/messages.js +12 -0
  4. package/config/app.js +2 -0
  5. package/containers/Cap/index.js +1 -0
  6. package/containers/Line/Create/index.js +2 -2
  7. package/containers/Line/Edit/index.js +2 -2
  8. package/containers/MobilePush/Create/index.js +2 -2
  9. package/containers/MobilePush/Edit/index.js +2 -2
  10. package/containers/Sms/Create/index.js +2 -3
  11. package/containers/Templates/index.js +9 -7
  12. package/hoc/withCreatives.js +46 -0
  13. package/hoc/withStyles.js +12 -0
  14. package/index.js +2 -1
  15. package/package.json +1 -4
  16. package/routes.js +2 -1
  17. package/services/api.js +14 -0
  18. package/utils/smsCharCountV2.js +28 -6
  19. package/v2Components/TemplatePreview/_templatePreview.scss +8 -0
  20. package/v2Components/TemplatePreview/index.js +29 -11
  21. package/v2Components/TemplatePreview/messages.js +4 -0
  22. package/v2Containers/CreativesContainer/SlideBoxContent.js +36 -20
  23. package/v2Containers/CreativesContainer/index.js +9 -6
  24. package/v2Containers/Ebill/index.js +9 -6
  25. package/v2Containers/Email/index.js +10 -7
  26. package/v2Containers/LanguageProvider/index.js +2 -0
  27. package/v2Containers/LanguageProvider/reducer.js +1 -1
  28. package/v2Containers/Line/Create/index.js +8 -6
  29. package/v2Containers/Line/Edit/index.js +8 -5
  30. package/v2Containers/MobilePush/Create/index.js +8 -5
  31. package/v2Containers/MobilePush/Edit/index.js +8 -5
  32. package/v2Containers/Sms/Create/index.js +10 -7
  33. package/v2Containers/Sms/Edit/index.js +10 -7
  34. package/v2Containers/TemplatesV2/TemplatesV2.style.js +29 -0
  35. package/v2Containers/TemplatesV2/index.js +29 -51
  36. package/v2Containers/WeChat/MapTemplates/index.js +8 -10
  37. package/v2Containers/TemplatesV2/_templatesV2.scss +0 -5
@@ -2037,8 +2037,8 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2037
2037
  img.src = _URL.createObjectURL(file);
2038
2038
  img.onload = () => {
2039
2039
  const fileParams = {
2040
- width: this.width,
2041
- height: this.height,
2040
+ width: img.width,
2041
+ height: img.height,
2042
2042
  error: file.size / (1e+6) > 5,
2043
2043
  };
2044
2044
  this.callChildEvent({file, type: 'image', fileParams}, val, val.submitAction);
@@ -152,6 +152,11 @@ class TemplatePreview extends React.Component { // eslint-disable-line react/pre
152
152
  }
153
153
  <div style={{marginTop: '8px', fontSize: '16px'}} >{`${this.props.intl.formatMessage(messages.sms)}: ${smsDetails.parts}`}</div>
154
154
  <div style={{fontSize: '16px'}}>{`${this.props.intl.formatMessage(messages.charactersPerSms)}: ${smsDetails.chars_used}`}</div>
155
+ { smsDetails.optoutUrlPresent && <div>
156
+ <span style={{fontWeight: '100', fontSize: '12px'}}>{this.props.intl.formatMessage(messages.includes)}</span>
157
+ <span style={{fontSize: '12px'}}>{this.props.intl.formatMessage(messages.optout)}</span>
158
+ <span style={{fontWeight: '100', fontSize: '12px'}}>{this.props.intl.formatMessage(messages.tag)}</span>: {smsDetails.optouturlLength}
159
+ </div>}
155
160
  </p>
156
161
  </div>
157
162
  : ''
@@ -26,4 +26,16 @@ export default defineMessages({
26
26
  id: 'app.components.TemplatePreview.smsFormatType',
27
27
  defaultMessage: 'Message has unicode characters',
28
28
  },
29
+ includes: {
30
+ id: 'app.components.TemplatePreview.includes',
31
+ defaultMessage: 'Includes ',
32
+ },
33
+ optout: {
34
+ id: 'app.components.TemplatePreview.optout',
35
+ defaultMessage: 'Optout ',
36
+ },
37
+ tag: {
38
+ id: 'app.components.TemplatePreview.tag',
39
+ defaultMessage: 'tag ',
40
+ },
29
41
  });
package/config/app.js CHANGED
@@ -9,12 +9,14 @@ const config = {
9
9
  login_url: 'auth/login',
10
10
  dashboard_url: '/sms',
11
11
  dashboard_url_v2: '/v2',
12
+ subscription_api_endpoint: '/arya/api/v1/subscription',
12
13
  accountConfig: (strs, accountId) => `${window.location.origin}/org/config/AccountAdd?q=a&channelId=2&accountId=${accountId}&edit=1`,
13
14
  },
14
15
  development: {
15
16
  api_endpoint: 'https://nightly.capillary.in/arya/api/v1/creatives',
16
17
  auth_endpoint: 'https://nightly.capillary.in/arya/api/v1/auth',
17
18
  arya_endpoint: 'https://nightly.capillary.in/arya/api/v1',
19
+ subscription_api_endpoint: 'https://nightly.capillary.in/arya/api/v1/subscription',
18
20
  login_url: 'auth/login',
19
21
  dashboard_url: '/sms',
20
22
  dashboard_url_v2: '/v2',
@@ -166,6 +166,7 @@ export class Cap extends React.Component { // eslint-disable-line react/prefer-s
166
166
  const map = {
167
167
  'en': 'en',
168
168
  'zh-cn': 'zh',
169
+ 'zh': 'zh',
169
170
  };
170
171
  return map[locale];
171
172
  }
@@ -717,8 +717,8 @@ export class Line extends Component {
717
717
  } else {
718
718
  data.fileParams.isGeneratePreview = true;
719
719
  const name = data.file.name.split('.');
720
- const blob = data.file.slice(0, -1, 'image');
721
- const newFile = new File([blob], `${name[0]}${Date.now()}.${name[1]}`, {type: 'image'});
720
+ // const blob = data.file.slice(0, -1, 'image');
721
+ const newFile = new File([data.file], `${name[0]}${Date.now()}.${name[1]}`, {type: 'image/jpeg'});
722
722
  this.props.actions.uploadAsset(newFile, data.type, data.fileParams);
723
723
  }
724
724
  };
@@ -718,8 +718,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
718
718
  this.props.globalActions.addMessageToQueue(message);
719
719
  } else {
720
720
  const name = data.file.name.split('.');
721
- const blob = data.file.slice(0, -1, 'image');
722
- const newFile = new File([blob], `${name[0]}${Date.now()}.${name[1]}`, {type: 'image'});
721
+ // const blob = data.file.slice(0, -1, 'image');
722
+ const newFile = new File([data.file], `${name[0]}${Date.now()}.${name[1]}`, {type: 'image'});
723
723
  this.props.actions.uploadAsset(newFile, data.type, data.fileParams);
724
724
  }
725
725
  };
@@ -1706,8 +1706,8 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
1706
1706
  this.props.globalActions.addMessageToQueue(message);
1707
1707
  } else {
1708
1708
  const name = data.file.name.split('.');
1709
- const blob = data.file.slice(0, -1, 'image');
1710
- const newFile = new File([blob], `${name[0]}${Date.now()}.${name[1]}`, {type: 'image'});
1709
+ // const blob = data.file.slice(0, -1, 'image');
1710
+ const newFile = new File([data.file], `${name[0]}${Date.now()}.${name[1]}`, {type: 'image'});
1711
1711
  this.props.actions.uploadAsset(newFile, data.type, data.fileParams);
1712
1712
  }
1713
1713
  };
@@ -1064,8 +1064,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
1064
1064
  this.props.globalActions.addMessageToQueue(message);
1065
1065
  } else {
1066
1066
  const name = data.file.name.split('.');
1067
- const blob = data.file.slice(0, -1, 'image');
1068
- const newFile = new File([blob], `${name[0]}${Date.now()}.${name[1]}`, {type: 'image'});
1067
+ // const blob = data.file.slice(0, -1, 'image');
1068
+ const newFile = new File([data.file], `${name[0]}${Date.now()}.${name[1]}`, {type: 'image'});
1069
1069
  this.props.actions.uploadAsset(newFile, data.type, data.fileParams);
1070
1070
  }
1071
1071
  };
@@ -20,8 +20,7 @@ import './_smsCreate.scss';
20
20
  import FormBuilder from '../../../components/FormBuilder';
21
21
  import * as actions from './actions';
22
22
  import messages from './messages';
23
- import * as charCount from '../../../utils/smsCharCount';
24
- import {checkUnicode} from '../../../utils/smsCharCountV2';
23
+ import {checkUnicode, updateCharCount} from '../../../utils/smsCharCountV2';
25
24
  import * as globalActions from '../../../containers/Cap/actions';
26
25
  import {getMessageObject} from '../../../utils/messageUtils';
27
26
 
@@ -223,7 +222,7 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
223
222
  }
224
223
  const result = {};
225
224
  result.base = baseData;
226
- const msgObj = charCount.updateCharCount(baseData['sms-editor']);
225
+ const msgObj = updateCharCount(baseData['sms-editor']);
227
226
  result.base.msg_count = msgObj.msgCount;
228
227
  console.log("Message Count", msgObj.msgCount);
229
228
  const response = {
@@ -222,13 +222,15 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
222
222
  }
223
223
  }
224
224
  });
225
- this.setState({selectedAccount: selectedAccount.name}, () => {
226
- params.wecrmId = selectedAccount.configs.wecrm_app_id;
227
- params.wecrmToken = selectedAccount.configs.wecrm_token;
228
- params.originalId = selectedAccount.sourceAccountIdentifier;
229
- nextProps.actions.setWeChatAccount(selectedAccount);
230
- this.getAllTemplates({params});
231
- });
225
+ if (!_.isEmpty(selectedAccount)) {
226
+ this.setState({selectedAccount: selectedAccount.name}, () => {
227
+ params.wecrmId = selectedAccount.configs.wecrm_app_id;
228
+ params.wecrmToken = selectedAccount.configs.wecrm_token;
229
+ params.originalId = selectedAccount.sourceAccountIdentifier;
230
+ nextProps.actions.setWeChatAccount(selectedAccount);
231
+ this.getAllTemplates({params});
232
+ });
233
+ }
232
234
  } else if (this.state.channel.toLowerCase() === 'mobilepush' && (nextProps.location.query.account_id || nextProps.location.query.source_account_id)) {
233
235
  _.forEach(nextProps.Templates.weCrmAccounts, (account) => {
234
236
  if ((nextProps.location.query.account_id && account.id === Number(nextProps.location.query.account_id)) || (nextProps.location.query.source_account_id && account.sourceAccountIdentifier && account.sourceAccountIdentifier === nextProps.location.query.source_account_id)) {
@@ -0,0 +1,46 @@
1
+ import React, { useEffect } from 'react';
2
+ import { connect } from 'react-redux';
3
+ import { bindActionCreators } from 'redux';
4
+ import { injectIntl } from 'react-intl';
5
+ import * as globalActions from '../v2Containers/Cap/actions';
6
+ import * as creativesContainerActions from '../v2Containers/CreativesContainer/actions';
7
+ import { UserIsAuthenticated } from '../utils/authWrapper';
8
+
9
+ /**
10
+ * Higher Order Component to common out creatives channel logic
11
+ * @param {*} WrappedComponent
12
+ * @returns {*} modified wrapped component
13
+ */
14
+ export default ({
15
+ WrappedComponent,
16
+ mapStateToProps,
17
+ mapDispatchToProps,
18
+ userAuth,
19
+ }) => {
20
+ const CreativesCommon = (props) => {
21
+ useEffect(() => {
22
+ const {
23
+ globalActions: {
24
+ setInjectedTags,
25
+ },
26
+ forwardedTags = {},
27
+ } = props;
28
+ // setting the passed tags from parent in Cap store
29
+ setInjectedTags(forwardedTags);
30
+ }, []);
31
+
32
+ return <WrappedComponent {...props} />;
33
+ };
34
+
35
+ const hocMapDispatchToProps = (dispatch) => {
36
+ const passedMapDispatchToProps = mapDispatchToProps(dispatch);
37
+ return {
38
+ ...passedMapDispatchToProps,
39
+ globalActions: bindActionCreators(globalActions, dispatch),
40
+ creativesContainerActions: bindActionCreators(creativesContainerActions, dispatch),
41
+ };
42
+ };
43
+
44
+ const CreativeComponent = connect(mapStateToProps, hocMapDispatchToProps)(injectIntl(CreativesCommon));
45
+ return userAuth ? UserIsAuthenticated(CreativeComponent) : CreativeComponent;
46
+ };
@@ -0,0 +1,12 @@
1
+ import styled from 'styled-components';
2
+
3
+ /**
4
+ * Higher Order Component to have consistent logic of styling components
5
+ * @param {*} WrappedComponent
6
+ * @returns {*} styled wrapped component
7
+ */
8
+ export default (WrappedComponent, styles) => {
9
+ const StyledComponent = styled(WrappedComponent)`${styles};`;
10
+ StyledComponent.defaultProps = WrappedComponent.defaultProps;
11
+ return StyledComponent;
12
+ };
package/index.js CHANGED
@@ -51,7 +51,7 @@ import TemplatesV2 from './v2Containers/TemplatesV2/index';
51
51
 
52
52
  import CreativesContainer from './v2Containers/CreativesContainer';
53
53
  import CreativesContainerReducer from './v2Containers/CreativesContainer/reducer';
54
-
54
+ import { updateCharCount } from './utils/smsCharCountV2';
55
55
 
56
56
  export {default as Ebill} from './v2Containers/Ebill';
57
57
  export {default as EbillReducer} from './v2Containers/Ebill/reducer';
@@ -103,4 +103,5 @@ export { CapContainer,
103
103
  TemplatesV2Container,
104
104
  CreativesContainer,
105
105
  WeChat,
106
+ updateCharCount,
106
107
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "3.0.29",
4
+ "version": "3.0.30",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -16,9 +16,7 @@
16
16
  "jquery": "^3.3.1",
17
17
  "load-script": "^1.0.0",
18
18
  "normalizr": "^3.2.3",
19
- "perfect-scrollbar": "^0.7.0",
20
19
  "react-datepicker": "^0.46.0",
21
- "react-grid-layout": "^0.14.6",
22
20
  "react-router": "^3.2.0",
23
21
  "react-router-dom": "^4.2.2",
24
22
  "redux": "3.6.0",
@@ -27,7 +25,6 @@
27
25
  "redux-immutable": "3.0.8",
28
26
  "reselect": "2.5.4",
29
27
  "styled-components": "^3.2.1",
30
- "warning": "3.0.0",
31
28
  "whatwg-fetch": "2.0.1"
32
29
  }
33
30
  }
package/routes.js CHANGED
@@ -12,7 +12,7 @@ import * as emailSagas from 'containers/Email/sagas';
12
12
  import * as templateSagas from 'containers/Templates/sagas';
13
13
  import * as lineSagas from 'containers/Line/Create/sagas';
14
14
  import * as languageSaga from './v2Containers/LanguageProvider/sagas';
15
-
15
+ import {updateCharCount} from './utils/smsCharCountV2';
16
16
  const errorLoading = (err) => {
17
17
  console.error('Dynamic page loading failed', err); // eslint-disable-line no-console
18
18
  };
@@ -23,6 +23,7 @@ const loadModule = (cb) => (componentModule) => {
23
23
 
24
24
  export default function createRoutes(store) {
25
25
  // Create reusable async injectors using getAsyncInjectors factory
26
+ updateCharCount("", false); // calling here to get unsubscribeurl from api.
26
27
  const { injectReducer, injectSagas } = getAsyncInjectors(store); // eslint-disable-line no-unused-vars
27
28
  injectSagas(rootSaga.default);
28
29
  injectSagas(languageSaga.default);
package/services/api.js CHANGED
@@ -10,10 +10,12 @@ import * as API from '../utils/ApiCaller';
10
10
  let API_ENDPOINT = config.development.api_endpoint;
11
11
  let API_AUTH_ENDPOINT = config.development.auth_endpoint;
12
12
  let ARYA_ENDPOINT = config.development.arya_endpoint;
13
+ let SUBSCRIPTION_API_ENDPOINT = config.development.subscription_api_endpoint;
13
14
  if (process.env.NODE_ENV === 'production') {
14
15
  API_ENDPOINT = config.production.api_endpoint;
15
16
  API_AUTH_ENDPOINT = config.production.auth_endpoint;
16
17
  ARYA_ENDPOINT = config.production.arya_endpoint;
18
+ SUBSCRIPTION_API_ENDPOINT = config.production.subscription_api_endpoint;
17
19
  }
18
20
 
19
21
  const isProd = process.env.NODE_ENV === 'production';
@@ -324,3 +326,15 @@ export const getLocizMessage = (locale) => {
324
326
  const url = `${ARYA_ENDPOINT}/translations/${appName}/${locale}`;
325
327
  return request(url, getAPICallObject('GET'));
326
328
  };
329
+
330
+ export const getUnsubscribeUrl = () => {
331
+ const body = {
332
+ orgUnitId: -1,
333
+ source: 'INSTORE',
334
+ accountId: '',
335
+ priority: 'BULK',
336
+ channel: 'mobile',
337
+ };
338
+ const url = `${SUBSCRIPTION_API_ENDPOINT}/unsubscribeUrl`;
339
+ return request(url, getAPICallObject('POST', body));
340
+ };
@@ -1,4 +1,9 @@
1
1
  import React from 'react';
2
+ import * as Api from './../services/api';
3
+ let optoutUrl;
4
+ let showOptoutCount = true;
5
+ let responseState = "REQUEST";
6
+
2
7
  function getURLParameter(name) {
3
8
  return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [, ""])[1].replace(/\+/g, '%20')) || null
4
9
  }
@@ -49,13 +54,27 @@ export function checkUnicode(content) {
49
54
  return false;
50
55
  }
51
56
  export function updateCharCount(content, isUnicodeEnabled) {
52
- console.log(content);
53
- var chars_arr = content.split("");
54
- console.log(chars_arr);
57
+ if (showOptoutCount && optoutUrl === undefined && responseState === 'REQUEST') {
58
+ Api.getUnsubscribeUrl().then((res) => {
59
+ optoutUrl = res.response.response;
60
+ responseState = "SUCCESS";
61
+ }).catch((err) => {
62
+ showOptoutCount = false;
63
+ responseState = "FAIL";
64
+ optoutUrl = undefined;
65
+ console.log('get optouturl error: ', err);
66
+ });
67
+ }
68
+ const optoutTag = /{{optout}}/g;
69
+ const optoutTagLength = 14;
70
+ const contentOriginal = content;
71
+ const noOfOptout = (content.match(optoutTag) || []).length;
72
+ content = showOptoutCount ? content.replace(optoutTag, "") : content;
73
+ var chars_arr = contentOriginal.split("");
55
74
  var coding = '7bit';
56
75
  var parts = 1;
57
76
  var part = 1;
58
- var chars_used = 0;
77
+ var chars_used = showOptoutCount ? ((optoutUrl && optoutUrl.length || 0) * noOfOptout) : 0;
59
78
  var chars_sms = 160;
60
79
  var sms_parts_container = [];
61
80
  var partc = [];
@@ -127,17 +146,20 @@ export function updateCharCount(content, isUnicodeEnabled) {
127
146
  }
128
147
  }
129
148
 
149
+ chars_used = showOptoutCount ? (chars_used - (optoutTagLength * noOfOptout)) : chars_used;
130
150
  console.log('Type:', (coding == '7bit' ? '7bit' : 'Unicode'));
131
151
  console.log('Parts:', parts);
132
152
  console.log('SMS Chars:', chars_sms);
133
153
  console.log('SMS Char total:', chars_used);
134
-
154
+ console.log('SMS optouturl: ', optoutUrl);
135
155
  return {
136
156
  unicode: (coding === '7bit' ? false : true),
137
157
  parts,
138
158
  chars_sms,
139
159
  chars_used,
140
160
  char_list: partc,
161
+ optouturlLength: (optoutUrl && optoutUrl.length) || 0,
162
+ optoutUrlPresent: noOfOptout > 0,
163
+ responseState,
141
164
  };
142
165
  }
143
-
@@ -350,3 +350,11 @@
350
350
  background-color: #333333;
351
351
  margin-right: 4px;
352
352
  }
353
+
354
+ .character-count-col{
355
+ margin-top: 8px;
356
+ margin-left: 40px;
357
+ .optout-tag-heading{
358
+ font-size: 12px;
359
+ }
360
+ }
@@ -59,24 +59,42 @@ class TemplatePreview extends React.Component { // eslint-disable-line react/pre
59
59
  <FormattedMessage {...messages.smsFormatType}/>
60
60
  }
61
61
  </CapHeading>}
62
+ {smsDetails.optoutUrlPresent && <CapHeading type="h6">
63
+ <FormattedMessage {...messages.optoutCharactersTotal} values={{optoutUrlLength: smsDetails.optouturlLength}} />
64
+ </CapHeading>}
62
65
  </CapColumn>}
63
66
  <CapColumn span={this.props.showCount ? 8 : 24}>
64
67
  <div className={`preview-container ${type === 'embedded' ? 'embedded-preview' : ''}`}>
65
68
  { channel && channel.toLowerCase() === 'sms' &&
66
- <div className="shell align-center" id="sms-preview">
67
- <img className="preview-image sms" src={smsBody} alt="Preview is being generated"/>
68
- <div className="msgContainer sms">
69
- <img className="sms-icon" src={smsIcon} alt="Sms icon" />
70
- <div className={"message-pop sms"}>
71
- {content && content.length && content.map((msg, index) =>
72
- <CapColumn key={`"message-pop-content-${index}`} className="message-pop-item align-left" style={{ background: '#3F51B5', color: '#ffffff'}}>
73
- {msg}
74
- </CapColumn>)
75
- }
69
+ <div>
70
+ <div className="shell align-center" id="sms-preview">
71
+ <img className="preview-image sms" src={smsBody} alt="Preview is being generated"/>
72
+ <div className="msgContainer sms">
73
+ <img className="sms-icon" src={smsIcon} alt="Sms icon" />
74
+ <div className={"message-pop sms"}>
75
+ {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'}}>
77
+ {msg}
78
+ </CapColumn>)
79
+ }
80
+ </div>
76
81
  </div>
77
82
  </div>
83
+ {!this.props.showCount && <div>
84
+ <CapColumn className="character-count-col" span={20}>
85
+ {channel && channel.toLowerCase() === 'sms' && <CapHeading type="h3">
86
+ <FormattedMessage {...messages.charactersTotal} values={{smsCount: smsDetails.parts, charCount: smsDetails.chars_used}}/>
87
+ {smsDetails.unicode &&
88
+ <FormattedMessage {...messages.smsFormatType}/>
89
+ }
90
+ </CapHeading>}
91
+ {smsDetails.optoutUrlPresent && <CapHeading type="h6" className="optout-tag-heading">
92
+ <FormattedMessage {...messages.optoutCharactersTotal} values={{optoutUrlLength: smsDetails.optouturlLength}} />
93
+ </CapHeading>}
94
+ </CapColumn>
95
+ </div>}
78
96
  </div>
79
- }
97
+ }
80
98
  {channel && channel.toLowerCase() === 'wechat' ?
81
99
  ( <div className="shell align-center" id="sms-preview">
82
100
  <img className="preview-image" src={channel.toLowerCase() === 'wechat' ? wechatBody : smsBody} alt="Preview is being generated"/>
@@ -22,6 +22,10 @@ export default defineMessages({
22
22
  id: 'app.components.TemplatePreview.charactersTotal',
23
23
  defaultMessage: "{smsCount} SMS ({charCount} characters)",
24
24
  },
25
+ optoutCharactersTotal: {
26
+ id: 'app.components.TemplatePreview.optoutCharactersTotal',
27
+ defaultMessage: "Includes Optout tag ({optoutUrlLength} characters)",
28
+ },
25
29
  smsFormatType: {
26
30
  id: 'app.components.TemplatePreview.smsFormatType',
27
31
  defaultMessage: 'Message has unicode characters',
@@ -50,6 +50,7 @@ function SlideBoxContent(props) {
50
50
  showTemplateName,
51
51
  onValidationFail,
52
52
  channelsToHide,
53
+ forwardedTags,
53
54
  } = props;
54
55
  const type = messageDetails.type.toLowerCase(); // type is context in get tags values : outbound | dvs | referral | loyalty | coupons
55
56
  const query = { type: !isFullMode && 'embedded', module: isFullMode ? 'defualt' : 'library'};
@@ -97,6 +98,7 @@ function SlideBoxContent(props) {
97
98
  onCallTaskSubmit={onCallTaskSubmit}
98
99
  cap={cap}
99
100
  channelsToHide={channelsToHide}
101
+ forwardedTags={forwardedTags}
100
102
  />
101
103
  )}
102
104
  {isPreview && (
@@ -107,44 +109,52 @@ function SlideBoxContent(props) {
107
109
  charCounterEnabled
108
110
  templateData={templateData}
109
111
  showCount
112
+ forwardedTags={forwardedTags}
110
113
  />
111
114
  )}
112
115
  {isEmailPreview && (
113
116
  <EmailPreviewV2
114
117
  templateData={templateData}
115
- />
118
+ forwardedTags={forwardedTags}
119
+ />
116
120
  )
117
121
  }
118
- {isMpushPreview &&
119
- <MobilePushPreview templateData={templateData} channel={channel}/>
120
- }
122
+ {isMpushPreview && (
123
+ <MobilePushPreview
124
+ templateData={templateData}
125
+ channel={channel}
126
+ forwardedTags={forwardedTags}
127
+ />
128
+ )}
121
129
  {isEditSms && (
122
- <SmsEdit
123
- setIsLoadingContent={setIsLoadingContent}
124
- location={creativesLocationProps}
125
- isFullMode={isFullMode}
126
- route={{ name: 'sms' }}
127
- params={{id: templateData._id}}
128
- isGetFormData={isGetFormData}
129
- getFormSubscriptionData={getFormData}
130
- getDefaultTags={type}
131
- templateData={templateData}
132
- // subscriptionTemplateDetails={templateData} // used only in library mode
133
- />
134
- )}
130
+ <SmsEdit
131
+ setIsLoadingContent={setIsLoadingContent}
132
+ location={creativesLocationProps}
133
+ isFullMode={isFullMode}
134
+ route={{ name: 'sms' }}
135
+ params={{id: templateData._id}}
136
+ isGetFormData={isGetFormData}
137
+ getFormSubscriptionData={getFormData}
138
+ getDefaultTags={type}
139
+ templateData={templateData}
140
+ forwardedTags={forwardedTags}
141
+ />
142
+ )}
135
143
  {
136
144
  isEditCallTask &&
137
145
  <CallTask
138
146
  mode={'edit'}
139
147
  templateData={templateData}
140
148
  onCallTaskSubmit={onCallTaskSubmit}
141
- />
149
+ forwardedTags={forwardedTags}
150
+ />
142
151
  }
143
152
  {
144
153
  isCreateCallTask &&
145
154
  <CallTask
146
155
  mode={'create'}
147
156
  onCallTaskSubmit={onCallTaskSubmit}
157
+ forwardedTags={forwardedTags}
148
158
  />
149
159
  }
150
160
  {isCreateSms && (
@@ -157,7 +167,8 @@ function SlideBoxContent(props) {
157
167
  getFormSubscriptionData={getFormData}
158
168
  getDefaultTags={type}
159
169
  isFullMode={isFullMode}
160
- />
170
+ forwardedTags={forwardedTags}
171
+ />
161
172
  )}
162
173
  {isEmailCreate && (
163
174
  <EmailWrapper
@@ -177,6 +188,7 @@ function SlideBoxContent(props) {
177
188
  onResetStep={onResetStep}
178
189
  showTemplateName={showTemplateName}
179
190
  onValidationFail={onValidationFail}
191
+ forwardedTags={forwardedTags}
180
192
  />
181
193
  )}
182
194
  {(isEditEmailWithId || isEmailEditWithContent) && (
@@ -198,7 +210,8 @@ function SlideBoxContent(props) {
198
210
  cap={cap}
199
211
  showTemplateName={showTemplateName}
200
212
  onValidationFail={onValidationFail}
201
- />
213
+ forwardedTags={forwardedTags}
214
+ />
202
215
  )}
203
216
  {isEditMPush &&
204
217
  <MobliPushEdit
@@ -216,6 +229,7 @@ function SlideBoxContent(props) {
216
229
  showTemplateName={showTemplateName}
217
230
  getDefaultTags={type}
218
231
  onValidationFail={onValidationFail}
232
+ forwardedTags={forwardedTags}
219
233
  />
220
234
  }
221
235
  {isCreateMPush &&
@@ -238,6 +252,7 @@ function SlideBoxContent(props) {
238
252
  onResetStep={onResetStep}
239
253
  showTemplateName={showTemplateName}
240
254
  query={query}
255
+ forwardedTags={forwardedTags}
241
256
  onValidationFail={onValidationFail}/>
242
257
  }
243
258
  </CreativesWrapper>
@@ -271,5 +286,6 @@ SlideBoxContent.propTypes = {
271
286
  showTemplateName: PropTypes.func,
272
287
  onValidationFail: PropTypes.func,
273
288
  channelsToHide: PropTypes.array,
289
+ forwardedTags: PropTypes.object,
274
290
  };
275
291
  export default SlideBoxContent;