qpp-style 9.33.0 → 9.33.2
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/.editorconfig +1 -1
- package/components/Header/HeaderAccountMenu.jsx +2 -2
- package/components/Session/Session.jsx +99 -0
- package/components/Session/SessionDialogWrapped.jsx +12 -0
- package/components/Session/index.jsx +3 -0
- package/dist/browser.js +1 -1
- package/dist/browser.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/index.js.map +1 -1
- package/index.js +3 -3
- package/package.json +1 -1
- package/session/refresh.js +2 -3
- package/session/ttl.js +3 -3
- package/components/SessionDialog/sessionDialog.js +0 -26
- package/components/SessionDialogUI.jsx +0 -241
- package/test/components/SessionDialogUI.test.js +0 -312
package/.editorconfig
CHANGED
|
@@ -2,8 +2,8 @@ import React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { useHeaderState } from './hooks';
|
|
4
4
|
import { setUtagLink } from './utag-helpers';
|
|
5
|
-
import SessionDialogUI from '../SessionDialogUI';
|
|
6
5
|
import HeaderMenuItem from './HeaderMenuItem';
|
|
6
|
+
import Session from '../Session';
|
|
7
7
|
|
|
8
8
|
const HeaderAccountMenu = ({ handleClick, isLoginEnabled, isDevPre }) => {
|
|
9
9
|
const { closeMenus, RouterLink, headerContent } = useHeaderState();
|
|
@@ -66,7 +66,7 @@ const HeaderAccountMenu = ({ handleClick, isLoginEnabled, isDevPre }) => {
|
|
|
66
66
|
if (isLoggedIn) {
|
|
67
67
|
return (
|
|
68
68
|
<>
|
|
69
|
-
<
|
|
69
|
+
<Session />
|
|
70
70
|
<HeaderMenuItem
|
|
71
71
|
hasMenu
|
|
72
72
|
menuName="Login"
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import cookie from 'cookie';
|
|
3
|
+
import Modal from '../Modal';
|
|
4
|
+
import { fetchTtl } from '../../session';
|
|
5
|
+
import refreshSession from '../../session/refresh';
|
|
6
|
+
import logoutSession from '../../session/logout';
|
|
7
|
+
|
|
8
|
+
// calculate TWO_MINUTES for interval
|
|
9
|
+
const SECOND = 1000;
|
|
10
|
+
const MINUTE = 60 * SECOND;
|
|
11
|
+
const TWO_MINUTES = 2 * MINUTE;
|
|
12
|
+
const DEFAULT_SESSION_CHECK_INTERVAL = TWO_MINUTES;
|
|
13
|
+
|
|
14
|
+
// This Dialog shows up 2 minutes before the user session ends
|
|
15
|
+
// giving the user an opportunity to refresh the token
|
|
16
|
+
// or to sign out
|
|
17
|
+
const InactiveDialog = () => {
|
|
18
|
+
const [isOpen, setIsOpen] = useState(true);
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const timeout = setTimeout(() => logoutSession(window), TWO_MINUTES);
|
|
22
|
+
return () => clearInterval(timeout);
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<Modal
|
|
27
|
+
useDesignSystem
|
|
28
|
+
title="You will be signed out within two minutes"
|
|
29
|
+
isOpen={isOpen}
|
|
30
|
+
primary={{
|
|
31
|
+
title: 'Keep me signed in',
|
|
32
|
+
onClick: () => {
|
|
33
|
+
refreshSession();
|
|
34
|
+
setIsOpen(false);
|
|
35
|
+
},
|
|
36
|
+
}}
|
|
37
|
+
secondary={{
|
|
38
|
+
title: 'Sign me out now',
|
|
39
|
+
onClick: () => logoutSession(window),
|
|
40
|
+
}}
|
|
41
|
+
onRequestClose={() => setIsOpen(false)}
|
|
42
|
+
>
|
|
43
|
+
<p>
|
|
44
|
+
You have been inactive for thirty minutes. For your security, we will
|
|
45
|
+
sign you out automatically.
|
|
46
|
+
</p>
|
|
47
|
+
</Modal>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// 120 seconds is 2 minutes
|
|
52
|
+
const DEFAULT_WARNING_TIMEOUT_SECONDS = 120;
|
|
53
|
+
function shouldShowInactiveDialog(
|
|
54
|
+
timeRemainingSeconds,
|
|
55
|
+
warningTimeoutSeconds = DEFAULT_WARNING_TIMEOUT_SECONDS,
|
|
56
|
+
) {
|
|
57
|
+
return timeRemainingSeconds < warningTimeoutSeconds;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const Session = () => {
|
|
61
|
+
const [isInactiveDialogOpen, setIsInactiveDialogOpen] = useState(false);
|
|
62
|
+
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
let didCancel = false;
|
|
65
|
+
const cookies = cookie.parse(document.cookie);
|
|
66
|
+
const hasAuthToken = !!cookies.qpp_auth_token;
|
|
67
|
+
async function isSessionValid() {
|
|
68
|
+
if (hasAuthToken) {
|
|
69
|
+
const timeRemaining = await fetchTtl(cookies.qpp_auth_token);
|
|
70
|
+
// safeguard against unmounted component
|
|
71
|
+
if (didCancel) return;
|
|
72
|
+
|
|
73
|
+
// token expired
|
|
74
|
+
if (timeRemaining === 0) {
|
|
75
|
+
logoutSession(window);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// token is about to expire
|
|
79
|
+
if (shouldShowInactiveDialog(timeRemaining)) {
|
|
80
|
+
setIsInactiveDialogOpen(true);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
isSessionValid();
|
|
85
|
+
const interval = setInterval(
|
|
86
|
+
isSessionValid,
|
|
87
|
+
DEFAULT_SESSION_CHECK_INTERVAL,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
return () => {
|
|
91
|
+
clearInterval(interval);
|
|
92
|
+
didCancel = true;
|
|
93
|
+
};
|
|
94
|
+
}, []);
|
|
95
|
+
|
|
96
|
+
return <>{isInactiveDialogOpen && <InactiveDialog />}</>;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export default Session;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from 'react-dom';
|
|
3
|
+
import SessionDialogUI from '../Session';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Renders the Session Dialog UI content.
|
|
7
|
+
*/
|
|
8
|
+
export default class SessionDialog {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
render(<SessionDialogUI />, options.rootElement);
|
|
11
|
+
}
|
|
12
|
+
}
|