@capillarytech/creatives-library 7.9.13 → 7.9.15

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 (45) hide show
  1. package/assets/group.png +0 -0
  2. package/components/Card/index.js +1 -1
  3. package/components/Card/tests/__snapshots__/index.test.js.snap +22 -0
  4. package/components/Card/tests/index.test.js +19 -7
  5. package/containers/App/constants.js +2 -1
  6. package/helpers/intl-enzym-test-helpers.js +40 -0
  7. package/index.js +6 -0
  8. package/package.json +3 -2
  9. package/routes.js +5 -0
  10. package/services/api.js +9 -15
  11. package/utils/common.js +17 -4
  12. package/v2Components/CapTagList/index.js +38 -9
  13. package/v2Components/CapTagList/messages.js +4 -0
  14. package/v2Containers/Cap/constants.js +2 -0
  15. package/v2Containers/Cap/index.js +9 -2
  16. package/v2Containers/Cap/reducer.js +5 -1
  17. package/v2Containers/Cap/selectors.js +10 -1
  18. package/v2Containers/CreativesContainer/SlideBoxContent.js +10 -4
  19. package/v2Containers/CreativesContainer/SlideBoxHeader.js +6 -1
  20. package/v2Containers/CreativesContainer/messages.js +4 -0
  21. package/v2Containers/FTP/index.js +14 -4
  22. package/v2Containers/Sms/Create/index.js +5 -6
  23. package/v2Containers/Sms/Edit/sagas.js +1 -1
  24. package/v2Containers/SmsTrai/Create/actions.js +25 -0
  25. package/v2Containers/SmsTrai/Create/constants.js +74 -0
  26. package/v2Containers/SmsTrai/Create/index.js +681 -0
  27. package/v2Containers/SmsTrai/Create/index.scss +92 -0
  28. package/v2Containers/SmsTrai/Create/messages.js +116 -0
  29. package/v2Containers/SmsTrai/Create/reducer.js +43 -0
  30. package/v2Containers/SmsTrai/Create/sagas.js +36 -0
  31. package/v2Containers/SmsTrai/Create/selectors.js +26 -0
  32. package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +10351 -0
  33. package/v2Containers/SmsTrai/Create/tests/index.test.js +77 -0
  34. package/v2Containers/SmsTrai/Create/tests/mockData.js +58 -0
  35. package/v2Containers/SmsTrai/Edit/constants.js +16 -0
  36. package/v2Containers/SmsTrai/Edit/index.js +483 -0
  37. package/v2Containers/SmsTrai/Edit/messages.js +58 -0
  38. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +16103 -0
  39. package/v2Containers/SmsTrai/Edit/tests/index.test.js +61 -0
  40. package/v2Containers/SmsTrai/Edit/tests/mockData.js +36 -0
  41. package/v2Containers/SmsWrapper/index.js +75 -0
  42. package/v2Containers/SmsWrapper/tests/index.test.js +10 -0
  43. package/v2Containers/Templates/_templates.scss +2 -0
  44. package/v2Containers/Templates/index.js +89 -27
  45. package/v2Containers/Templates/messages.js +16 -0
Binary file
@@ -10,7 +10,7 @@ import React from 'react';
10
10
  import { Card } from 'antd';
11
11
  import './_customCard.scss';
12
12
 
