@capillarytech/creatives-library 6.12.12 → 6.12.13

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "6.12.12",
4
+ "version": "6.12.13",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -15,7 +15,7 @@
15
15
  "@babel/polyfill": "7.4.3",
16
16
  "@bugsnag/js": "^7.2.1",
17
17
  "@bugsnag/plugin-react": "^7.2.1",
18
- "@capillarytech/cap-ui-utils": "^1.2.8",
18
+ "@capillarytech/cap-ui-utils": "1.3.1",
19
19
  "@mailupinc/bee-plugin": "^1.2.0",
20
20
  "babel-cli": "^6.26.0",
21
21
  "chalk": "1.1.3",
@@ -31,3 +31,7 @@ export const CLEAR_TOPBAR_MENU_DATA = 'creatives/cap/CLEAR_TOPBAR_MENU_DATA';
31
31
  export const CAMPAIGN_SETTINGS_URL = '/creatives/settings/message';
32
32
  export const ORG_SETTINGS_URL = '/org/index';
33
33
  export const HELP_URL = 'https://support.capillarytech.com/en/support/solutions/4000007853';
34
+
35
+ export const ORG_REFRESH_SEC = 10;
36
+ export const ORG_CHANGED = 'ORG_CHANGED';
37
+
@@ -2,15 +2,15 @@ import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
3
  import Helmet from 'react-helmet';
4
4
  import { connect } from 'react-redux';
5
- import {CapNotification} from '@capillarytech/cap-ui-library';
5
+ import { CapNotification, CapModal, CapSnackBar } from '@capillarytech/cap-ui-library';
6
6
  import { bindActionCreators } from 'redux';
7
7
  import styled from 'styled-components';
8
8
  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 } from '@capillarytech/cap-ui-utils';
13
- import { injectIntl, FormattedMessage } from 'react-intl';
12
+ import { GA, multipleOrgSwitch, utilsSessionStorageApi } from '@capillarytech/cap-ui-utils';
13
+ import { injectIntl, FormattedMessage, intlShape, FormattedHTMLMessage } from 'react-intl';
14
14
  import messages from './messages';
15
15
  import { makeSelectAuthenticated, makeSelectUser } from './selectors';
16
16
  import * as actions from './actions';
@@ -25,8 +25,24 @@ import {
25
25
  HELP_URL,
26
26
  ORG_SETTINGS_URL,
27
27
  CAMPAIGN_SETTINGS_URL,
28
+ ORG_REFRESH_SEC,
29
+ ORG_CHANGED
28
30
  } from './constants';
31
+ import './_cap.scss';
32
+ import { BugsnagClient } from '../../app';
33
+
29
34
  const gtm = window.dataLayer || [];
35
+ const {
36
+ logNewTab,
37
+ getOrgNameFromId,
38
+ tabBeforeUnloadEventHandler,
39
+ utilsHandleStorageChange,
40
+ isMultipleTabsOpen,
41
+ } = multipleOrgSwitch;
42
+ const {
43
+ loadSessionItem,
44
+ saveSessionItem,
45
+ } = utilsSessionStorageApi;
30
46
 
