qpp-style 9.17.1 → 9.18.0
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/components/Header/HeaderMenuLink.js +6 -0
- package/components/NotificationBanner/CollapsedView.js +32 -0
- package/components/NotificationBanner/ExpandedView.js +45 -0
- package/components/NotificationBanner/NotificationBanner.stories.js +5 -5
- package/components/NotificationBanner/index.js +122 -166
- package/components/SideNav/Content/LevelOneContent.jsx +42 -16
- package/components/SideNav/Content/SelectRole/index.js +7 -9
- package/components/SideNav/Content/SelectRole/utils.js +20 -12
- package/components/SideNav/UI/SideNavUI.jsx +2 -0
- package/components/SideNav/UI/default-content.json +15 -1
- package/components/SideNav/helpers.js +67 -7
- 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/lib/SvgComponents.jsx +17 -1
- package/package.json +1 -1
- package/coverage/clover.xml +0 -1420
- package/coverage/coverage-final.json +0 -73
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -491
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/react/components/Accordion/index.html +0 -116
- package/coverage/lcov-report/react/components/Accordion/index.jsx.html +0 -364
- package/coverage/lcov-report/react/components/Button/index.html +0 -116
- package/coverage/lcov-report/react/components/Button/index.js.html +0 -355
- package/coverage/lcov-report/react/components/Dropdown/index.html +0 -116
- package/coverage/lcov-report/react/components/Dropdown/index.js.html +0 -340
- package/coverage/lcov-report/react/components/Error/Collapsible.jsx.html +0 -349
- package/coverage/lcov-report/react/components/Error/ErrorUI.jsx.html +0 -178
- package/coverage/lcov-report/react/components/Error/error.js.html +0 -163
- package/coverage/lcov-report/react/components/Error/index.html +0 -146
- package/coverage/lcov-report/react/components/Footer/FooterUI.jsx.html +0 -880
- package/coverage/lcov-report/react/components/Footer/LegacyFooterUI.jsx.html +0 -667
- package/coverage/lcov-report/react/components/Footer/SocialLinks.jsx.html +0 -265
- package/coverage/lcov-report/react/components/Footer/Subscribe.jsx.html +0 -187
- package/coverage/lcov-report/react/components/Footer/footer.js.html +0 -175
- package/coverage/lcov-report/react/components/Footer/index.html +0 -176
- package/coverage/lcov-report/react/components/GovBanner/index.html +0 -116
- package/coverage/lcov-report/react/components/GovBanner/index.js.html +0 -436
- package/coverage/lcov-report/react/components/Header/HeaderAccountMenu.jsx.html +0 -592
- package/coverage/lcov-report/react/components/Header/HeaderCancel.jsx.html +0 -133
- package/coverage/lcov-report/react/components/Header/HeaderContainer.jsx.html +0 -280
- package/coverage/lcov-report/react/components/Header/HeaderLogo.jsx.html +0 -211
- package/coverage/lcov-report/react/components/Header/HeaderMenuButton.js.html +0 -235
- package/coverage/lcov-report/react/components/Header/HeaderMenuItem.jsx.html +0 -802
- package/coverage/lcov-report/react/components/Header/HeaderMenuLink.js.html +0 -235
- package/coverage/lcov-report/react/components/Header/HeaderMenuSignOutButton.js.html +0 -271
- package/coverage/lcov-report/react/components/Header/HeaderMobileButton.js.html +0 -196
- package/coverage/lcov-report/react/components/Header/HeaderUI.jsx.html +0 -586
- package/coverage/lcov-report/react/components/Header/HelpIcon.jsx.html +0 -181
- package/coverage/lcov-report/react/components/Header/ImpersonatorBanner.jsx.html +0 -331
- package/coverage/lcov-report/react/components/Header/NavigationButtonIcon.jsx.html +0 -166
- package/coverage/lcov-report/react/components/Header/header.js.html +0 -205
- package/coverage/lcov-report/react/components/Header/hooks.js.html +0 -241
- package/coverage/lcov-report/react/components/Header/index.html +0 -341
- package/coverage/lcov-report/react/components/Header/utag-helpers.js.html +0 -112
- package/coverage/lcov-report/react/components/Infotip/Infotip.jsx.html +0 -310
- package/coverage/lcov-report/react/components/Infotip/InfotipIcon.jsx.html +0 -208
- package/coverage/lcov-report/react/components/Infotip/index.html +0 -146
- package/coverage/lcov-report/react/components/Infotip/index.js.html +0 -94
- package/coverage/lcov-report/react/components/Modal/LegacyModal.jsx.html +0 -301
- package/coverage/lcov-report/react/components/Modal/Modal.jsx.html +0 -505
- package/coverage/lcov-report/react/components/Modal/index.html +0 -146
- package/coverage/lcov-report/react/components/Modal/index.jsx.html +0 -151
- package/coverage/lcov-report/react/components/NotificationBanner/index.html +0 -116
- package/coverage/lcov-report/react/components/NotificationBanner/index.js.html +0 -880
- package/coverage/lcov-report/react/components/SanitizedContent/index.html +0 -116
- package/coverage/lcov-report/react/components/SanitizedContent/index.jsx.html +0 -685
- package/coverage/lcov-report/react/components/SessionDialog/index.html +0 -116
- package/coverage/lcov-report/react/components/SessionDialog/sessionDialog.js.html +0 -163
- package/coverage/lcov-report/react/components/SessionDialogUI.jsx.html +0 -868
- package/coverage/lcov-report/react/components/SideNav/AnimationGroup/AnimationGroup.jsx.html +0 -166
- package/coverage/lcov-report/react/components/SideNav/AnimationGroup/index.html +0 -116
- package/coverage/lcov-report/react/components/SideNav/Chart/ScoreChart.jsx.html +0 -889
- package/coverage/lcov-report/react/components/SideNav/Chart/index.html +0 -131
- package/coverage/lcov-report/react/components/SideNav/Chart/index.js.html +0 -94
- package/coverage/lcov-report/react/components/SideNav/Content/LevelOneContent.jsx.html +0 -604
- package/coverage/lcov-report/react/components/SideNav/Content/LevelTwoContent.jsx.html +0 -733
- package/coverage/lcov-report/react/components/SideNav/Content/SelectRole/index.html +0 -131
- package/coverage/lcov-report/react/components/SideNav/Content/SelectRole/index.js.html +0 -322
- package/coverage/lcov-report/react/components/SideNav/Content/SelectRole/utils.js.html +0 -445
- package/coverage/lcov-report/react/components/SideNav/Content/index.html +0 -146
- package/coverage/lcov-report/react/components/SideNav/Content/index.js.html +0 -97
- package/coverage/lcov-report/react/components/SideNav/Details/IndividualDetails.jsx.html +0 -139
- package/coverage/lcov-report/react/components/SideNav/Details/PracticeDetails.jsx.html +0 -220
- package/coverage/lcov-report/react/components/SideNav/Details/index.html +0 -146
- package/coverage/lcov-report/react/components/SideNav/Details/index.js.html +0 -97
- package/coverage/lcov-report/react/components/SideNav/Links/CmsSwitchLink.jsx.html +0 -208
- package/coverage/lcov-report/react/components/SideNav/Links/NavItemInline.jsx.html +0 -247
- package/coverage/lcov-report/react/components/SideNav/Links/NavLinkContainer.jsx.html +0 -199
- package/coverage/lcov-report/react/components/SideNav/Links/NavLinkDrawer.jsx.html +0 -913
- package/coverage/lcov-report/react/components/SideNav/Links/NavLinkInline.jsx.html +0 -421
- package/coverage/lcov-report/react/components/SideNav/Links/NavLinkToggle.jsx.html +0 -187
- package/coverage/lcov-report/react/components/SideNav/Links/index.html +0 -206
- package/coverage/lcov-report/react/components/SideNav/Links/index.js.html +0 -124
- package/coverage/lcov-report/react/components/SideNav/UI/SideNavUI.jsx.html +0 -1099
- package/coverage/lcov-report/react/components/SideNav/UI/index.html +0 -131
- package/coverage/lcov-report/react/components/SideNav/UI/index.js.html +0 -94
- package/coverage/lcov-report/react/components/SideNav/helpers.js.html +0 -877
- package/coverage/lcov-report/react/components/SideNav/index.html +0 -131
- package/coverage/lcov-report/react/components/SideNav/index.js.html +0 -244
- package/coverage/lcov-report/react/components/Tooltip/Tooltip.jsx.html +0 -349
- package/coverage/lcov-report/react/components/Tooltip/index.html +0 -146
- package/coverage/lcov-report/react/components/Tooltip/index.js.html +0 -94
- package/coverage/lcov-report/react/components/Tooltip/position.js.html +0 -289
- package/coverage/lcov-report/react/components/hooks/index.html +0 -116
- package/coverage/lcov-report/react/components/hooks/useGetConfig.js.html +0 -310
- package/coverage/lcov-report/react/components/index.html +0 -116
- package/coverage/lcov-report/react/index.html +0 -116
- package/coverage/lcov-report/react/index.js.html +0 -178
- package/coverage/lcov-report/react/lib/Chevron.jsx.html +0 -181
- package/coverage/lcov-report/react/lib/SvgComponents.jsx.html +0 -1744
- package/coverage/lcov-report/react/lib/index.html +0 -146
- package/coverage/lcov-report/react/lib/svg-definitions.svg.html +0 -460
- package/coverage/lcov-report/react/session/index.html +0 -161
- package/coverage/lcov-report/react/session/index.js.html +0 -100
- package/coverage/lcov-report/react/session/logout.js.html +0 -307
- package/coverage/lcov-report/react/session/refresh.js.html +0 -232
- package/coverage/lcov-report/react/session/ttl.js.html +0 -196
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -196
- package/coverage/lcov.info +0 -3168
|
@@ -33,6 +33,12 @@ const HeaderMenuLink = ({ href, name }) => {
|
|
|
33
33
|
data-track-category="TopNav"
|
|
34
34
|
data-track-action="click"
|
|
35
35
|
data-track-label={name}
|
|
36
|
+
onKeyDown={(e) => {
|
|
37
|
+
if (e.key === ' ' || e.code === 'Space') {
|
|
38
|
+
window.location.href = window.location.origin + href;
|
|
39
|
+
setUtagLink('main navbar', 'keydown', href);
|
|
40
|
+
}
|
|
41
|
+
}}
|
|
36
42
|
onClick={() => {
|
|
37
43
|
setUtagLink('main navbar', 'click', href);
|
|
38
44
|
}}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { BellOutline } from '../../lib/SvgComponents.jsx';
|
|
4
|
+
|
|
5
|
+
const CollapsedView = (
|
|
6
|
+
{ expandNotification, label },
|
|
7
|
+
{ collapsedWrapperRef, collapsedBannerRef }
|
|
8
|
+
) => {
|
|
9
|
+
return (
|
|
10
|
+
<div
|
|
11
|
+
ref={collapsedWrapperRef}
|
|
12
|
+
className={`notification-banner-wrapper collapsed-view`}
|
|
13
|
+
onClick={expandNotification}
|
|
14
|
+
>
|
|
15
|
+
<button ref={collapsedBannerRef} className={`notification-banner-label`}>
|
|
16
|
+
{label}
|
|
17
|
+
<span className="bell-icon">
|
|
18
|
+
<svg aria-hidden="true" focusable="false">
|
|
19
|
+
<BellOutline />
|
|
20
|
+
</svg>
|
|
21
|
+
</span>
|
|
22
|
+
</button>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
CollapsedView.propTypes = {
|
|
28
|
+
expandNotification: PropTypes.func,
|
|
29
|
+
label: PropTypes.string,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default forwardRef(CollapsedView);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import SanitizedContent from '../SanitizedContent';
|
|
4
|
+
import { CloseXIcon } from '../../lib/SvgComponents.jsx';
|
|
5
|
+
|
|
6
|
+
const ExpandedView = ({
|
|
7
|
+
label,
|
|
8
|
+
expanded,
|
|
9
|
+
content,
|
|
10
|
+
dismissable,
|
|
11
|
+
collapseNotification,
|
|
12
|
+
}) => {
|
|
13
|
+
return (
|
|
14
|
+
<div className={`notification-banner-wrapper expanded-view`}>
|
|
15
|
+
<div className="notification-banner-label">{label}</div>
|
|
16
|
+
<div className="notification-banner-content">
|
|
17
|
+
<SanitizedContent
|
|
18
|
+
html={expanded ? content : '<p>No notifications to display</p>'}
|
|
19
|
+
/>
|
|
20
|
+
</div>
|
|
21
|
+
{expanded && dismissable && (
|
|
22
|
+
<button
|
|
23
|
+
onClick={collapseNotification}
|
|
24
|
+
type="button"
|
|
25
|
+
className="notification-banner-close"
|
|
26
|
+
>
|
|
27
|
+
<svg className="close-icon" aria-hidden="true" focusable="false">
|
|
28
|
+
<CloseXIcon />
|
|
29
|
+
</svg>
|
|
30
|
+
<span className="sr-only">Close</span>
|
|
31
|
+
</button>
|
|
32
|
+
)}
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
ExpandedView.propTypes = {
|
|
38
|
+
label: PropTypes.string,
|
|
39
|
+
expanded: PropTypes.bool,
|
|
40
|
+
content: PropTypes.string,
|
|
41
|
+
dismissable: PropTypes.bool,
|
|
42
|
+
collapseNotification: PropTypes.func,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default ExpandedView;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import NotificationBanner from './index';
|
|
3
|
-
import { withKnobs
|
|
3
|
+
import { withKnobs } from '@storybook/addon-knobs';
|
|
4
4
|
|
|
5
5
|
export default {
|
|
6
6
|
title: 'NotificationBanner',
|
|
@@ -11,11 +11,11 @@ export default {
|
|
|
11
11
|
export const ExampleNotificationBanner = () => (
|
|
12
12
|
<NotificationBanner
|
|
13
13
|
result={{
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
display: true,
|
|
15
|
+
dismissable: true,
|
|
16
|
+
content: 'test',
|
|
17
|
+
label: 'Update',
|
|
17
18
|
color: 'blue',
|
|
18
|
-
dismissable: boolean('dismissable', false),
|
|
19
19
|
}}
|
|
20
20
|
/>
|
|
21
21
|
);
|
|
@@ -1,80 +1,87 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useState, useEffect, useRef } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
import { CloseXIcon, BellOutline } from '../../lib/SvgComponents.jsx';
|
|
3
|
+
import ExpandedView from './ExpandedView';
|
|
4
|
+
import CollapsedView from './CollapsedView';
|
|
6
5
|
import { withGetConfig } from '../hooks/useGetConfig';
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
this._collapseNotification = this.collapseNotification.bind(this);
|
|
19
|
-
this._expandNotification = this.expandNotification.bind(this);
|
|
20
|
-
this._setBannerHeight = this.setBannerHeight.bind(this);
|
|
21
|
-
}
|
|
7
|
+
function debounce(fn, ms) {
|
|
8
|
+
let timer;
|
|
9
|
+
return () => {
|
|
10
|
+
clearTimeout(timer);
|
|
11
|
+
timer = setTimeout(() => {
|
|
12
|
+
timer = null;
|
|
13
|
+
fn.apply(this, arguments);
|
|
14
|
+
}, ms);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
22
17
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
const NotificationBanner = ({ result }) => {
|
|
19
|
+
const {
|
|
20
|
+
color = 'blue',
|
|
21
|
+
content,
|
|
22
|
+
dismissable,
|
|
23
|
+
enabled,
|
|
24
|
+
label = 'Update',
|
|
25
|
+
} = result.content;
|
|
26
|
+
|
|
27
|
+
const bannerContainerRef = useRef(null);
|
|
28
|
+
const collapsedWrapperRef = useRef(null);
|
|
29
|
+
const collapsedBannerRef = useRef(null);
|
|
30
|
+
const VIEW_BREAKPOINT = 767;
|
|
31
|
+
const [height, setHeight] = useState('100%');
|
|
32
|
+
const [expanded, setExpanded] = useState();
|
|
33
|
+
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
|
|
34
|
+
const cssDeterminesBannerView = expanded ? 'expanded' : 'collapsed';
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
//setBannerHeight on Load & Resize
|
|
38
|
+
setBannerHeight();
|
|
39
|
+
|
|
40
|
+
if (window.innerWidth <= VIEW_BREAKPOINT) {
|
|
41
|
+
setExpanded(false);
|
|
28
42
|
}
|
|
29
43
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
44
|
+
const debounceBrowserResizeHandler = debounce(() => {
|
|
45
|
+
return setWindowWidth(window.innerWidth);
|
|
46
|
+
}, 600);
|
|
33
47
|
|
|
34
|
-
|
|
35
|
-
componentDidUpdate(prevProps) {
|
|
36
|
-
if (prevProps.result !== this.props?.result) {
|
|
37
|
-
const { result: notifications } = this.props;
|
|
38
|
-
if (Object.keys(notifications).length > 0) {
|
|
39
|
-
this.setState({
|
|
40
|
-
expanded: this.isNotificationExpanded(notifications.content),
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
48
|
+
window.addEventListener('resize', debounceBrowserResizeHandler);
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
},
|
|
51
|
-
} = this.props;
|
|
52
|
-
if (content) {
|
|
53
|
-
this.bannerContainer.style.transition = 'none';
|
|
54
|
-
|
|
55
|
-
this.state.expanded
|
|
56
|
-
? this.collapsedBanner.setAttribute('tabIndex', '-1')
|
|
57
|
-
: this.collapsedBanner.setAttribute('tabIndex', ' ');
|
|
50
|
+
return () => {
|
|
51
|
+
window.removeEventListener('resize', debounceBrowserResizeHandler);
|
|
52
|
+
};
|
|
53
|
+
}, [windowWidth]);
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
});
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
// setExpanded => updates cssDeterminesBannerView
|
|
57
|
+
if (Object.keys(result).length > 0) {
|
|
58
|
+
setExpanded(isNotificationExpanded());
|
|
64
59
|
}
|
|
65
|
-
}
|
|
60
|
+
}, [result]);
|
|
66
61
|
|
|
67
|
-
isNotificationExpanded(
|
|
68
|
-
const dateDismissed = new Date(
|
|
69
|
-
const dateUpdated = new Date(
|
|
62
|
+
const isNotificationExpanded = () => {
|
|
63
|
+
const dateDismissed = new Date(result.content.dateDismissed);
|
|
64
|
+
const dateUpdated = new Date(result.content.dateUpdated);
|
|
70
65
|
const notDismissed =
|
|
71
|
-
(
|
|
72
|
-
|
|
66
|
+
(isDateValid(dateUpdated) &&
|
|
67
|
+
isDateValid(dateDismissed) &&
|
|
73
68
|
dateUpdated >= dateDismissed) ||
|
|
74
|
-
!
|
|
75
|
-
|
|
69
|
+
!isDateValid(dateDismissed);
|
|
76
70
|
return notDismissed;
|
|
77
|
-
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const setBannerHeight = () => {
|
|
74
|
+
if (content) {
|
|
75
|
+
bannerContainerRef.current.style.transition = 'none';
|
|
76
|
+
expanded
|
|
77
|
+
? collapsedBannerRef.current.setAttribute('tabIndex', '-1')
|
|
78
|
+
: collapsedBannerRef.current.setAttribute('tabIndex', ' ');
|
|
79
|
+
|
|
80
|
+
setHeight(
|
|
81
|
+
expanded ? '100%' : `${collapsedWrapperRef.current.offsetHeight}px`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
78
85
|
|
|
79
86
|
/**
|
|
80
87
|
* Whether the date is valid, i.e. not null
|
|
@@ -82,17 +89,17 @@ class NotificationBanner extends Component {
|
|
|
82
89
|
* @param {Date} date
|
|
83
90
|
* @return {Boolean}
|
|
84
91
|
*/
|
|
85
|
-
isDateValid(date) {
|
|
86
|
-
return !isNaN(Date.parse(date));
|
|
87
|
-
}
|
|
88
92
|
|
|
93
|
+
const isDateValid = (date) => {
|
|
94
|
+
return !isNaN(Date.parse(date));
|
|
95
|
+
};
|
|
89
96
|
/**
|
|
90
97
|
* Try to find this NotificationBanner instance in localStorage, or else add
|
|
91
98
|
* a minimal version of it, and mark it with a dateDismissed, then update
|
|
92
99
|
* localStorage.
|
|
93
100
|
*/
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
|
|
102
|
+
const markNotificationClosed = () => {
|
|
96
103
|
const dateDismissed = new Date().toISOString();
|
|
97
104
|
const storageNotification = result || {};
|
|
98
105
|
|
|
@@ -119,128 +126,76 @@ class NotificationBanner extends Component {
|
|
|
119
126
|
})
|
|
120
127
|
);
|
|
121
128
|
}
|
|
122
|
-
}
|
|
129
|
+
};
|
|
123
130
|
|
|
124
131
|
/**
|
|
125
132
|
* Callback when the user dimisses a notification. Mark it as dismissed in
|
|
126
133
|
* localStorage, empty the contents, and dispatch a custom event to notify
|
|
127
134
|
* any observers that it has been dismissed.
|
|
128
135
|
*/
|
|
129
|
-
|
|
136
|
+
|
|
137
|
+
const collapseNotification = (e) => {
|
|
130
138
|
e.stopPropagation();
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
this.setState({
|
|
135
|
-
expanded: false,
|
|
136
|
-
height: this.collapsedWrapper.offsetHeight + 'px',
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
+
markNotificationClosed();
|
|
140
|
+
collapsedBannerRef.current.setAttribute('tabIndex', ' ');
|
|
141
|
+
bannerContainerRef.current.style.transition = 'height .2s ease-out';
|
|
139
142
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
this.bannerContainer.style.transition = 'height .2s ease-out';
|
|
144
|
-
this.setState({
|
|
145
|
-
expanded: true,
|
|
146
|
-
height: '100%',
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
}
|
|
143
|
+
setExpanded(false);
|
|
144
|
+
setHeight(`${collapsedWrapperRef.current.offsetHeight}px`);
|
|
145
|
+
};
|
|
150
146
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const {
|
|
158
|
-
result: {
|
|
159
|
-
content: { dismissable },
|
|
160
|
-
},
|
|
161
|
-
} = this.props;
|
|
162
|
-
if (dismissable) {
|
|
163
|
-
return (
|
|
164
|
-
<button
|
|
165
|
-
onClick={this._collapseNotification}
|
|
166
|
-
type="button"
|
|
167
|
-
className="notification-banner-close"
|
|
168
|
-
>
|
|
169
|
-
<svg className="close-icon" aria-hidden="true" focusable="false">
|
|
170
|
-
<CloseXIcon />
|
|
171
|
-
</svg>
|
|
172
|
-
<span className="sr-only">Close</span>
|
|
173
|
-
</button>
|
|
174
|
-
);
|
|
175
|
-
} else {
|
|
176
|
-
return '';
|
|
177
|
-
}
|
|
178
|
-
}
|
|
147
|
+
const expandNotification = () => {
|
|
148
|
+
collapsedBannerRef.current.setAttribute('tabIndex', '-1');
|
|
149
|
+
bannerContainerRef.current.style.transition = 'height .2s ease-out';
|
|
150
|
+
setExpanded(true);
|
|
151
|
+
setHeight('100%');
|
|
152
|
+
};
|
|
179
153
|
|
|
180
154
|
/**
|
|
181
155
|
* Render the notification if it has any contents.
|
|
182
156
|
*
|
|
183
157
|
* @return {String} HTML content
|
|
184
158
|
*/
|
|
185
|
-
render() {
|
|
186
|
-
const { expanded, height } = this.state;
|
|
187
|
-
const { result: { content: { enabled, content } = {} } = {} } = this.props;
|
|
188
|
-
if (!content || !enabled) {
|
|
189
|
-
return <div id="notification-banner" />;
|
|
190
|
-
} else {
|
|
191
|
-
const notificationStatus = expanded ? 'expanded' : 'collapsed';
|
|
192
|
-
const { color = 'blue', label = 'Update' } = content;
|
|
193
|
-
const className = `notification-banner notification-banner-${color} ${notificationStatus}`;
|
|
194
159
|
|
|
195
|
-
|
|
160
|
+
return (
|
|
161
|
+
<>
|
|
162
|
+
{!content || !enabled ? (
|
|
163
|
+
<div id="notification-banner" />
|
|
164
|
+
) : (
|
|
196
165
|
<div
|
|
166
|
+
ref={bannerContainerRef}
|
|
197
167
|
style={{ height }}
|
|
198
|
-
|
|
199
|
-
className={className}
|
|
168
|
+
className={`notification-banner notification-banner-${color} ${cssDeterminesBannerView}`}
|
|
200
169
|
>
|
|
201
|
-
<
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
{
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
<div
|
|
215
|
-
ref={(elem) => (this.collapsedWrapper = elem)}
|
|
216
|
-
className={`notification-banner-wrapper collapsed-view`}
|
|
217
|
-
onClick={this._expandNotification}
|
|
218
|
-
>
|
|
219
|
-
<button
|
|
220
|
-
ref={(elem) => (this.collapsedBanner = elem)}
|
|
221
|
-
className={`notification-banner-label`}
|
|
222
|
-
>
|
|
223
|
-
{label}
|
|
224
|
-
<span className="bell-icon">
|
|
225
|
-
<svg aria-hidden="true" focusable="false">
|
|
226
|
-
<BellOutline />
|
|
227
|
-
</svg>
|
|
228
|
-
</span>
|
|
229
|
-
</button>
|
|
230
|
-
</div>
|
|
170
|
+
<ExpandedView
|
|
171
|
+
label={label}
|
|
172
|
+
expanded={expanded}
|
|
173
|
+
content={content}
|
|
174
|
+
dismissable={dismissable}
|
|
175
|
+
collapseNotification={collapseNotification}
|
|
176
|
+
/>
|
|
177
|
+
|
|
178
|
+
<CollapsedView
|
|
179
|
+
expandNotification={expandNotification}
|
|
180
|
+
label={label}
|
|
181
|
+
ref={{ collapsedWrapperRef, collapsedBannerRef }}
|
|
182
|
+
/>
|
|
231
183
|
</div>
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
184
|
+
)}
|
|
185
|
+
</>
|
|
186
|
+
);
|
|
187
|
+
};
|
|
236
188
|
|
|
237
189
|
NotificationBanner.propTypes = {
|
|
238
190
|
result: PropTypes.shape({
|
|
239
191
|
content: PropTypes.shape({
|
|
240
|
-
content: PropTypes.string,
|
|
241
|
-
label: PropTypes.string,
|
|
242
192
|
color: PropTypes.string,
|
|
193
|
+
content: PropTypes.string,
|
|
194
|
+
dateDismissed: PropTypes.string,
|
|
195
|
+
dateUpdated: PropTypes.string,
|
|
243
196
|
dismissable: PropTypes.bool,
|
|
197
|
+
enabled: PropTypes.bool,
|
|
198
|
+
label: PropTypes.string,
|
|
244
199
|
}),
|
|
245
200
|
}),
|
|
246
201
|
};
|
|
@@ -248,10 +203,11 @@ NotificationBanner.propTypes = {
|
|
|
248
203
|
NotificationBanner.defaultProps = {
|
|
249
204
|
result: {
|
|
250
205
|
content: {
|
|
251
|
-
content: null,
|
|
252
|
-
label: 'Update',
|
|
253
206
|
color: 'blue',
|
|
207
|
+
content: null,
|
|
254
208
|
dismissable: true,
|
|
209
|
+
enabled: true,
|
|
210
|
+
label: 'Update',
|
|
255
211
|
},
|
|
256
212
|
},
|
|
257
213
|
};
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
loadUserPermissions,
|
|
11
11
|
getUrlConditionMap,
|
|
12
12
|
isMultiRoleUser,
|
|
13
|
-
isReviewerOrSelfNomRole,
|
|
14
13
|
getIcon,
|
|
15
14
|
isImpersonating,
|
|
16
15
|
isImpersonationLink,
|
|
16
|
+
loadSideNavContent,
|
|
17
17
|
} from '../helpers';
|
|
18
18
|
import SelectRole from './SelectRole';
|
|
19
19
|
|
|
@@ -32,27 +32,31 @@ const LevelOneContent = ({
|
|
|
32
32
|
name = `${firstName} ${lastName}`;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
const linkClass = isExpanded ? 'link-inline' : 'link-collapsed';
|
|
36
|
+
|
|
35
37
|
const permissions = loadUserPermissions(document.cookie, selectedRole);
|
|
36
38
|
const { internalReviewerNames } = permissions;
|
|
37
39
|
|
|
38
40
|
const hasMultipleRoles = isMultiRoleUser(document.cookie);
|
|
39
|
-
|
|
40
|
-
const linkClass = isExpanded ? 'link-inline' : 'link-collapsed';
|
|
41
|
-
|
|
42
41
|
const isDevPre = qpp_is_dev_pre === 'true';
|
|
43
|
-
|
|
44
42
|
let content;
|
|
45
|
-
content = isDevPre ? levelOneContent?.devPre : levelOneContent?.default;
|
|
46
43
|
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
content =
|
|
50
|
-
levelOneContent?.internalReviewers || defaultContent.internalReviewers;
|
|
51
|
-
}
|
|
44
|
+
if (isDevPre) {
|
|
45
|
+
content = levelOneContent?.devPre || defaultContent.devPre;
|
|
52
46
|
} else {
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
47
|
+
if (!hasMultipleRoles) {
|
|
48
|
+
// internalReviewerNames has 1 value b/c !hasMultipleRoles
|
|
49
|
+
const reviewerRoleName = internalReviewerNames[0];
|
|
50
|
+
content = loadSideNavContent(reviewerRoleName, {
|
|
51
|
+
levelOneContent,
|
|
52
|
+
defaultContent,
|
|
53
|
+
});
|
|
54
|
+
} else {
|
|
55
|
+
content = loadSideNavContent(
|
|
56
|
+
selectedRole,
|
|
57
|
+
{ levelOneContent, defaultContent },
|
|
58
|
+
true
|
|
59
|
+
);
|
|
56
60
|
}
|
|
57
61
|
}
|
|
58
62
|
|
|
@@ -60,8 +64,8 @@ const LevelOneContent = ({
|
|
|
60
64
|
const urlConditionMap = getUrlConditionMap(permissions);
|
|
61
65
|
|
|
62
66
|
const navLinks = content
|
|
63
|
-
// Filter out Exception & Targeted Review links for Helpdesk Viewer when not impersonating
|
|
64
67
|
.filter((link) => {
|
|
68
|
+
// Filter out Exception & Targeted Review links for Helpdesk Viewer when not impersonating
|
|
65
69
|
const isHelpdeskRoleNotImpersonating =
|
|
66
70
|
selectedRole === 'Helpdesk Viewer' && !isImpersonating(document.cookie);
|
|
67
71
|
if (isHelpdeskRoleNotImpersonating) {
|
|
@@ -70,6 +74,23 @@ const LevelOneContent = ({
|
|
|
70
74
|
link.url !== '/user/targeted-review/#/landing'
|
|
71
75
|
);
|
|
72
76
|
}
|
|
77
|
+
|
|
78
|
+
// Filter Content Manager links
|
|
79
|
+
// Check if user has content mgmt. admin || frontend author roles
|
|
80
|
+
const contentMgrCanManageDocs = internalReviewerNames.some((name) =>
|
|
81
|
+
name.includes('QPP Content Management')
|
|
82
|
+
);
|
|
83
|
+
const contentMgrFrontendAuthor = internalReviewerNames.includes(
|
|
84
|
+
'QPP Front-end - Author'
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
if (!contentMgrCanManageDocs) {
|
|
88
|
+
return link.label !== 'Manage Documents';
|
|
89
|
+
}
|
|
90
|
+
if (!contentMgrFrontendAuthor) {
|
|
91
|
+
return link.label !== 'Author Content';
|
|
92
|
+
}
|
|
93
|
+
|
|
73
94
|
return link;
|
|
74
95
|
})
|
|
75
96
|
.reduce((acc, link) => {
|
|
@@ -80,7 +101,11 @@ const LevelOneContent = ({
|
|
|
80
101
|
return acc;
|
|
81
102
|
}
|
|
82
103
|
|
|
83
|
-
const
|
|
104
|
+
const isContentMgrLink =
|
|
105
|
+
label === 'Manage Documents' || label === 'Author Content';
|
|
106
|
+
const IconComponent = isContentMgrLink
|
|
107
|
+
? getIcon(null, label)
|
|
108
|
+
: getIcon(url);
|
|
84
109
|
const Icon = IconComponent ? <IconComponent /> : null;
|
|
85
110
|
const sharedProps = {
|
|
86
111
|
url,
|
|
@@ -167,6 +192,7 @@ LevelOneContent.propTypes = {
|
|
|
167
192
|
devPre: PropTypes.arrayOf(PropTypes.object),
|
|
168
193
|
viewer: PropTypes.arrayOf(PropTypes.object),
|
|
169
194
|
internalReviewers: PropTypes.arrayOf(PropTypes.object),
|
|
195
|
+
contentManager: PropTypes.arrayOf(PropTypes.object),
|
|
170
196
|
}),
|
|
171
197
|
};
|
|
172
198
|
|
|
@@ -28,8 +28,8 @@ const SelectRole = ({ selectedRole, setSelectedRole }) => {
|
|
|
28
28
|
const newRoleSelected = ROLE_OPTIONS.filter(
|
|
29
29
|
(opt) => opt.value === dropdownValue
|
|
30
30
|
)[0].value;
|
|
31
|
-
// Update localStorage with the
|
|
32
|
-
updateLocalStorageRoleState(
|
|
31
|
+
// Update localStorage with the new role selected
|
|
32
|
+
updateLocalStorageRoleState(newRoleSelected);
|
|
33
33
|
setSelectedRole(newRoleSelected);
|
|
34
34
|
redirectPage(newRoleSelected);
|
|
35
35
|
};
|
|
@@ -37,9 +37,9 @@ const SelectRole = ({ selectedRole, setSelectedRole }) => {
|
|
|
37
37
|
// Set role on init render
|
|
38
38
|
// below is executed on every page refresh including on side nav link navigation & on role selection
|
|
39
39
|
useEffect(() => {
|
|
40
|
-
// Check
|
|
41
|
-
const {
|
|
42
|
-
const roleValue =
|
|
40
|
+
// Check localStorage & set initial selected role
|
|
41
|
+
const { selectedUserRole } = getLocalStorageRoleState();
|
|
42
|
+
const roleValue = selectedUserRole || ROLE_OPTIONS[0].value;
|
|
43
43
|
|
|
44
44
|
// Set localStorage values if not set
|
|
45
45
|
initializeLocalStorageRoleState(roleValue);
|
|
@@ -47,10 +47,8 @@ const SelectRole = ({ selectedRole, setSelectedRole }) => {
|
|
|
47
47
|
// Update state
|
|
48
48
|
setSelectedRole(roleValue);
|
|
49
49
|
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
// If the above condition is not met, redirect to default page of selected role
|
|
53
|
-
if (!previousSelectedRole && selectedRole !== 'QPP User') {
|
|
50
|
+
//Redirect to role default page IF localStorage was not set (indicates initial login)
|
|
51
|
+
if (!selectedUserRole) {
|
|
54
52
|
redirectPage(roleValue);
|
|
55
53
|
}
|
|
56
54
|
}, []);
|