13
- class CustomCard extends React.Component { // eslint-disable-line react/prefer-stateless-function
13
+ export class CustomCard extends React.Component { // eslint-disable-line react/prefer-stateless-function
14
14
  constructor(props) {
15
15
  super(props);
16
16
  this.handleMouseHover = this.handleMouseHover.bind(this);
@@ -0,0 +1,22 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`RestrictionPlainInput test Test 1 should render default component when a retriction constant is passed 1`] = `
4
+ <Card
5
+ className="custom-card"
6
+ onClick={[Function]}
7
+ onMouseEnter={[Function]}
8
+ onMouseLeave={[Function]}
9
+ style={
10
+ Object {
11
+ "height": undefined,
12
+ "width": undefined,
13
+ }
14
+ }
15
+ >
16
+ <div>
17
+ <div
18
+ className="content-wrapper"
19
+ />
20
+ </div>
21
+ </Card>
22
+ `;
@@ -1,10 +1,22 @@
1
- // import React from 'react';
2
- // import { shallow } from 'enzyme';
1
+ import React from 'react';
2
+ import { shallowWithIntl } from '../../../helpers/intl-enzym-test-helpers';
3
+ import { CustomCard } from '../index';
3
4
 
4
- // import Card from '../index';
5
+ describe('RestrictionPlainInput test', () => {
6
+
7
+ let renderedComponent;
8
+
9
+ const renderFunc = () => {
10
+ renderedComponent = shallowWithIntl(
11
+ <CustomCard />
12
+ );
13
+ }
14
+
15
+ describe('Test 1', () => {
16
+ it('should render default component when a retriction constant is passed', () => {
17
+ renderFunc();
18
+ expect(renderedComponent).toMatchSnapshot();
19
+ })
20
+ });
5
21
 
6
- describe('<Card />', () => {
7
- it('Expect to have unit tests specified', () => {
8
- expect(true).toEqual(false);
9
- });
10
22
  });
@@ -2,4 +2,5 @@ export const GET_SIDEBAR_REQUEST = 'app/App/GET_SIDEBAR_REQUEST';
2
2
  export const GET_SIDEBAR_SUCCESS = 'app/App/GET_SIDEBAR_SUCCESS';
3
3
  export const GET_SIDEBAR_FAILURE = 'app/App/GET_SIDEBAR_FAILURE';
4
4
 
5
- export const STORE2DOOR_PLUS_ENABLED = 'STORE2DOOR_PLUS_ENABLED';
5
+ export const STORE2DOOR_PLUS_ENABLED = 'STORE2DOOR_PLUS_ENABLED';
6
+ export const TRAI_DLT = 'TRAI_DLT';
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Components using the react-intl module require access to the intl context.
3
+ * This is not available when mounting single components in Enzyme.
4
+ * These helper functions aim to address that and wrap a valid,
5
+ * English-locale intl context around them.
6
+ */
7
+
8
+ import React from 'react';
9
+ import { IntlProvider, intlShape } from 'react-intl';
10
+ import { mount, shallow, configure } from 'enzyme';
11
+ import Adapter from 'enzyme-adapter-react-16';
12
+
13
+ configure({ adapter: new Adapter() });
14
+ // You can pass your messages to the IntlProvider. Optional: remove if unneeded.
15
+ const messages = require('../translations/en.json'); // en.json
16
+
17
+ // Create the IntlProvider to retrieve context for wrapping around.
18
+ const intlProvider = new IntlProvider({ locale: 'en', messages }, {});
19
+ const { intl } = intlProvider.getChildContext();
20
+
21
+ /**
22
+ * When using React-Intl `injectIntl` on components, props.intl is required.
23
+ */
24
+ function nodeWithIntlProp(node) {
25
+ return React.cloneElement(node, { intl });
26
+ }
27
+
28
+ /**
29
+ * Export these methods.
30
+ */
31
+ export function shallowWithIntl(node) {
32
+ return shallow(nodeWithIntlProp(node), { context: { intl } });
33
+ }
34
+
35
+ export function mountWithIntl(node) {
36
+ return mount(nodeWithIntlProp(node), {
37
+ context: { intl },
38
+ childContextTypes: { intl: intlShape },
39
+ });
40
+ }
package/index.js CHANGED
@@ -83,6 +83,10 @@ import CreativesContainer from './v2Containers/CreativesContainer';
83
83
  import CreativesContainerReducer from './v2Containers/CreativesContainer/reducer';
84
84
  import { updateCharCount } from './utils/smsCharCountV2';
85
85
 
86
+ import SmsTraiCreate from './v2Containers/SmsTrai/Create';
87
+ import SmsTraiCreateReducer from './v2Containers/SmsTrai/Create/reducer';
88
+ import SmsTraiCreateSaga from './v2Containers/SmsTrai/Create/sagas';
89
+
86
90
  export {default as Ebill} from './v2Containers/Ebill';
87
91
  export {default as EbillReducer} from './v2Containers/Ebill/reducer';
88
92
  export {default as EbillSaga} from './v2Containers/Ebill/sagas';
@@ -106,6 +110,7 @@ const TemplatesV2Container = {TemplatesV2, templateReducer, templateSaga};
106
110
  const FacebookContainer = {Facebook, facebookReducer, facebookSaga};
107
111
  const ViberContainer = {Viber, viberReducer, viberSaga};
108
112
  const FacebookPreviewContainer = { FacebookPreview, facebookPreviewReducer, facebookPreviewSaga };
113
+ const SmsTraiContainer = {SmsTraiCreate, SmsTraiCreateReducer, SmsTraiCreateSaga};
109
114
 
110
115
  const GalleryContainer = {Gallery, galleryReducer, gallerySagas};
111
116
  const FTPContainer = {FTP, FTPReducer, FTPSagas};
@@ -151,4 +156,5 @@ export { CapContainer,
151
156
  FTPContainer,
152
157
  ViberContainer,
153
158
  FacebookPreviewContainer,
159
+ SmsTraiContainer,
154
160
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "7.9.13",
4
+ "version": "7.9.15",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -12,7 +12,6 @@
12
12
  },
13
13
  "license": "LicenseRef-LICENSE",
14
14
  "dependencies": {
15
- "@babel/polyfill": "7.4.3",
16
15
  "@bugsnag/js": "^7.2.1",
17
16
  "@bugsnag/plugin-react": "^7.2.1",
18
17
  "@capillarytech/cap-ui-utils": "1.4.0",
@@ -24,7 +23,9 @@
24
23
  "jquery": "^3.3.1",
25
24
  "load-script": "^1.0.0",
26
25
  "normalizr": "^3.2.3",
26
+ "papaparse": "^5.3.1",
27
27
  "react-datepicker": "^0.46.0",
28
+ "react-dropzone": "^11.3.4",
28
29
  "react-router": "^3.2.0",
29
30
  "react-router-dom": "^4.2.2",
30
31
  "redux": "3.6.0",
package/routes.js CHANGED
@@ -639,6 +639,8 @@ export default function createRoutes(store) {
639
639
  import('v2Containers/Viber/reducer'),
640
640
  import('v2Containers/CapFacebookPreview/sagas'),
641
641
  import('v2Containers/CapFacebookPreview/reducer'),
642
+ import('v2Containers/SmsTrai/Create/sagas'),
643
+ import('v2Containers/SmsTrai/Create/reducer'),
642
644
  ]);
643
645
 
644
646
  const renderRoute = loadModule(cb);
@@ -661,6 +663,7 @@ export default function createRoutes(store) {
661
663
  lineCreateSagas, lineCreateReducer,
662
664
  viberSagas, viberReducer,
663
665
  capFacebookPreviewSagas, capFacebookPreviewReducer,
666
+ smsTraiSagas, smsTraiReducer,
664
667
  ]) => {
665
668
  injectReducer('templates', reducer.default);
666
669
  injectReducer('cap', capReducer.default);
@@ -679,6 +682,7 @@ export default function createRoutes(store) {
679
682
  injectReducer('lineCreate', lineCreateReducer.default);
680
683
  injectReducer('viber', viberReducer.default);
681
684
  injectReducer('facebookPreview', capFacebookPreviewReducer.default);
685
+ injectReducer('smsTrai', smsTraiReducer.default);
682
686
  injectSagas(gallerySagas.default);
683
687
  injectSagas(sagas.default);
684
688
  injectSagas(capSagas.default);
@@ -696,6 +700,7 @@ export default function createRoutes(store) {
696
700
  injectSagas(lineCreateSagas.default);
697
701
  injectSagas(viberSagas.default);
698
702
  injectSagas(capFacebookPreviewSagas.default);
703
+ injectSagas(smsTraiSagas.default);
699
704
  renderRoute(component);
700
705
  });
701
706
  importModules.catch(errorLoading);
package/services/api.js CHANGED
@@ -40,7 +40,7 @@ function getUrlWithQueryParams({url, queryParams}) {
40
40
  }
41
41
  });
42
42
  return updatedUrl;
43
- };
43
+ }
44
44
 
