@capillarytech/creatives-library 3.2.1 → 3.2.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.
package/app.js CHANGED
@@ -10,7 +10,7 @@ import CapV2 from 'v2Containers/Cap';
10
10
  import Cap from 'containers/Cap';
11
11
  import { LocaleProvider } from 'antd';
12
12
  import { makeSelectLocationState } from 'containers/Cap/selectors';
13
- import LanguageProvider from 'containers/LanguageProvider';
13
+ import LanguageProvider from 'v2Containers/LanguageProvider';
14
14
  import FontFaceObserver from 'fontfaceobserver';
15
15
  /* eslint-disable import/no-unresolved, import/extensions */
16
16
  import '!file-loader?name=[name].[ext]!./favicon.ico';
package/config/app.js CHANGED
@@ -5,6 +5,7 @@ const config = {
5
5
  production: {
6
6
  api_endpoint: '/arya/api/v1/creatives',
7
7
  auth_endpoint: '/arya/api/v1/auth',
8
+ arya_endpoint: '/arya/api/v1',
8
9
  login_url: 'auth/login',
9
10
  dashboard_url: '/sms',
10
11
  dashboard_url_v2: '/v2',
@@ -14,7 +15,8 @@ const config = {
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
- subscription_api_endpoint: 'https://nightly.capillary.in/arya/api/v1/subscription',
18
+ arya_endpoint: 'https://nightly.capillary.in/arya/api/v1',
19
+ subscription_api_endpoint: 'https://nightly.capillary.in/arya/api/v1/org-settings/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
  }
@@ -0,0 +1,63 @@
1
+ import { defineMessages } from 'react-intl';
2
+ export default defineMessages({
3
+ "sms": {
4
+ id: 'reon.components.Cap.sms',
5
+ defaultMessage: 'SMS',
6
+ },
7
+ "wechat": {
8
+ id: 'reon.components.Cap.wechat',
9
+ defaultMessage: 'WeChat',
10
+ },
11
+ "gallery": {
12
+ id: 'reon.components.Cap.gallery',
13
+ defaultMessage: 'Gallery',
14
+ },
15
+ "creativesDashboard": {
16
+ id: 'reon.components.Cap.creativesDashboard',
17
+ defaultMessage: 'Creatives',
18
+ },
19
+ "creatives": {
20
+ id: 'reon.components.Cap.creatives',
21
+ defaultMessage: 'Creatives',
22
+ },
23
+ "campaigns": {
24
+ id: 'reon.components.Cap.campaigns',
25
+ defaultMessage: 'Campaigns',
26
+ },
27
+ "loyalty": {
28
+ id: 'reon.components.Cap.loyalty',
29
+ defaultMessage: 'Loyalty',
30
+ },
31
+ "member care": {
32
+ id: 'reon.components.Cap.memberCare',
33
+ defaultMessage: 'Member Care',
34
+ },
35
+ "workbench": {
36
+ id: 'reon.components.Cap.Workbench',
37
+ defaultMessage: 'WorkBench',
38
+ },
39
+ "store care": {
40
+ id: 'reon.components.Cap.storeCare',
41
+ defaultMessage: 'Store Care',
42
+ },
43
+ "store performance": {
44
+ id: 'reon.components.Cap.storePerformance',
45
+ defaultMessage: 'Store Performance',
46
+ },
47
+ "email": {
48
+ id: 'reon.components.Cap.email',
49
+ defaultMessage: 'Email',
50
+ },
51
+ "ebill": {
52
+ id: 'reon.components.Cap.ebill',
53
+ defaultMessage: 'Ebill',
54
+ },
55
+ "campaignsDashboard": {
56
+ id: 'reon.components.campaignsDashboard',
57
+ defaultMessage: 'Campaigns',
58
+ },
59
+ "campaignsHome": {
60
+ id: 'reon.components.campaignsHome',
61
+ defaultMessage: "Campaigns Home",
62
+ },
63
+ });
@@ -9,6 +9,9 @@
9
9
  import PropTypes from 'prop-types';
10
10
 
11
11
  import React from 'react';
12
+ import { ConfigProvider } from 'antd';
13
+ import enUS from 'antd/es/locale-provider/en_US';
14
+ import zhCN from 'antd/es/locale-provider/zh_CN';
12
15
  import { connect } from 'react-redux';
13
16
  import { createSelector } from 'reselect';
14
17
  import { IntlProvider } from 'react-intl';
@@ -16,11 +19,31 @@ import { IntlProvider } from 'react-intl';
16
19
  import { makeSelectLocale } from './selectors';
17
20
 
18
21
  export class LanguageProvider extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function
22
+ getMappedLocale = (locale) => {
23
+ const map = {
24
+ 'en': 'en-US',
25
+ 'zh-cn': 'zh',
26
+ 'en-US': 'en-US',
27
+ 'zh': 'zh',
28
+ };
29
+ return map[locale];
30
+ }
31
+
19
32
  render() {
33
+ const mappedLocale = {
34
+ 'en': enUS,
35
+ 'zh-cn': zhCN,
36
+ 'en-US': enUS,
37
+ zh: zhCN,
38
+ };
39
+ const jLocale = localStorage.getItem('jlocale') || 'en';
40
+ const file = mappedLocale[jLocale];
20
41
  return (
21
- <IntlProvider locale={this.props.locale} key={this.props.locale} messages={this.props.messages[this.props.locale]}>
22
- {React.Children.only(this.props.children)}
23
- </IntlProvider>
42
+ <ConfigProvider locale={file}>
43
+ <IntlProvider locale={this.props.locale} key={this.props.locale} messages={this.props.messages[this.props.locale]}>
44
+ {React.Children.only(this.props.children)}
45
+ </IntlProvider>
46
+ </ConfigProvider>
24
47
  );
25
48
  }
26
49
  }
@@ -102,4 +102,8 @@ export default defineMessages({
102
102
  id: 'creatives.containers.WeChat.linkCantEmpty',
103
103
  defaultMessage: "Link cannot be empty",
104
104
  },
105
+ "loadingEDMTemplates": {
106
+ id: 'creatives.containers.WeChat.loadingEDMTemplates',
107
+ defaultMessage: "loading EDM Templates",
108
+ },
105
109
  });