31
47
  const CapWrapper = styled.div`
32
48
  margin: 0 auto;
@@ -45,6 +61,11 @@ export class Cap extends React.Component { // eslint-disable-line react/prefer-s
45
61
  this.state = {
46
62
  switchedOrg: false,
47
63
  isCreativesAccessible: true,
64
+ refreshSeconds: ORG_REFRESH_SEC,
65
+ selectedOrgId: null,
66
+ showRefreshModal: false,
67
+ showOrgChangeModal: false,
68
+ localStorageOrgInfo: { oldValue: null, newValue: null },
48
69
  };
49
70
  this.changeOrg = this.changeOrg.bind(this);
50
71
  this.logout = this.logout.bind(this);
@@ -85,6 +106,14 @@ export class Cap extends React.Component { // eslint-disable-line react/prefer-s
85
106
  //locale = 'zh';
86
107
  console.log('Setting final locale as', locale);
87
108
  moment.locale(locale);
109
+ logNewTab(BugsnagClient);
110
+ window.addEventListener('storage', this.handleStorageChange, false);
111
+ document.addEventListener(
112
+ 'visibilitychange',
113
+ this.handleVisibilityChange,
114
+ false,
115
+ );
116
+ window.addEventListener('unload', tabBeforeUnloadEventHandler, false);
88
117
  }
89
118
 
90
119
  componentWillReceiveProps(nextProps) {
@@ -119,10 +148,33 @@ export class Cap extends React.Component { // eslint-disable-line react/prefer-s
119
148
  }
120
149
  }
121
150
 
151
+ componentDidUpdate(prevProps) {
152
+ if (
153
+ !(prevProps.Global.currentOrgDetails) &&
154
+ this.props.Global.currentOrgDetails &&
155
+ loadSessionItem(ORG_CHANGED)
156
+ ) {
157
+ this.showOrgChangeSnackBar();
158
+ }
159
+ }
160
+
122
161
  componentWillUnmount() {
123
162
  this.setState({ switchedOrg: false });
124
163
  this.props.actions.clearTopbarMenuData();
164
+ window.removeEventListener('storage', this.handleStorageChange, false);
165
+ document.removeEventListener(
166
+ 'visibilitychange',
167
+ this.handleVisibilityChange,
168
+ false,
169
+ );
170
+
171
+ window.removeEventListener(
172
+ 'unload',
173
+ this.tabBeforeUnloadEventHandler,
174
+ false,
175
+ );
125
176
  }
177
+
126
178
  setDimensionData() {
127
179
  const userGtmData = this.getUserGtmData();
128
180
  Object.values(userGtmData).forEach((value, index) => {
@@ -158,6 +210,7 @@ export class Cap extends React.Component { // eslint-disable-line react/prefer-s
158
210
  };
159
211
  return map[locale];
160
212
  }
213
+
161
214
  handleRemoveMessage(messageIndex) {
162
215
  this.props.actions.removeMessageFromQueue(messageIndex);
163
216
  }
@@ -172,17 +225,157 @@ export class Cap extends React.Component { // eslint-disable-line react/prefer-s
172
225
  this.props.actions.logout();
173
226
  }
174
227
  changeOrg(orgId) {
175
- this.props.actions.changeOrg(orgId);
176
- this.navigateToDashboard();
228
+ //display orgChangeModal if more than one tabs is open
229
+ if (isMultipleTabsOpen()) {
230
+ this.setState({
231
+ showOrgChangeModal: true,
232
+ selectedOrgId: orgId,
233
+ });
234
+ } else {
235
+ this.props.actions.changeOrg(orgId);
236
+ }
177
237
  }
178
238
 
239
+ showOrgChangeSnackBar = () => {
240
+ saveSessionItem(ORG_CHANGED, false);
241
+ const {
242
+ Global: {
243
+ currentOrgDetails: {
244
+ basic_details: { name: currentOrgName } = {},
245
+ } = {},
246
+ } = {},
247
+ intl: { formatMessage } = {},
248
+ } = this.props;
249
+ CapSnackBar.warning({
250
+ content: (
251
+ <div>
252
+ {formatMessage(messages.orgChangedText)}
253
+ <b>
254
+ {formatMessage(messages.newOrgName, {
255
+ newOrgName: currentOrgName,
256
+ })}
257
+ </b>
258
+ </div>
259
+ ),
260
+ showCloseIcon: true,
261
+ });
262
+ };
263
+
264
+ handleVisibilityChange = () => {
265
+ const activeDoc = document.hidden || false;
266
+ const { showRefreshModal, refreshSeconds } = this.state;
267
+ if (
268
+ activeDoc === false &&
269
+ showRefreshModal &&
270
+ refreshSeconds === ORG_REFRESH_SEC
271
+ ) {
272
+ const timer = setInterval(() => {
273
+ this.setState(prevState => ({
274
+ refreshSeconds: prevState.refreshSeconds - 1,
275
+ }));
276
+ }, 1000);
277
+ setTimeout(() => {
278
+ clearInterval(timer);
279
+ saveSessionItem(ORG_CHANGED, true);
280
+ this.navigateToDashboard();
281
+ }, refreshSeconds * 1000);
282
+ }
283
+ };
284
+
285
+ handleStorageChange = (e) => {
286
+ const { oldValue, newValue } = e;
287
+ if (utilsHandleStorageChange(e, 'orgID')) {
288
+ const localStorageOrgInfo = { oldValue, newValue };
289
+ this.setState({ showRefreshModal: true, localStorageOrgInfo });
290
+ }
291
+ };
292
+
293
+ renderOrgRefreshModal = () => {
294
+ const {
295
+ localStorageOrgInfo: { oldValue: oldOrgId, newValue: newOrgId } = {},
296
+ showRefreshModal,
297
+ refreshSeconds,
298
+ } = this.state;
299
+ const {
300
+ Global: { user: { proxyOrgList } = {} } = {},
301
+ intl: { formatMessage } = {},
302
+ } = this.props;
303
+ const oldOrgName = getOrgNameFromId(Number(oldOrgId), proxyOrgList);
304
+ const newOrgName = getOrgNameFromId(Number(newOrgId), proxyOrgList);
305
+ const modalData = (
306
+ <CapModal
307
+ title={formatMessage(messages.orgRefreshHeading)}
308
+ visible={showRefreshModal}
309
+ closable={false}
310
+ centered
311
+ maskClosable={false}
312
+ footer={null}
313
+ >
314
+ <div className="modal-body">
315
+ <span className="title">
316
+ <FormattedHTMLMessage
317
+ {...messages.refreshOrgText}
318
+ values={{ oldOrgName, newOrgName }}
319
+ />
320
+ </span>
321
+ <div className="content seconds-right">
322
+ {formatMessage(messages.refreshText, {
323
+ time: `${refreshSeconds}s`,
324
+ })}
325
+ </div>
326
+ </div>
327
+ </CapModal>
328
+ );
329
+ return modalData;
330
+ };
331
+
332
+ renderOrgChangeModal = () => {
333
+ const { selectedOrgId, showOrgChangeModal } = this.state;
334
+ const {
335
+ Global: { user: { proxyOrgList } = {},
336
+ currentOrgDetails: { basic_details: { name: oldOrgName } = {} } = {},
337
+ },
338
+ intl: { formatMessage } = {},
339
+ } = this.props;
340
+ const newOrgName = getOrgNameFromId(selectedOrgId, proxyOrgList);
341
+ return (
342
+ <CapModal
343
+ className="change-org-confirm"
344
+ title={formatMessage(messages.areYouSureText)}
345
+ visible={showOrgChangeModal}
346
+ onOk={this.handleOrgChangeOk}
347
+ onCancel={this.handleOrgChangeCancel}
348
+ centered
349
+ okText={formatMessage(messages.changeOk)}
350
+ cancelText={formatMessage(messages.cancel)}
351
+ >
352
+ <FormattedHTMLMessage
353
+ {...messages.orgChangeText}
354
+ values={{ oldOrgName, newOrgName }}
355
+ />
356
+ </CapModal>
357
+ );
358
+ };
359
+
360
+ handleOrgChangeOk = () => {
361
+ const { selectedOrgId: orgId } = this.state;
362
+ if (orgId !== null) {
363
+ this.props.actions.changeOrg(orgId);
364
+ this.setState({ showOrgChangeModal: false });
365
+ }
366
+ };
367
+
368
+ handleOrgChangeCancel = () => {
369
+ this.setState({ showOrgChangeModal: false });
370
+ };
371
+
179
372
  render() {
180
373
  const { Global, location } = this.props;
181
374
  const { topbarMenuData, isLoggedIn, currentOrgDetails } = Global;
182
375
  const topbarMenuDataOptions = topbarMenuData && topbarMenuData.data ? topbarMenuData.data : [];
183
376
  const type = this.props.location.query.type;
184
377
  const toastMessages = this.props.Global.messages;
185
- const { isCreativesAccessible } = this.state;
378
+ const { isCreativesAccessible, showOrgChangeModal, showRefreshModal } = this.state;
186
379
  console.log('v2 locale loading', this.props.loader.localeLoading);
187
380
  return (
188
381
  <CapWrapper>
@@ -231,6 +424,8 @@ export class Cap extends React.Component { // eslint-disable-line react/prefer-s
231
424
  )
232
425
  }
233
426
  </> }
427
+ {showRefreshModal && this.renderOrgRefreshModal()}
428
+ {showOrgChangeModal && this.renderOrgChangeModal()}
234
429
  </CapWrapper>
235
430
  );
236
431
  }
@@ -244,6 +439,7 @@ Cap.propTypes = {
244
439
  appActions: PropTypes.object,
245
440
  locationActions: PropTypes.object,
246
441
  location: PropTypes.object,
442
+ intl: intlShape.isRequired,
247
443
  };
248
444
 
249
445
  const mapStateToProps = createStructuredSelector({
@@ -72,4 +72,45 @@ export default defineMessages({
72
72
  id: 'creatives.containersV2.incentive',
73
73
  defaultMessage: 'Incentive',
74
74
  },
75
+
76
+ //refresh due to org change messages
77
+
78
+ "refreshOrgText": {
79
+ id: `creatives.containersV2.refreshOrgText`,
80
+ defaultMessage:
81
+ 'Refreshing this page & changing the Org from <b>{oldOrgName}</b> to <b>{newOrgName}</b>. At a time only one Org can be selected on the browser.',
82
+ },
83
+ "refreshText": {
84
+ id: `creatives.containersV2.refreshText`,
85
+ defaultMessage: 'Refreshing in {time}...',
86
+ },
87
+ "areYouSureText": {
88
+ id: `creatives.containersV2.areYouSureText`,
89
+ defaultMessage: 'Are you sure?',
90
+ },
91
+ "changeOk": {
92
+ id: `creatives.containersV2.changeOk`,
93
+ defaultMessage: 'Ok, change',
94
+ },
95
+ "cancel": {
96
+ id: `creatives.containersV2.cancel`,
97
+ defaultMessage: 'Cancel',
98
+ },
99
+ "orgChangeText": {
100
+ id: `creatives.containersV2.orgChangeText`,
101
+ defaultMessage:
102
+ 'Changing from <b>{oldOrgName}</b> to <b>{newOrgName}</b> will change the organisation for applications open in other tabs as well.<br/>Do you want to make the change to <b>{newOrgName}</b>?',
103
+ },
104
+ "orgChangedText": {
105
+ id: `creatives.containersV2.orgChangedText`,
106
+ defaultMessage: 'Organization changed to ',
107
+ },
108
+ "orgRefreshHeading": {
109
+ id: `creatives.containersV2.orgRefreshHeading`,
110
+ defaultMessage: 'Org refresh',
111
+ },
112
+ "newOrgName": {
113
+ id: `creatives.containersV2.newOrgName`,
114
+ defaultMessage: '{newOrgName}',
115
+ },
75
116
  });