45
45
  // const loginUrl = (process.env.NODE_ENV === 'production') ?
46
46
  // config.production.login_url : config.development.login_url;
@@ -81,7 +81,7 @@ function checkStatus(response) {
81
81
  description: `API Error ${requestCallerName} returned ${status}`,
82
82
  fatal: true,
83
83
  apiError: true,
84
- statusCode: status
84
+ statusCode: status,
85
85
  });
86
86
  }
87
87
  if ((status >= 200 && status < 300) || [500, 409, 413].includes(response.status)) {
@@ -99,7 +99,7 @@ function request(url, options) {
99
99
  try {
100
100
  requestCallerName = getCallerName();
101
101
  } catch (e) {
102
-
102
+
103
103
  }
104
104
  const fetchUrl = url.indexOf('?') !== -1 ? `${url}&time=${Date.now()}` : `${url}?time=${Date.now()}`;
105
105
  return fetch(fetchUrl, options)
@@ -197,36 +197,31 @@ export const getSidebar = () => {
197
197
  };
198
198
 
199
199
  export const getUserData = () => {
200
- const url = `${API_AUTH_ENDPOINT}/user`;
200
+ const url = `${API_AUTH_ENDPOINT}/user?include_features=1`;
201
201
  return request(url, getAPICallObject('GET'));
202
202
  };
203
203
 
204
204
  export const createTemplate = ({template}) => {
205
-
206
205
  const url = `${API_ENDPOINT}/templates/SMS`;
207
206
  return request(url, getAPICallObject('POST', template));
208
207
  };
209
208
 
210
209
  export const editTemplate = ({template}) => {
211
-
212
210
  const url = `${API_ENDPOINT}/templates/SMS`;
213
211
  return request(url, getAPICallObject('POST', template));
214
212
  };
215
213
 
216
214
  export const createWeChatTemplate = ({template}) => {
217
-
218
215
  const url = `${API_ENDPOINT}/templates/WECHAT`;
219
216
  return request(url, getAPICallObject('POST', template));
220
217
  };
221
218
 
222
219
  export const createMobilePushTemplate = ({template}) => {
223
-
224
220
  const url = `${API_ENDPOINT}/templates/MOBILEPUSH`;
225
221
  return request(url, getAPICallObject('POST', template));
226
222
  };
227
223
 
228
224
  export const duplicateTemplate = ({id, channel}) => {
229
-
230
225
  const url = `${API_ENDPOINT}/templates/duplicate/${id}/${channel}`;
231
226
  return request(url, getAPICallObject('GET'));
232
227
  };
@@ -237,25 +232,21 @@ export const getFTPServers = () => {
237
232
  };
238
233
 
239
234
  export const editWeChatTemplate = ({template}) => {
240
-
241
235
  const url = `${API_ENDPOINT}/templates/WECHAT`;
242
236
  return request(url, getAPICallObject('POST', template));
243
237
  };
244
238
 
245
239
  export const createEmailTemplate = ({template}) => {
246
-
247
240
  const url = `${API_ENDPOINT}/templates/EMAIL`;
248
241
  return request(url, getAPICallObject('POST', template));
249
242
  };
250
243
 
251
244
  export const createEbillTemplate = ({template}) => {
252
-
253
245
  const url = `${API_ENDPOINT}/templates/EBILL`;
254
246
  return request(url, getAPICallObject('POST', template));
255
247
  };
256
248
 
257
249
  export const getTemplateDetails = ({id, channel}) => {
258
-
259
250
  const url = `${API_ENDPOINT}/templates/${id}/${channel ? channel.toUpperCase() : 'SMS'}`;
260
251
  return request(url, getAPICallObject('GET'));
261
252
  };
@@ -367,7 +358,6 @@ export const getCmsData = (cmsType, projectId, langId) => {
367
358
  };
368
359
 
369
360
  export const getEdmTemplates = () => {
370
-
371
361
  const url = `${API_ENDPOINT}/templates/email/default`;
372
362
  return request(url, getAPICallObject('GET'));
373
363
  };
@@ -380,7 +370,6 @@ export const getDefaultBeeTemplates = () => {
380
370
  // All about line
381
371
 
382
372
  export const createLineTemplate = ({template}) => {
383
-
384
373
  const url = `${API_ENDPOINT}/templates/LINE`;
385
374
  return request(url, getAPICallObject('POST', template));
386
375
  };
@@ -449,3 +438,8 @@ export const getFacebookVideoId = ({videoUrl, accessToken, actId, pageAccessToke
449
438
  const url = `${API_ENDPOINT}/facebook/getFacebookVideoId`;
450
439
  return request(url, getAPICallObject('POST', {videoUrl, accessToken, actId, pageAccessToken, pageId}));
451
440
  };
441
+
442
+ export const createBulkSMSTemplate = ({templates}) => {
443
+ const url = `${API_ENDPOINT}/templates/bulk/sms`;
444
+ return request(url, getAPICallObject('POST', templates));
445
+ };
package/utils/common.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import _ from 'lodash';
2
2
  import { Auth } from '@capillarytech/cap-ui-utils';
3
- import { STORE2DOOR_PLUS_ENABLED } from '../containers/App/constants';
3
+ import { STORE2DOOR_PLUS_ENABLED, TRAI_DLT } from '../containers/App/constants';
4
4
 
5
5
  export function getUserNameById(userId, allUserList) {
6
6
  let userName = "";
@@ -38,9 +38,16 @@ export const hasStore2DoorFeature = Auth.hasFeatureAccess.bind(
38
38
  STORE2DOOR_PLUS_ENABLED,
39
39
  );
40
40
 
41
- export function getTreeStructuredTags({tagsList, userLocale = 'en', offerDetails = []}) {
41
+ export const hasTraiDltFeature = Auth.hasFeatureAccess.bind(
42
+ null,
43
+ TRAI_DLT,
44
+ );
45
+
46
+ export function getTreeStructuredTags({tagsList, userLocale = 'en', offerDetails = [], disableTagsDetails = {}}) {
42
47
  console.log('populating tags', (tagsList || []).length);
43
48
  const mainTags = {};
49
+ const { disableRelatedTags, childTagsToDisable, parentTagstoDisable} = disableTagsDetails;
50
+
44
51
 
45
52
  _.forEach(tagsList, (temp) => {
46
53
  const tag = temp.definition;
@@ -48,6 +55,7 @@ export function getTreeStructuredTags({tagsList, userLocale = 'en', offerDetails
48
55
  mainTags[tag.value] = {
49
56
  name: tag.label[userLocale] || tag.label.en,
50
57
  value: tag.value,
58
+ disabled: disableRelatedTags ? childTagsToDisable.includes(tag.value) : false,
51
59
  };
52
60
  } else if (tag['tag-header'] && mainTags[tag.value]) {
53
61
  // to check it this tag header is already available in mainTags object,
@@ -60,6 +68,7 @@ export function getTreeStructuredTags({tagsList, userLocale = 'en', offerDetails
60
68
  "name": tag.label[userLocale] || tag.label.en,
61
69
  "subtags": tag.subtags,
62
70
  "value": tag.value,
71
+ "disabled": disableRelatedTags ? parentTagstoDisable.includes(tag.value) : false,
63
72
  };
64
73
  }
65
74
  });
@@ -175,17 +184,19 @@ function populateTagForChildren(targetTag, tagsObject, tagValue) {
175
184
  function getTreeStructureData(data) {
176
185
  const result = [];
177
186
  _.forOwn(data, (mainTag) => {
178
- const { name, value, subtags = [] } = mainTag;
187
+ const { name, value, subtags = [], disabled } = mainTag;
179
188
  if (!mainTag['tag-header']) {
180
189
  result.push({
181
190
  title: name,
182
191
  value: `{{${value}}}`,
192
+ disabled,
183
193
  });
184
194
  } else {
185
195
  const obj = {
186
196
  title: name,
187
197
  value: `{{${value}}}`,
188
198
  selectable: false,
199
+ disabled,
189
200
  };
190
201
  obj.children = getSubTags(subtags);
191
202
  result.push(obj);
@@ -197,17 +208,19 @@ function getTreeStructureData(data) {
197
208
  function getSubTags(subtagsParam) {
198
209
  const result = [];
199
210
  _.forOwn(subtagsParam, (subTag) => {
200
- const { name, value, subtags = [] } = subTag;
211
+ const { name, value, subtags = [], disabled } = subTag;
201
212
  if (_.isEmpty(subtags)) {
202
213
  result.push({
203
214
  title: name,
204
215
  value: `{{${value}}}`,
216
+ disabled,
205
217
  });
206
218
  } else {
207
219
  const obj = {
208
220
  title: name,
209
221
  value: `{{${value}}}`,
210
222
  selectable: false,
223
+ disabled,
211
224
  };
212
225
  obj.children = getSubTags(subtags);
213
226
  result.push(obj);
@@ -5,19 +5,20 @@
5
5
  */
6
6
 
7
7
  import PropTypes from 'prop-types';
8
-
9
8
  import React from 'react';
9
+ import { connect } from 'react-redux';
10
10
  // import styled from 'styled-components';
11
- import { CapSpin, CapModal, CapButton, CapPopover, CapInput, CapTree, CapSelect } from '@capillarytech/cap-ui-library';
11
+ import { CapSpin, CapModal, CapButton, CapPopover, CapInput, CapTree, CapSelect, CapTooltip } from '@capillarytech/cap-ui-library';
12
12
 
13
13
  import _ from 'lodash';
14
- import { injectIntl, intlShape } from 'react-intl';
14
+ import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
15
+ import { createStructuredSelector } from 'reselect';
15
16
  import messages from './messages';
17
+ import { makeSelectLoyaltyPromotionDisplay } from '../../v2Containers/Cap/selectors';
16
18
 
17
19
  const {Search} = CapInput;
18
20
  const {CapTreeNode} = CapTree;
19
21
  class CapTagList extends React.Component { // eslint-disable-line react/prefer-stateless-function
20
-
21
22
  constructor(props) {
22
23
  super(props);
23
24
  this.state = {
@@ -132,23 +133,39 @@ class CapTagList extends React.Component { // eslint-disable-line react/prefer-s
132
133
  };
133
134
 
134
135
  renderTags(tags, searchString = '') {
136
+ const { disableRelatedTags, childTagsToDisable, parentTagstoDisable} = this.props.disableTagsDetails;
135
137
  const list = [];
138
+ const loyaltyAttrDisableText = <FormattedMessage {...messages.loyaltyAttributeDisable} />;
136
139
  _.forEach(tags, (val = '', key) => {
137
140
  let supportedTagsString = '';
138
141
  _.forEach(val.supportedTags, (supportedTag) => {
139
142
  supportedTagsString += `${supportedTag} ,`;
140
143
  });
141
144
  supportedTagsString = supportedTagsString.replace(/,\s*$/, "");
142
-
143
145
  if (_.has(val, 'subtags')) {
144
- const temp = this.renderTags(val.subtags);
146
+ const disabled = disableRelatedTags ? parentTagstoDisable.includes(key) : false;
147
+ const temp = this.renderTags(val.subtags, '', disabled);
145
148
  list.push((
146
- <CapTreeNode title={val.name} tag={val} key={val.couponSeriesId ? `${key}(${val.couponSeriesId})` : `${key}`}>
149
+ <CapTreeNode
150
+ title={disabled ? <CapTooltip title={loyaltyAttrDisableText}>{val.name}</CapTooltip> : val.name}
151
+ tag={val}
152
+ key={val.couponSeriesId ? `${key}(${val.couponSeriesId})` : `${key}`}
153
+ disabled={disabled}
154
+ >
147
155
  {temp}
148
156
  </CapTreeNode>
149
157
  ));
150
158
  } else if (searchString === '' || !searchString || ((val.name || '').toLowerCase().indexOf(searchString.toLowerCase()) !== -1)) {
151
- const tempNode = (<CapTreeNode title={val.desc || val.name} tag={val} isLeaf key={val.couponSeriesId ? `${key}(${val.couponSeriesId})` : `${key}`}></CapTreeNode>);
159
+ const childDisabled = disableRelatedTags ? childTagsToDisable.includes(key) : false;
160
+ const tempNode = (
161
+ <CapTreeNode
162
+ title={childDisabled ? <CapTooltip title={loyaltyAttrDisableText}>{val.desc || val.name}</CapTooltip> : (val.desc || val.name)}
163
+ tag={val}
164
+ isLeaf
165
+ key={val.couponSeriesId ? `${key}(${val.couponSeriesId})` : `${key}`}
166
+ disabled={childDisabled}
167
+ >
168
+ </CapTreeNode>);
152
169
  list.push(tempNode);
153
170
  }
154
171
  });
@@ -253,10 +270,22 @@ CapTagList.propTypes = {
253
270
  visibleTaglist: PropTypes.bool,
254
271
  hidePopover: PropTypes.bool,
255
272
  modalProps: PropTypes.any,
273
+ disableTagsDetails: PropTypes.object,
256
274
  };
257
275
 
258
276
  CapTagList.defaultValue = {
259
277
  hidePopover: false,
260
278
  };
261
279
 
262
- export default injectIntl(CapTagList);
280
+ function mapDispatchToProps() {
281
+ return {
282
+ };
283
+ }
284
+
285
+ const mapStateToProps = createStructuredSelector({
286
+ disableTagsDetails: makeSelectLoyaltyPromotionDisplay(),
287
+ });
288
+
289
+
290
+ export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(CapTagList));
291
+
@@ -42,4 +42,8 @@ export default defineMessages({
42
42
  id: 'creatives.componentsV2.CapTagList.search',
43
43
  defaultMessage: 'Search',
44
44
  },
45
+ "loyaltyAttributeDisable": {
46
+ id: `creatives.componentsV2.CapTagList.loyaltyAttributeDisable`,
47
+ defaultMessage: 'You won’t be able to add loyalty related attributes since the loyalty program/ card series is None.',
48
+ },
45
49
  });
@@ -28,6 +28,8 @@ export const GET_TOPBAR_MENU_DATA_SUCCESS = 'creatives/cap/GET_TOPBAR_MENU_DATA_
28
28
  export const GET_TOPBAR_MENU_DATA_FAILURE = 'creatives/cap/GET_TOPBAR_MENU_DATA_FAILURE';
29
29
  export const CLEAR_TOPBAR_MENU_DATA = 'creatives/cap/CLEAR_TOPBAR_MENU_DATA';
30
30
 
31
+ export const SET_LOYALTY_PROMOTION_RELATED_CREATIVE_TAGS_DISPLAY = 'SET_LOYALTY_PROMOTION_RELATED_CREATIVE_TAGS_DISPLAY';
32
+
31
33
  export const CAMPAIGN_SETTINGS_URL = '/creatives/settings/message';
32
34
  export const ORG_SETTINGS_URL = '/org/index';
33
35
  export const HELP_URL = 'https://support.capillarytech.com/en/support/solutions/4000007853';
@@ -9,7 +9,7 @@ import { createStructuredSelector } from 'reselect';
9
9
  import _ from 'lodash';
10
10
  import moment from 'moment';
11
11
  // import 'moment/locale/zh-cn';
12
- import { GA, multipleOrgSwitch, utilsSessionStorageApi } from '@capillarytech/cap-ui-utils';
12
+ import { GA, multipleOrgSwitch, utilsSessionStorageApi, Auth } from '@capillarytech/cap-ui-utils';
13
13
  import { injectIntl, FormattedMessage, intlShape, FormattedHTMLMessage } from 'react-intl';
14
14
  import messages from './messages';
15
15
  import { makeSelectAuthenticated, makeSelectUser } from './selectors';
@@ -28,7 +28,6 @@ import {
28
28
  ORG_CHANGED,
29
29
  } from './constants';
30
30
  import './_cap.scss';
31
-
32
31
  const gtm = window.dataLayer || [];
33
32
  const {
34
33
  logNewTab,
@@ -75,12 +74,20 @@ export class Cap extends React.Component { // eslint-disable-line react/prefer-s
75
74
  const { pathname } = this.props.location;
76
75
  const parentModule = pathname.substring(pathname.lastIndexOf('/') + 1);
77
76
  this.props.actions.getUserData((userData) => {
77
+ const { currentOrgDetails } = this.props.Global || {};
78
+ const { accessibleFeatures = [] } = currentOrgDetails || {};
78
79
  if (!userData.accessiblePermissions.includes(CREATIVES_UI_VIEW)) {
79
80
  this.setState({ isCreativesAccessible: false });
80
81
  }
81
82
  const userGtmData = this.getUserGtmData();
82
83
  this.setDimensionData(userGtmData);
83
84
  gtm.push({...userGtmData, event: 'userAuthenticated'});
85
+ Auth.initialize({
86
+ permissions: userData.accessiblePermissions,
87
+ isCapUser: userData.isCapUser,
88
+ roles: Object.keys(userData.accessRoles),
89
+ accessibleFeatures,
90
+ });
84
91
  });
85
92
  this.props.actions.getTopbarMenuData(parentModule);
86
93
  if (this.props.Global.orgID !== undefined) {
@@ -82,7 +82,6 @@ function capReducer(state = fromJS(initialState.cap), action) {
82
82
  .set('fetchingSchema', false);
83
83
  case types.GET_SCHEMA_FOR_ENTITY_SUCCESS: {
84
84
  const stateMeta = state.get('metaEntities');
85
-
86
85
  return state
87
86
  .set('fetchingSchema', false)
88
87
  .set('metaEntities', {
@@ -117,6 +116,11 @@ function capReducer(state = fromJS(initialState.cap), action) {
117
116
  );
118
117
  case types.CLEAR_TOPBAR_MENU_DATA:
119
118
  return state.set('topbarMenuData', fromJS({}));
119
+ case types.SET_LOYALTY_PROMOTION_RELATED_CREATIVE_TAGS_DISPLAY: {
120
+ return state.set('disableLoyaltyPromotionRelatedTags', action.disable)
121
+ .set('tagsToDisable', action.tagsToDisable)
122
+ .set('parentTagsToDisable', action.parentTagsToDisable);
123
+ }
120
124
  default:
121
125
  return state;
122
126
  }
@@ -31,7 +31,6 @@ const setInjectedTags = () => createSelector(
31
31
  const { tags } = metaEntities;
32
32
  const customTags = tags && (tags.custom || {});
33
33
  const extendedTags = tags && (tags.extended || {});
34
-
35
34
  return (injectedTags = _.merge({}, injectedTags, customTags, extendedTags));
36
35
  }
37
36
  );
@@ -74,6 +73,15 @@ const makeSelectFetchingSchema = () => createSelector(
74
73
  (globalState) => globalState.get('fetchingSchema')
75
74
  );
76
75
 
76
+ const makeSelectLoyaltyPromotionDisplay = () => createSelector(
77
+ selectCapDomain,
78
+ (globalState) => ({
79
+ disableRelatedTags: globalState.get('disableLoyaltyPromotionRelatedTags'),
80
+ childTagsToDisable: globalState.get('tagsToDisable') || [],
81
+ parentTagstoDisable: globalState.get('parentTagsToDisable') || [],
82
+ }),
83
+ );
84
+
77
85
  export {
78
86
  makeSelectLocationState,
79
87
  makeSelectAuthenticated,
@@ -85,4 +93,5 @@ export {
85
93
  isLoadingMetaEntities,
86
94
  makeSelectFetchingSchema,
87
95
  setInjectedTags,
96
+ makeSelectLoyaltyPromotionDisplay,
88
97
  };
@@ -5,8 +5,8 @@ import get from 'lodash/get';
5
5
  import cloneDeep from 'lodash/cloneDeep';
6
6
  import TemplatesV2 from '../TemplatesV2';
7
7
  import TemplatePreview from '../../v2Components/TemplatePreview';
8
- import SmsCreate from '../Sms/Create';
9
- import SmsEdit from '../Sms/Edit';
8
+ import SmsWrapper from '../SmsWrapper';
9
+ // import SmsEdit from '../Sms/Edit';
10
10
  import Email from '../Email';
11
11
  import EmailWrapper from '../EmailWrapper';
12
12
  import MobilepushWrapper from '../MobilepushWrapper';
@@ -394,8 +394,9 @@ function SlideBoxContent(props) {
394
394
  />
395
395
  }
396
396
  {isEditSms && (
397
- <SmsEdit
397
+ <SmsWrapper
398
398
  setIsLoadingContent={setIsLoadingContent}
399
+ isEditSms={isEditSms}
399
400
  location={creativesLocationProps}
400
401
  isFullMode={isFullMode}
401
402
  route={{ name: 'sms' }}
@@ -408,6 +409,8 @@ function SlideBoxContent(props) {
408
409
  selectedOfferDetails={selectedOfferDetails}
409
410
  onPreviewContentClicked={onPreviewContentClicked}
410
411
  onTestContentClicked={onTestContentClicked}
412
+ handleClose={handleClose}
413
+ onCreateComplete={onCreateComplete}
411
414
  />
412
415
  )}
413
416
  {isEditFTP && (
@@ -440,10 +443,11 @@ function SlideBoxContent(props) {
440
443
  />
441
444
  }
442
445
  {isCreateSms && (
443
- <SmsCreate
446
+ <SmsWrapper
444
447
  setIsLoadingContent={setIsLoadingContent}
445
448
  location={creativesLocationProps}
446
449
  route={{ name: 'sms' }}
450
+ isCreateSms={isCreateSms}
447
451
  isComponent
448
452
  isGetFormData={isGetFormData}
449
453
  getFormSubscriptionData={getFormData}
@@ -453,8 +457,10 @@ function SlideBoxContent(props) {
453
457
  selectedOfferDetails={selectedOfferDetails}
454
458
  onPreviewContentClicked={onPreviewContentClicked}
455
459
  onTestContentClicked={onTestContentClicked}
460
+ onCreateComplete={onCreateComplete}
456
461
  />
457
462
  )}
463
+
458
464
  {isEmailCreate && (
459
465
  <EmailWrapper
460
466
  key="creatives-email-wrapper"