package/index.js CHANGED
@@ -3,6 +3,10 @@ import capReducer from './v2Containers/Cap/reducer';
3
3
  import capSaga from './v2Containers/Cap/sagas';
4
4
  import Cap from './v2Containers/Cap/index';
5
5
 
6
+ import LanguageProvider from './v2Containers/LanguageProvider';
7
+ import LanguageProviderReducer from './v2Containers/LanguageProvider/reducer';
8
+ import LanguageProviderSaga from './v2Containers/LanguageProvider/sagas';
9
+
6
10
  import templateReducer from './v2Containers/Templates/reducer';
7
11
  import templateSaga from './v2Containers/Templates/sagas';
8
12
  import Templates from './v2Containers/Templates/index';
@@ -63,6 +67,7 @@ export {default as EbillSaga} from './v2Containers/Ebill/sagas';
63
67
 
64
68
 
65
69
  const CapContainer = {Cap, capReducer, capSaga};
70
+ const LanguageProviderContainer = {LanguageProvider, LanguageProviderReducer, LanguageProviderSaga};
66
71
  const TemplatesContainer = {Templates, templateReducer, templateSaga};
67
72
  const SmsCreateContainer = {SmsCreate, smsCreateReducer, smsCreateSaga};
68
73
  const SmsEditContainer = {SmsEdit, smsEditReducer, smsEditSaga};
@@ -91,6 +96,7 @@ export {default as WechatRichmediaTemplatePreview} from './v2Components/Template
91
96
  CreativesContainer.CreativesContainerReducer = CreativesContainerReducer;
92
97
 
93
98
  export { CapContainer,
99
+ LanguageProviderContainer,
94
100
  TemplatesContainer,
95
101
  SmsCreateContainer,
96
102
  SmsEditContainer,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "3.2.1",
4
+ "version": "3.2.3",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -18,9 +18,7 @@
18
18
  "jquery": "^3.3.1",
19
19
  "load-script": "^1.0.0",
20
20
  "normalizr": "^3.2.3",
21
- "perfect-scrollbar": "^0.7.0",
22
21
  "react-datepicker": "^0.46.0",
23
- "react-grid-layout": "^0.14.6",
24
22
  "react-router": "^3.2.0",
25
23
  "react-router-dom": "^4.2.2",
26
24
  "redux": "3.6.0",
@@ -29,7 +27,6 @@
29
27
  "redux-immutable": "3.0.8",
30
28
  "reselect": "2.5.4",
31
29
  "styled-components": "^3.2.1",
32
- "warning": "3.0.0",
33
30
  "whatwg-fetch": "2.0.1"
34
31
  }
35
32
  }
package/reducers.js CHANGED
@@ -7,7 +7,7 @@ import { combineReducers } from 'redux-immutable';
7
7
  import { fromJS } from 'immutable';
8
8
  import { LOCATION_CHANGE } from 'react-router-redux';
9
9
 
10
- import languageProviderReducer from 'containers/LanguageProvider/reducer';
10
+ import languageProviderReducer from 'v2Containers/LanguageProvider/reducer';
11
11
  import capReducer from 'containers/Cap/reducer';
12
12
  import appReducer from 'containers/App/reducer';
13
13
  import createSmsReducer from 'containers/Sms/Create/reducer';
package/routes.js CHANGED
@@ -11,8 +11,8 @@ import * as ebillSagas from 'containers/Ebill/sagas';
11
11
  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
+ import * as languageSaga from './v2Containers/LanguageProvider/sagas';
14
15
  import {updateCharCount} from './utils/smsCharCountV2';
15
-
16
16
  const errorLoading = (err) => {
17
17
  console.error('Dynamic page loading failed', err); // eslint-disable-line no-console
18
18
  };
@@ -26,6 +26,7 @@ export default function createRoutes(store) {
26
26
  updateCharCount("", false); // calling here to get unsubscribeurl from api.
27
27
  const { injectReducer, injectSagas } = getAsyncInjectors(store); // eslint-disable-line no-unused-vars
28
28
  injectSagas(rootSaga.default);
29
+ injectSagas(languageSaga.default);
29
30
  return [
30
31
  {
31
32
  path: '/',
package/services/api.js CHANGED
@@ -9,10 +9,12 @@ import getSchema from './getSchema';
9
9
  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
+ let ARYA_ENDPOINT = config.development.arya_endpoint;
12
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;
17
+ ARYA_ENDPOINT = config.production.arya_endpoint;
16
18
  SUBSCRIPTION_API_ENDPOINT = config.production.subscription_api_endpoint;
17
19
  }
18
20
 
@@ -58,8 +60,8 @@ function checkStatus(response) {
58
60
  if ((response.status >= 200 && response.status < 300) || response.status === 500) {
59
61
  return response;
60
62
  }
61
-
62
- redirectIfUnauthenticated(response);
63
+ const isLoginPage = window.location.pathname.indexOf('/login') !== -1;
64
+ if (!isLoginPage) redirectIfUnauthenticated(response);
63
65
 
64
66
  const error = new Error(response.statusText);
65
67
  error.response = response;
@@ -319,6 +321,13 @@ export const createLineTemplate = ({template}) => {
319
321
  return request(url, getAPICallObject('POST', template));
320
322
  };
321
323
 
324
+ export const getLocizMessage = async (locale) => {
325
+ const appName = 'creatives_v2';
326
+ const url = `${ARYA_ENDPOINT}/translations/${appName}/${locale}`;
327
+ const response = await request(url, getAPICallObject('GET'));
328
+ return response;
329
+ };
330
+
322
331
  export const getUnsubscribeUrl = () => {
323
332
  const body = {
324
333
  orgUnitId: -1,
@@ -73,7 +73,7 @@
73
73
  "creatives.componentsV2.CallTaskPreview.header": "This is the CallTaskPreview component !",
74
74
  "creatives.componentsV2.CapTagList.Cancel": "Cancel",
75
75
  "creatives.componentsV2.CapTagList.Ok": "Ok",
76
- "creatives.componentsV2.CapTagList.all": "Dynamic days before expiry",
76
+ "creatives.componentsV2.CapTagList.all": "All",
77
77
  "creatives.componentsV2.CapTagList.dynamic_days_before_expiry": "Dynamic days before expiry",
78
78
  "creatives.componentsV2.CapTagList.gettingTags": "Getting tags...",
79
79
  "creatives.componentsV2.CapTagList.loyalty": "Loyalty",
@@ -684,7 +684,7 @@
684
684
  "creatives.containers.WeChat.template": "Template",
685
685
  "creatives.containers.WeChat.templateMapping": "Template mapping",
686
686
  "creatives.containers.WeChat.wechatCreateSuccess": "WeChat template mapped successfully",
687
- "creatives.containers.WeChat.wechatEditSuccess": "WeChat template unmapped successfully",
687
+ "creatives.containers.WeChat.wechatEditSuccess": "WeChat template edited successfully",
688
688
  "creatives.containersV2.Assets.Gallery.addImages": "Add images",
689
689
  "creatives.containersV2.Assets.Gallery.alphabetically": "Alphabetically",
690
690
  "creatives.containersV2.Assets.Gallery.assetDeleteFailed": "Image deletion failed.",
@@ -1350,7 +1350,7 @@
1350
1350
  "creatives.containersV2.WeChat.template": "Template",
1351
1351
  "creatives.containersV2.WeChat.templateMapping": "Template mapping",
1352
1352
  "creatives.containersV2.WeChat.wechatCreateSuccess": "WeChat template mapped successfully",
1353
- "creatives.containersV2.WeChat.wechatEditSuccess": "WeChat template unmapped successfully",
1353
+ "creatives.containersV2.WeChat.wechatEditSuccess": "WeChat template edited successfully",
1354
1354
  "creatives.containersV2.appName": "App Name",
1355
1355
  "creatives.containersV2.audience": "Audience",
1356
1356
  "creatives.containersV2.campaigns": "Campaigns",
@@ -1415,5 +1415,11 @@
1415
1415
  "reon.modules.Login.componentsv2.LoginForm.input.invalidCredentials": "Invalid or Incorrect credentials!",
1416
1416
  "reon.modules.Login.componentsv2.LoginForm.input.loginButton": "Login",
1417
1417
  "reon.modules.Login.componentsv2.LoginForm.input.password": "Password",
1418
- "reon.modules.Login.componentsv2.LoginForm.input.username": "Username or email"
1418
+ "reon.modules.Login.componentsv2.LoginForm.input.username": "Username or email",
1419
+ "creatives.containers.WeChat.loadingEDMTemplates": "loading EDM Templates",
1420
+ "creatives.containersV2.WeChat.select": "Select",
1421
+ "creatives.containersV2.WeChat.newWechat": "New wechat",
1422
+ "creatives.containersV2.WeChat.linkErrorMessage": "Link cannot be empty.",
1423
+ "creatives.containersV2.WeChat.hasInvalidContent": "has invalid content.",
1424
+ "creatives.containersV2.WeChat.templateName": "Template Name"
1419
1425
  }
@@ -1415,5 +1415,11 @@
1415
1415
  "reon.modules.Login.componentsv2.LoginForm.input.invalidCredentials": "",
1416
1416
  "reon.modules.Login.componentsv2.LoginForm.input.loginButton": "",
1417
1417
  "reon.modules.Login.componentsv2.LoginForm.input.password": "",
1418
- "reon.modules.Login.componentsv2.LoginForm.input.username": ""
1418
+ "reon.modules.Login.componentsv2.LoginForm.input.username": "",
1419
+ "creatives.containers.WeChat.loadingEDMTemplates": "",
1420
+ "creatives.containersV2.WeChat.select": "",
1421
+ "creatives.containersV2.WeChat.newWechat": "",
1422
+ "creatives.containersV2.WeChat.linkErrorMessage": "",
1423
+ "creatives.containersV2.WeChat.hasInvalidContent": "",
1424
+ "creatives.containersV2.WeChat.templateName": ""
1419
1425
  }
@@ -1887,8 +1887,8 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1887
1887
 
1888
1888
  for (let i = 0; i < elems.length; i += 1) {
1889
1889
  if (elems.item(i).classList.contains("ant-tabs-tab-active")) {
1890
- activeTabIndex = i + 1;
1891
- }
1890
+ activeTabIndex = i + 1;
1891
+ }
1892
1892
  }
1893
1893
  if (this.props.isNewVersionFlow) {
1894
1894
  const formData = _.cloneDeep(this.state.formData);
@@ -0,0 +1,46 @@
1
+ /**
2
+ *
3
+ * Header
4
+ *
5
+ */
6
+
7
+ import PropTypes from 'prop-types';
8
+
9
+ import React from 'react';
10
+ // import styled from 'styled-components';
11
+ import { FormattedMessage } from 'react-intl';
12
+
13
+ import { CapRow, CapColumn, CapInput, CapButton } from '@capillarytech/cap-ui-library';
14
+ import messages from './messages';
15
+
16
+
17
+ function Header(props) {
18
+ return (
19
+ <div>
20
+ <CapRow className="template-form-header">
21
+ <CapColumn span={10}>
22
+ <CapInput id="template-name" placeholder="Enter template name*" defaultValue={props.templateName} type="input" onChange={props.templateNameHandler}/>
23
+ </CapColumn>
24
+ <CapColumn span={2} offset={8}>
25
+ <CapButton id="preview-button" type="cancel" onClick={props.previewHandler}> <FormattedMessage {...messages.preview} /> </CapButton>
26
+ </CapColumn>
27
+ <CapColumn span={2}>
28
+ <CapButton id="cancel-button" type="cancel" onClick={props.cancelHandler}> <FormattedMessage {...messages.cancel} /> </CapButton>
29
+ </CapColumn>
30
+ <CapColumn span={2}>
31
+ <CapButton id="save-button" type="primary" onClick={props.saveHandler}> <FormattedMessage {...messages.save} /> </CapButton>
32
+ </CapColumn>
33
+ </CapRow>
34
+ </div>
35
+ );
36
+ }
37
+
38
+ Header.propTypes = {
39
+ templateNameHandler: PropTypes.func,
40
+ previewHandler: PropTypes.func,
41
+ cancelHandler: PropTypes.func,
42
+ saveHandler: PropTypes.func,
43
+ templateName: PropTypes.string,
44
+ };
45
+
46
+ export default Header;
@@ -0,0 +1,10 @@
1
+ // import React from 'react';
2
+ // import { shallow } from 'enzyme';
3
+
4
+ // import Header from '../index';
5
+
6
+ describe('<Header />', () => {
7
+ it('Expect to have unit tests specified', () => {
8
+ expect(true).toEqual(false);
9
+ });
10
+ });
@@ -60,6 +60,7 @@ function SlideBoxContent(props) {
60
60
  onValidationFail,
61
61
  channelsToHide,
62
62
  forwardedTags,
63
+ channelsToDisable,
63
64
  weChatTemplateType,
64
65
  onWechatTemplateChange,
65
66
  selectedWeChatAccount,
@@ -113,6 +114,7 @@ function SlideBoxContent(props) {
113
114
  cap={cap}
114
115
  channelsToHide={channelsToHide}
115
116
  forwardedTags={forwardedTags}
117
+ channelsToDisable={channelsToDisable}
116
118
  />
117
119
  )}
118
120
  {isPreview && (
@@ -323,6 +325,7 @@ SlideBoxContent.propTypes = {
323
325
  onValidationFail: PropTypes.func,
324
326
  channelsToHide: PropTypes.array,
325
327
  forwardedTags: PropTypes.object,
328
+ channelsToDisable: PropTypes.array,
326
329
  weChatTemplateType: PropTypes.string,
327
330
  onWechatTemplateChange: PropTypes.func,
328
331
  selectedWeChatAccount: PropTypes.object,
@@ -465,7 +465,7 @@ class Creatives extends React.Component {
465
465
  }
466
466
  render() {
467
467
  const {slidBoxContent, isGetFormData, showSlideBox, templateData, currentChannel, emailCreateMode, templateStep, isLoadingContent, mobilePushCreateMode, isDiscardMessage, weChatTemplateType, weChatMaptemplateStep} = this.state;
468
- const {isFullMode, creativesMode, cap, isUploading, channelsToHide, selectedWeChatAccount, forwardedTags} = this.props;
468
+ const {isFullMode, creativesMode, cap, isUploading, channelsToHide, selectedWeChatAccount, forwardedTags, channelsToDisable} = this.props;
469
469
  const mapTemplateCreate = slidBoxContent === 'createTemplate' && weChatTemplateType === MAP_TEMPLATE && templateStep !== 'modeSelection';
470
470
  return (
471
471
  <SlideBoxWrapper className={classnames(`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`)}>
@@ -522,6 +522,7 @@ class Creatives extends React.Component {
522
522
  onValidationFail={this.onValidationFail}
523
523
  channelsToHide={channelsToHide}
524
524
  forwardedTags={forwardedTags}
525
+ channelsToDisable={channelsToDisable}
525
526
  weChatTemplateType={weChatTemplateType}
526
527
  onWechatTemplateChange={this.onWechatTemplateChange}
527
528
  weChatMaptemplateStep={weChatMaptemplateStep}
@@ -573,6 +574,7 @@ Creatives.propTypes = {
573
574
  EmailLayout: PropTypes.string,
574
575
  channelsToHide: PropTypes.array,
575
576
  forwardedTags: PropTypes.object,
577
+ channelsToDisable: PropTypes.array,
576
578
  selectedWeChatAccount: PropTypes.object,
577
579
  };
578
580
  const mapStatesToProps = () => createStructuredSelector({
@@ -58,7 +58,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
58
58
  showImageSelectionBox: false,
59
59
  isDragDrop: false,
60
60
  showConfirmationModal: false,
61
- modalContent: {title: this.props.intl.formatMessage(messages.alertMessage), body: this.props.intl.formatMessage(messages.deleteLanguageConfirmation), type: 'confirm', id: 'email-language-delete-modal'},
61
+ modalContent: {title: this.props.intl.formatMessage(messages.alert), body: this.props.intl.formatMessage(messages.deleteLanguageConfirmation), type: 'confirm', id: 'email-language-delete-modal'},
62
62
  showModal: false,
63
63
  page: 1,
64
64
  perPageLimit: 25,
@@ -906,14 +906,14 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
906
906
  let modalContent = {};
907
907
  if (type === 'delete-version') {
908
908
  modalContent = {
909
- title: this.props.intl.formatMessage(messages.alertMessage),
909
+ title: this.props.intl.formatMessage(messages.alert),
910
910
  body: this.props.intl.formatMessage(messages.deleteVersionConfirmation),
911
911
  type: 'confirm',
912
912
  id: 'email-version-delete-modal',
913
913
  };
914
914
  } else if (type === 'delete-language') {
915
915
  modalContent = {
916
- title: this.props.intl.formatMessage(messages.alertMessage),
916
+ title: this.props.intl.formatMessage(messages.alert),
917
917
  body: this.props.intl.formatMessage(messages.deleteLanguageConfirmation),
918
918
  type: 'confirm',
919
919
  id: 'email-language-delete-modal',
@@ -1001,7 +1001,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
1001
1001
  showImageSelectionBox: false,
1002
1002
  isDragDrop: false,
1003
1003
  showConfirmationModal: false,
1004
- modalContent: {title: this.props.intl.formatMessage(messages.alertMessage), body: this.props.intl.formatMessage(messages.deleteLanguageConfirmation), type: 'confirm', id: 'email-language-delete-modal'},
1004
+ modalContent: {title: this.props.intl.formatMessage(messages.alert), body: this.props.intl.formatMessage(messages.deleteLanguageConfirmation), type: 'confirm', id: 'email-language-delete-modal'},
1005
1005
  showModal: false,
1006
1006
  page: 1,
1007
1007
  perPageLimit: 25,
@@ -1823,7 +1823,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
1823
1823
 
1824
1824
  moveToTemplates = () => {
1825
1825
  const modalContent = {
1826
- title: this.props.intl.formatMessage(messages.alertMessage),
1826
+ title: this.props.intl.formatMessage(messages.alert),
1827
1827
  body: this.props.intl.formatMessage(messages.goBackTemporaryChangesLost),
1828
1828
  type: 'confirm',
1829
1829
  id: 'template-back-confirm-modal',
@@ -203,15 +203,15 @@ export class EmailWrapper extends React.Component { // eslint-disable-line react
203
203
  </CardContainer>
204
204
  <div>
205
205
  {emailCreateMode === "upload" &&
206
- <div style={{ marginLeft: '8px'}}>
207
- <CapUploader onChange={this.useFileUpload} accept=".zip, .html, .htm" showUploadList={false}>
208
- <CapButton>{this.props.intl.formatMessage(messages.upload)}</CapButton>
209
- </CapUploader>
210
- {!_.isEmpty(EmailLayout) &&
211
- <div>{_.get(modeContent, "file.name")}</div>
212
- }
213
- </div>
214
- }
206
+ <div style={{ marginLeft: '8px' }}>
207
+ <CapUploader onChange={this.useFileUpload} accept=".zip, .html, .htm" showUploadList={false}>
208
+ <CapButton>{this.props.intl.formatMessage(messages.upload)}</CapButton>
209
+ </CapUploader>
210
+ {!_.isEmpty(EmailLayout) &&
211
+ <div>{_.get(modeContent, "file.name")}</div>
212
+ }
213
+ </div>
214
+ }
215
215
  </div>
216
216
  </div>
217
217
  :
@@ -4,14 +4,19 @@
4
4
  *
5
5
  */
6
6
 
7
- import {
8
- CHANGE_LOCALE,
9
- } from './constants';
7
+ import * as types from './constants';
10
8
 
11
9
  export function changeLocale(languageLocale) {
12
10
  console.log('trying to change locale', languageLocale);
13
11
  return {
14
- type: CHANGE_LOCALE,
12
+ type: types.CHANGE_LOCALE,
15
13
  locale: languageLocale,
16
14
  };
17
15
  }
16
+
17
+ export function getLocizMessage(locale) {
18
+ return {
19
+ type: types.GET_LOCIZ_MESSAGE_REQUEST,
20
+ locale,
21
+ };
22
+ }
@@ -6,3 +6,10 @@
6
6
 
7
7
  export const CHANGE_LOCALE = 'app/LanguageToggle/CHANGE_LOCALE';
8
8
  export const DEFAULT_LOCALE = 'en';
9
+
10
+ export const GET_LOCIZ_MESSAGE_REQUEST =
11
+ 'app/LanguageProvider/GET_LOCIZ_MESSAGE_REQUEST';
12
+ export const GET_LOCIZ_MESSAGE_SUCCESS =
13
+ 'app/LanguageProvider/GET_LOCIZ_MESSAGE_SUCCESS';
14
+ export const GET_LOCIZ_MESSAGE_FAILURE =
15
+ 'app/LanguageProvider/GET_LOCIZ_MESSAGE_FAILURE';
@@ -9,37 +9,72 @@
9
9
  import PropTypes from 'prop-types';
10
10
 
11
11
  import React from 'react';
12
+ import { ConfigProvider } from 'antd';
13
+ import enUS from 'antd/es/locale-provider/en_US';
14
+ import zhCN from 'antd/es/locale-provider/zh_CN';
12
15
  import { connect } from 'react-redux';
13
- import { createSelector } from 'reselect';
16
+ import { createStructuredSelector } from 'reselect';
14
17
  import { IntlProvider } from 'react-intl';
15
-
18
+ import { bindActionCreators } from 'redux';
19
+ import * as actions from './actions';
16
20
  import { makeSelectLocale } from './selectors';
17
21
 
22
+
18
23
  export class LanguageProvider extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function
24
+ componentDidMount() {
25
+ const user = localStorage.getItem('user');
26
+ let locale = localStorage.getItem('jlocale') || 'en';
27
+ if (user) {
28
+ locale = JSON.parse(user).lang;
29
+ }
30
+ locale = this.getMappedLocale(locale);
31
+ this.props.actions.getLocizMessage(locale);
32
+ }
33
+ /*global getMappedLocale */
34
+ getMappedLocale = (locale) => {
35
+ const map = {
36
+ 'en': 'en-US',
37
+ 'zh-cn': 'zh',
38
+ 'zh': 'zh',
39
+ 'en-US': 'en-US',
40
+ };
41
+ return map[locale];
42
+ };
43
+
19
44
  render() {
45
+ const { locale, messages} = this.props.language;
46
+ const mappedLocale = {
47
+ 'en': enUS,
48
+ 'zh-cn': zhCN,
49
+ 'en-US': enUS,
50
+ 'zh': zhCN,
51
+ };
52
+ const jLocale = localStorage.getItem('jlocale') || 'en';
53
+ const file = mappedLocale[jLocale];
20
54
  return (
21
- <IntlProvider locale={this.props.locale} key={this.props.locale} messages={this.props.messages[this.props.locale]}>
22
- {React.Children.only(this.props.children)}
23
- </IntlProvider>
55
+ <ConfigProvider locale={file}>
56
+ <IntlProvider locale={locale} key={locale} messages={messages}>
57
+ {React.Children.only(this.props.children)}
58
+ </IntlProvider>
59
+ </ConfigProvider>
24
60
  );
25
61
  }
26
62
  }
27
63
 
28
64
  LanguageProvider.propTypes = {
29
- locale: PropTypes.string,
30
- messages: PropTypes.object,
65
+ language: PropTypes.object,
66
+ actions: PropTypes.object,
31
67
  children: PropTypes.element.isRequired,
32
68
  };
33
69
 
34
70
 
35
- const mapStateToProps = createSelector(
36
- makeSelectLocale(),
37
- (locale) => ({ locale })
38
- );
71
+ const mapStateToProps = createStructuredSelector({
72
+ language: makeSelectLocale(),
73
+ });
39
74
 
40
75
  function mapDispatchToProps(dispatch) {
41
76
  return {
42
- dispatch,
77
+ actions: bindActionCreators(actions, dispatch),
43
78
  };
44
79
  }
45
80
 
@@ -6,22 +6,30 @@
6
6
 
7
7
  import { fromJS } from 'immutable';
8
8
 
9
- import {
10
- CHANGE_LOCALE,
11
- } from './constants';
9
+ import * as types from './constants';
12
10
  import {
13
11
  DEFAULT_LOCALE,
14
12
  } from '../Cap/constants'; // eslint-disable-line
15
13
 
16
14
  const initialState = fromJS({
17
15
  locale: DEFAULT_LOCALE,
16
+ messages: {},
17
+ localeLoading: false,
18
18
  });
19
19
 
20
20
  function languageProviderReducer(state = initialState, action) {
21
21
  switch (action.type) {
22
- case CHANGE_LOCALE:
22
+ case types.CHANGE_LOCALE:
23
23
  return state
24
24
  .set('locale', action.locale);
25
+ case types.GET_LOCIZ_MESSAGE_REQUEST:
26
+ return state.set('localeLoading', true);
27
+ case types.GET_LOCIZ_MESSAGE_SUCCESS:
28
+ return state
29
+ .set('localeLoading', false)
30
+ .set('messages', fromJS(action.data));
31
+ case types.GET_LOCIZ_MESSAGE_FAILURE:
32
+ return state.set('localeLoading', false);
25
33
  default:
26
34
  return state;
27
35
  }
@@ -11,7 +11,7 @@ const selectLanguage = (state) => state.get('language');
11
11
 
12
12
  const makeSelectLocale = () => createSelector(
13
13
  selectLanguage,
14
- (languageState) => languageState.get('locale')
14
+ (languageState) => languageState.toJS()
15
15
  );
16
16
 
17
17
  export {
@@ -5,18 +5,16 @@
5
5
  */
6
6
 
7
7
  import PropTypes from 'prop-types';
8
-
9
8
  import React from 'react';
10
9
  import { connect } from 'react-redux';
11
10
  import { injectIntl, intlShape, FormattedMessage } from 'react-intl';
12
11
  import { createStructuredSelector } from 'reselect';
13
12
  import { bindActionCreators } from 'redux';
14
- import styled from 'styled-components';
15
13
  import { CapTab, CapCustomCard, CapButton, CapHeader, CapSpin, CapIcon } from '@capillarytech/cap-ui-library';
16
14
  import { find, get } from 'lodash';
15
+ import isEmpty from 'lodash/isEmpty';
17
16
  import Helmet from 'react-helmet';
18
17
 
19
- import {CAP_SPACE_24, CAP_SPACE_16} from '@capillarytech/cap-ui-library/styled/variables';
20
18
  import { UserIsAuthenticated } from '../../utils/authWrapper';
21
19
  import { makeSelectTemplates, makeSelectTemplatesResponse } from '../Templates/selectors';
22
20
  import messages from './messages';
@@ -24,33 +22,17 @@ import * as actions from './actions';
24
22
  import Templates from '../Templates';
25
23
  import CallTask from '../CallTask';
26
24
  import Gallery from '../Assets/Gallery';
27
- import './_templatesV2.scss';
25
+ import withStyles from '../../hoc/withStyles';
26
+ import styles, { CapTabStyle } from './TemplatesV2.style';
28
27
 
29
28
  const {CapCustomCardList} = CapCustomCard;
30
29
 
31
- const ComponentWrapper = styled.div`
32
- ${(props) => props.isFullMode ? `
33
- max-width: 1140px;
34
- margin: 0 auto;
35
- width: 100%;
36
- padding: ${CAP_SPACE_24} 0;
37
- .ant-tabs-content{
38
- margin-top: ${CAP_SPACE_16}
39
- }
40
- ` : `.cap-tab-v2 {
41
- height: calc(100vh - 118px);
42
- } `}
43
-
44
-
45
- `;
46
- const MarginTop = styled.div`
47
- ${(props) => props.isFullMode ? `margin-top: ${CAP_SPACE_24}` : ``
48
- }
49
- `;
30
+ const StyledCapTab = withStyles(CapTab, CapTabStyle);
31
+
50
32
  export class TemplatesV2 extends React.Component { // eslint-disable-line react/prefer-stateless-function
51
33
  constructor(props) {
52
34
  super(props);
53
- const defaultChannel = get(this, 'props.channel') || get(this, 'props.params.channel') || 'sms';
35
+ let defaultChannel = get(this, 'props.channel') || get(this, 'props.params.channel') || 'sms';
54
36
  const defaultPanes = {
55
37
  sms: {content: <div></div>, tab: props.intl.formatMessage(messages.sms), key: 'sms'},
56
38
  email: {content: <div></div>, tab: props.intl.formatMessage(messages.email), key: 'email'},
@@ -59,8 +41,8 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
59
41
  mPush: {content: <div></div>, tab: props.intl.formatMessage(messages.pushNotification), key: 'mobilepush'},
60
42
  };
61
43
  const channelsToHide = this.props.channelsToHide || [];
62
-
63
- const filteredPanes = Object.keys(defaultPanes)
44
+ const channelsToDisable = this.props.channelsToDisable || [];
45
+ let filteredPanes = Object.keys(defaultPanes)
64
46
  .filter((key) => !channelsToHide.includes(key)).reduce((obj = [], key) => {
65
47
  obj.push(defaultPanes[key]);
66
48
  return obj;
@@ -72,7 +54,26 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
72
54
  filteredPanes.push({content: <div></div>, tab: props.intl.formatMessage(messages.callTask), key: 'call_task'});
73
55
  }
74
56
 
57
+ filteredPanes = filteredPanes.map( (pane) => {
58
+ if (channelsToDisable.includes(pane.key)) {
59
+ pane.disabled = true;
60
+ }
61
+ return pane;
62
+ });
63
+
64
+ const channel = ['sms', 'email', 'mobilepush', 'call_task'];
65
+ if (!isEmpty(channelsToDisable)) {
66
+ channel.some((ch) => {
67
+ if (!channelsToDisable.includes(ch)) {
68
+ defaultChannel = ch;
69
+ return true;
70
+ }
71
+ return false;
72
+ });
73
+ }
74
+
75
75
  const panes = this.setChannelContent(defaultChannel, filteredPanes);
76
+
76
77
  this.state = {
77
78
  selectedChannel: defaultChannel,
78
79
  panes,
@@ -147,21 +148,20 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
147
148
  }
148
149
  }
149
150
 
150
- setChannelContent = (selectedChannel, argsPanes) => {
151
- const panes = argsPanes.map((p) => {
152
- const pane = p;
151
+ setChannelContent = (selectedChannel, argsPanes) => (
152
+ argsPanes.map((pane) => {
153
+ let content = null;
153
154
  if (pane.key === selectedChannel) {
154
- let channel = selectedChannel;
155
- if (channel === "mpush") {
156
- channel = "mobilepush";
157
- }
158
- pane.content = this.getTemplatesComponent(channel);
159
- return pane;
155
+ const channel = selectedChannel === "mpush" ? "mobilepush" : selectedChannel;
156
+ content = this.getTemplatesComponent(channel);
160
157
  }
161
- return {...pane, content: <div></div>};
162
- });
163
- return panes;
164
- }
158
+ return {
159
+ ...pane,
160
+ content,
161
+ };
162
+ })
163
+ );
164
+
165
165
  channelChange = (selectedChannel) => {
166
166
  const panes = this.setChannelContent(selectedChannel, this.state.panes);
167
167
  this.setState({panes, selectedChannel}, () => { if (!this.props.isFullMode) this.props.onChannelChange(selectedChannel); });
@@ -172,28 +172,25 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
172
172
  return this.props.Templates.loadingTemplates;
173
173
  }
174
174
  render() {
175
- const {isFullMode} = this.props;
175
+ const { isFullMode, className } = this.props;
176
176
  return (
177
- <div className={`creatives-templates-container ${isFullMode ? 'fullmode' : 'library-mode'}`}>
177
+ <div className={`${className} creatives-templates-container ${isFullMode ? 'fullmode' : 'library-mode'}`}>
178
178
  {isFullMode && <Helmet
179
179
  title={this.props.intl.formatMessage(messages.creatives)}
180
180
  meta={[
181
181
  { name: 'description', content: this.props.intl.formatMessage(messages.creativesDesc) },
182
182
  ]}
183
183
  />}
184
- <ComponentWrapper isFullMode={isFullMode}>
185
-
184
+ <div className="component-wrapper">
186
185
  {isFullMode && <CapHeader title={<FormattedMessage {...messages.creatives}/>} description={<FormattedMessage {...messages.creativesDesc}/>}/>}
187
- <MarginTop isFullMode={isFullMode}>
188
- <CapTab
189
- panes={this.state.panes}
190
- onChange={this.channelChange}
191
- activeKey={this.state.selectedChannel}
192
- defaultActiveKey={this.state.selectedChannel}/>
193
- </MarginTop>
194
-
195
-
196
- </ComponentWrapper>
186
+ <StyledCapTab
187
+ panes={this.state.panes}
188
+ onChange={this.channelChange}
189
+ activeKey={this.state.selectedChannel}
190
+ defaultActiveKey={this.state.selectedChannel}
191
+ isFullMode={isFullMode}
192
+ />
193
+ </div>
197
194
  </div>
198
195
 
199
196
  );
@@ -213,6 +210,8 @@ TemplatesV2.propTypes = {
213
210
  intl: intlShape,
214
211
  onChannelChange: PropTypes.func,
215
212
  channelsToHide: PropTypes.array,
213
+ className: PropTypes.string.isRequired,
214
+ channelsToDisable: PropTypes.array,
216
215
  };
217
216
 
218
217
  TemplatesV2.defaultProps = {
@@ -230,4 +229,4 @@ function mapDispatchToProps(dispatch) {
230
229
  };
231
230
  }
232
231
 
233
- export default UserIsAuthenticated(connect(mapStateToProps, mapDispatchToProps)(injectIntl(TemplatesV2)));
232
+ export default UserIsAuthenticated(connect(mapStateToProps, mapDispatchToProps)(injectIntl(withStyles(TemplatesV2, styles))));
@@ -1232,7 +1232,7 @@ export class MapTemplates extends React.Component { // eslint-disable-line react
1232
1232
  tip={this.props.intl.formatMessage(messages.gettingTemplateData)}
1233
1233
  spinning={spinning}>
1234
1234
  <div>
1235
- <CapHeading type="h5">Template name</CapHeading>
1235
+ <CapHeading type="h5"><FormattedMessage {...messages.templateName}/></CapHeading>
1236
1236
  <CapHeading type="h3">{weChatData.title}</CapHeading>
1237
1237
  <CapRow className="wechat-container">
1238
1238
  <CapColumn>
@@ -60,7 +60,7 @@ export default defineMessages({
60
60
  },
61
61
  "wechatEditSuccess": {
62
62
  id: 'creatives.containersV2.WeChat.wechatEditSuccess',
63
- defaultMessage: "WeChat template unmapped successfully",
63
+ defaultMessage: "WeChat template edited successfully",
64
64
  },
65
65
  "wechatCreateSuccess": {
66
66
  id: 'creatives.containersV2.WeChat.wechatCreateSuccess',
@@ -87,19 +87,23 @@ export default defineMessages({
87
87
  defaultMessage: "has valid content.",
88
88
  },
89
89
  "select": {
90
- id: 'creatives.containers.WeChat.select',
90
+ id: 'creatives.containersV2.WeChat.select',
91
91
  defaultMessage: 'Select',
92
92
  },
93
93
  "newWechat": {
94
- id: 'creatives.containers.WeChat.newWechat',
94
+ id: 'creatives.containersV2.WeChat.newWechat',
95
95
  defaultMessage: 'New wechat',
96
96
  },
97
97
  "linkErrorMessage": {
98
- id: 'creatives.containers.WeChat.linkErrorMessage',
98
+ id: 'creatives.containersV2.WeChat.linkErrorMessage',
99
99
  defaultMessage: 'Link cannot be empty.',
100
100
  },
101
101
  "hasInvalidContent": {
102
- id: 'creatives.containers.WeChat.hasInvalidContent',
102
+ id: 'creatives.containersV2.WeChat.hasInvalidContent',
103
103
  defaultMessage: 'has invalid content.',
104
104
  },
105
+ "templateName": {
106
+ id: 'creatives.containersV2.WeChat.templateName',
107
+ defaultMessage: 'Template Name',
108
+ },
105
109
  });