qpp-style 1.0.0-ds.2 → 1.0.0-ds.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.
Files changed (138) hide show
  1. package/.storybook/main.js +46 -32
  2. package/components/Header/HeaderMenuLink.js +6 -0
  3. package/components/SideNav/Content/LevelOneContent.jsx +42 -16
  4. package/components/SideNav/Content/SelectRole/index.js +8 -9
  5. package/components/SideNav/Content/SelectRole/utils.js +24 -13
  6. package/components/SideNav/UI/SideNavUI.jsx +2 -0
  7. package/components/SideNav/UI/default-content.json +19 -1
  8. package/components/SideNav/helpers.js +76 -7
  9. package/coverage/clover.xml +1453 -0
  10. package/coverage/coverage-final.json +74 -0
  11. package/coverage/lcov-report/base.css +224 -0
  12. package/coverage/lcov-report/block-navigation.js +87 -0
  13. package/coverage/lcov-report/favicon.png +0 -0
  14. package/coverage/lcov-report/index.html +491 -0
  15. package/coverage/lcov-report/prettify.css +1 -0
  16. package/coverage/lcov-report/prettify.js +2 -0
  17. package/coverage/lcov-report/react/components/Accordion/index.html +116 -0
  18. package/coverage/lcov-report/react/components/Accordion/index.jsx.html +364 -0
  19. package/coverage/lcov-report/react/components/Button/index.html +116 -0
  20. package/coverage/lcov-report/react/components/Button/index.js.html +355 -0
  21. package/coverage/lcov-report/react/components/Dropdown/index.html +116 -0
  22. package/coverage/lcov-report/react/components/Dropdown/index.js.html +340 -0
  23. package/coverage/lcov-report/react/components/Error/Collapsible.jsx.html +349 -0
  24. package/coverage/lcov-report/react/components/Error/ErrorUI.jsx.html +178 -0
  25. package/coverage/lcov-report/react/components/Error/error.js.html +163 -0
  26. package/coverage/lcov-report/react/components/Error/index.html +146 -0
  27. package/coverage/lcov-report/react/components/Footer/FooterUI.jsx.html +706 -0
  28. package/coverage/lcov-report/react/components/Footer/SocialLinks.jsx.html +265 -0
  29. package/coverage/lcov-report/react/components/Footer/Subscribe.jsx.html +187 -0
  30. package/coverage/lcov-report/react/components/Footer/footer.js.html +145 -0
  31. package/coverage/lcov-report/react/components/Footer/index.html +161 -0
  32. package/coverage/lcov-report/react/components/GovBanner/index.html +116 -0
  33. package/coverage/lcov-report/react/components/GovBanner/index.js.html +436 -0
  34. package/coverage/lcov-report/react/components/Header/HeaderAccountMenu.jsx.html +592 -0
  35. package/coverage/lcov-report/react/components/Header/HeaderCancel.jsx.html +133 -0
  36. package/coverage/lcov-report/react/components/Header/HeaderContainer.jsx.html +280 -0
  37. package/coverage/lcov-report/react/components/Header/HeaderLogo.jsx.html +211 -0
  38. package/coverage/lcov-report/react/components/Header/HeaderMenuButton.js.html +235 -0
  39. package/coverage/lcov-report/react/components/Header/HeaderMenuItem.jsx.html +802 -0
  40. package/coverage/lcov-report/react/components/Header/HeaderMenuLink.js.html +253 -0
  41. package/coverage/lcov-report/react/components/Header/HeaderMenuSignOutButton.js.html +271 -0
  42. package/coverage/lcov-report/react/components/Header/HeaderMobileButton.js.html +196 -0
  43. package/coverage/lcov-report/react/components/Header/HeaderUI.jsx.html +586 -0
  44. package/coverage/lcov-report/react/components/Header/HelpIcon.jsx.html +181 -0
  45. package/coverage/lcov-report/react/components/Header/ImpersonatorBanner.jsx.html +331 -0
  46. package/coverage/lcov-report/react/components/Header/NavigationButtonIcon.jsx.html +166 -0
  47. package/coverage/lcov-report/react/components/Header/header.js.html +205 -0
  48. package/coverage/lcov-report/react/components/Header/hooks.js.html +241 -0
  49. package/coverage/lcov-report/react/components/Header/index.html +341 -0
  50. package/coverage/lcov-report/react/components/Header/utag-helpers.js.html +112 -0
  51. package/coverage/lcov-report/react/components/Infotip/Infotip.jsx.html +310 -0
  52. package/coverage/lcov-report/react/components/Infotip/InfotipIcon.jsx.html +208 -0
  53. package/coverage/lcov-report/react/components/Infotip/index.html +146 -0
  54. package/coverage/lcov-report/react/components/Infotip/index.js.html +94 -0
  55. package/coverage/lcov-report/react/components/Modal/LegacyModal.jsx.html +301 -0
  56. package/coverage/lcov-report/react/components/Modal/Modal.jsx.html +505 -0
  57. package/coverage/lcov-report/react/components/Modal/index.html +146 -0
  58. package/coverage/lcov-report/react/components/Modal/index.jsx.html +151 -0
  59. package/coverage/lcov-report/react/components/NotificationBanner/CollapsedView.js.html +181 -0
  60. package/coverage/lcov-report/react/components/NotificationBanner/ExpandedView.js.html +220 -0
  61. package/coverage/lcov-report/react/components/NotificationBanner/index.html +146 -0
  62. package/coverage/lcov-report/react/components/NotificationBanner/index.js.html +748 -0
  63. package/coverage/lcov-report/react/components/SanitizedContent/index.html +116 -0
  64. package/coverage/lcov-report/react/components/SanitizedContent/index.jsx.html +685 -0
  65. package/coverage/lcov-report/react/components/SessionDialog/index.html +116 -0
  66. package/coverage/lcov-report/react/components/SessionDialog/sessionDialog.js.html +163 -0
  67. package/coverage/lcov-report/react/components/SessionDialogUI.jsx.html +868 -0
  68. package/coverage/lcov-report/react/components/SideNav/AnimationGroup/AnimationGroup.jsx.html +166 -0
  69. package/coverage/lcov-report/react/components/SideNav/AnimationGroup/index.html +116 -0
  70. package/coverage/lcov-report/react/components/SideNav/Chart/ScoreChart.jsx.html +889 -0
  71. package/coverage/lcov-report/react/components/SideNav/Chart/index.html +131 -0
  72. package/coverage/lcov-report/react/components/SideNav/Chart/index.js.html +94 -0
  73. package/coverage/lcov-report/react/components/SideNav/Content/LevelOneContent.jsx.html +682 -0
  74. package/coverage/lcov-report/react/components/SideNav/Content/LevelTwoContent.jsx.html +733 -0
  75. package/coverage/lcov-report/react/components/SideNav/Content/SelectRole/index.html +131 -0
  76. package/coverage/lcov-report/react/components/SideNav/Content/SelectRole/index.js.html +316 -0
  77. package/coverage/lcov-report/react/components/SideNav/Content/SelectRole/utils.js.html +469 -0
  78. package/coverage/lcov-report/react/components/SideNav/Content/index.html +146 -0
  79. package/coverage/lcov-report/react/components/SideNav/Content/index.js.html +97 -0
  80. package/coverage/lcov-report/react/components/SideNav/Details/IndividualDetails.jsx.html +139 -0
  81. package/coverage/lcov-report/react/components/SideNav/Details/PracticeDetails.jsx.html +220 -0
  82. package/coverage/lcov-report/react/components/SideNav/Details/index.html +146 -0
  83. package/coverage/lcov-report/react/components/SideNav/Details/index.js.html +97 -0
  84. package/coverage/lcov-report/react/components/SideNav/Links/CmsSwitchLink.jsx.html +208 -0
  85. package/coverage/lcov-report/react/components/SideNav/Links/NavItemInline.jsx.html +247 -0
  86. package/coverage/lcov-report/react/components/SideNav/Links/NavLinkContainer.jsx.html +199 -0
  87. package/coverage/lcov-report/react/components/SideNav/Links/NavLinkDrawer.jsx.html +913 -0
  88. package/coverage/lcov-report/react/components/SideNav/Links/NavLinkInline.jsx.html +421 -0
  89. package/coverage/lcov-report/react/components/SideNav/Links/NavLinkToggle.jsx.html +187 -0
  90. package/coverage/lcov-report/react/components/SideNav/Links/index.html +206 -0
  91. package/coverage/lcov-report/react/components/SideNav/Links/index.js.html +124 -0
  92. package/coverage/lcov-report/react/components/SideNav/UI/SideNavUI.jsx.html +1105 -0
  93. package/coverage/lcov-report/react/components/SideNav/UI/index.html +131 -0
  94. package/coverage/lcov-report/react/components/SideNav/UI/index.js.html +94 -0
  95. package/coverage/lcov-report/react/components/SideNav/helpers.js.html +1057 -0
  96. package/coverage/lcov-report/react/components/SideNav/index.html +131 -0
  97. package/coverage/lcov-report/react/components/SideNav/index.js.html +244 -0
  98. package/coverage/lcov-report/react/components/Tooltip/Tooltip.jsx.html +349 -0
  99. package/coverage/lcov-report/react/components/Tooltip/index.html +146 -0
  100. package/coverage/lcov-report/react/components/Tooltip/index.js.html +94 -0
  101. package/coverage/lcov-report/react/components/Tooltip/position.js.html +289 -0
  102. package/coverage/lcov-report/react/components/hooks/index.html +116 -0
  103. package/coverage/lcov-report/react/components/hooks/useGetConfig.js.html +310 -0
  104. package/coverage/lcov-report/react/components/index.html +116 -0
  105. package/coverage/lcov-report/react/index.html +116 -0
  106. package/coverage/lcov-report/react/index.js.html +178 -0
  107. package/coverage/lcov-report/react/lib/Chevron.jsx.html +181 -0
  108. package/coverage/lcov-report/react/lib/SvgComponents.jsx.html +1792 -0
  109. package/coverage/lcov-report/react/lib/index.html +146 -0
  110. package/coverage/lcov-report/react/lib/svg-definitions.svg.html +460 -0
  111. package/coverage/lcov-report/react/session/index.html +161 -0
  112. package/coverage/lcov-report/react/session/index.js.html +100 -0
  113. package/coverage/lcov-report/react/session/logout.js.html +307 -0
  114. package/coverage/lcov-report/react/session/refresh.js.html +232 -0
  115. package/coverage/lcov-report/react/session/ttl.js.html +196 -0
  116. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  117. package/coverage/lcov-report/sorter.js +196 -0
  118. package/coverage/lcov.info +3205 -0
  119. package/dist/browser.js +1 -1
  120. package/dist/browser.js.LICENSE.txt +0 -9
  121. package/dist/browser.js.map +1 -1
  122. package/dist/index.js +1 -1
  123. package/dist/index.js.LICENSE.txt +0 -9
  124. package/dist/index.js.map +1 -1
  125. package/dist/react/index.js +1 -1
  126. package/dist/react/index.js.LICENSE.txt +0 -9
  127. package/dist/react/index.js.map +1 -1
  128. package/lib/SvgComponents.jsx +17 -1
  129. package/package.json +21 -21
  130. package/styles/qppds/base/_typography.scss +12 -0
  131. package/styles/qppds/components/_checkbox.scss +199 -0
  132. package/styles/qppds/components/_radio-button.scss +184 -0
  133. package/styles/qppds/components/index.scss +2 -0
  134. package/styles/qppds/settings/variables/_layout.scss +5 -3
  135. package/styles/qppds/utilities/_list-style.scss +18 -0
  136. package/styles/qppds/utilities/index.scss +1 -0
  137. package/webpack.config.js +36 -37
  138. package/webpack.config.react.js +14 -16
@@ -1,4 +1,5 @@
1
1
  const path = require('path');
2
+
2
3
  const CopyWebpackPlugin = require('copy-webpack-plugin');
3
4
 
4
5
  module.exports = {
@@ -19,31 +20,36 @@ module.exports = {
19
20
  ],
20
21
  webpackFinal: async (config) => {
21
22
  // do mutation to the config
22
-
23
23
  config.plugins.push(
24
- new CopyWebpackPlugin([
25
- {
26
- from: path.join(__dirname, '..', '..', 'shared', 'fonts/'),
27
- to: 'fonts/',
28
- },
29
- {
30
- from: path.join(__dirname, '..', '..', 'shared', 'images/'),
31
- to: 'images/',
32
- force: true,
33
- },
34
- ])
24
+ new CopyWebpackPlugin({
25
+ patterns: [
26
+ {
27
+ from: path.join(__dirname, '..', '..', 'shared', 'fonts/'),
28
+ to: 'fonts/',
29
+ },
30
+ {
31
+ from: path.join(__dirname, '..', '..', 'shared', 'images/'),
32
+ to: 'images/',
33
+ force: true,
34
+ },
35
+ ],
36
+ })
35
37
  );
36
-
37
38
  config.module.rules.push({
38
39
  test: /\.scss$/,
39
40
  resolve: {
40
41
  extensions: ['.scss', '.sass'],
41
42
  },
42
43
  use: [
43
- { loader: 'style-loader' },
44
+ {
45
+ loader: 'style-loader',
46
+ },
44
47
  {
45
48
  loader: 'css-loader',
46
- options: { sourceMap: true, importLoaders: 1 },
49
+ options: {
50
+ sourceMap: true,
51
+ importLoaders: 1,
52
+ },
47
53
  },
48
54
  {
49
55
  loader: 'sass-loader',
@@ -53,26 +59,30 @@ module.exports = {
53
59
  },
54
60
  ],
55
61
  });
56
-
57
62
  config.module.rules.push({
58
63
  test: /\.svg$/,
59
- use: [
60
- 'raw-loader',
61
- {
62
- loader: 'svgo-loader',
63
- options: {
64
- plugins: [
65
- { removeTitle: true },
66
- { convertColors: { shorthex: false } },
67
- { convertPathData: false },
68
- ],
69
- },
64
+ type: 'asset/source',
65
+ use: {
66
+ loader: 'svgo-loader',
67
+ options: {
68
+ plugins: [
69
+ {
70
+ removeTitle: true,
71
+ },
72
+ {
73
+ convertColors: {
74
+ shorthex: false,
75
+ },
76
+ },
77
+ {
78
+ convertPathData: false,
79
+ },
80
+ ],
70
81
  },
71
- ],
72
- });
73
-
74
- // Modify default storybook SVG loader so we can use the one expected by qpp-style
82
+ },
83
+ }); // Modify default storybook SVG loader so we can use the one expected by qpp-style
75
84
  // NOTE: When updating storybook dependency, double check this override.
85
+
76
86
  const staticAssetLoader = config.module.rules.find((rule) => {
77
87
  const regExp = rule.test;
78
88
  const isRegExp = regExp && typeof regExp.test === 'function';
@@ -81,9 +91,13 @@ module.exports = {
81
91
 
82
92
  if (staticAssetLoader) {
83
93
  // remove svg matching from storybook's default static asset loader
84
- staticAssetLoader.test = /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/;
94
+ staticAssetLoader.test =
95
+ /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/;
85
96
  }
86
97
 
87
98
  return config;
88
99
  },
100
+ core: {
101
+ builder: 'webpack5',
102
+ },
89
103
  };
@@ -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
  }}
@@ -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 (!hasMultipleRoles) {
48
- if (internalReviewerNames?.some(isReviewerOrSelfNomRole)) {
49
- content =
50
- levelOneContent?.internalReviewers || defaultContent.internalReviewers;
51
- }
44
+ if (isDevPre) {
45
+ content = levelOneContent?.devPre || defaultContent.devPre;
52
46
  } else {
53
- if (selectedRole === 'Reviewer') {
54
- content =
55
- levelOneContent?.internalReviewers || defaultContent.internalReviewers;
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 IconComponent = getIcon(url);
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,9 @@ 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 current selected role in state & the new role selected
32
- updateLocalStorageRoleState(selectedRole, newRoleSelected);
31
+
32
+ // Update localStorage with the new role selected
33
+ updateLocalStorageRoleState(newRoleSelected);
33
34
  setSelectedRole(newRoleSelected);
34
35
  redirectPage(newRoleSelected);
35
36
  };
@@ -37,9 +38,9 @@ const SelectRole = ({ selectedRole, setSelectedRole }) => {
37
38
  // Set role on init render
38
39
  // below is executed on every page refresh including on side nav link navigation & on role selection
39
40
  useEffect(() => {
40
- // Check localstorage & set initial selected role
41
- const { selectedRole, previousSelectedRole } = getLocalStorageRoleState();
42
- const roleValue = selectedRole || ROLE_OPTIONS[0].value;
41
+ // Check localStorage & set initial selected role
42
+ const { selectedUserRole } = getLocalStorageRoleState();
43
+ const roleValue = selectedUserRole || ROLE_OPTIONS[0].value;
43
44
 
44
45
  // Set localStorage values if not set
45
46
  initializeLocalStorageRoleState(roleValue);
@@ -47,10 +48,8 @@ const SelectRole = ({ selectedRole, setSelectedRole }) => {
47
48
  // Update state
48
49
  setSelectedRole(roleValue);
49
50
 
50
- // No previous role set && current role is QPP User in localStorage values indicates
51
- // initial render, where a user has NOT used the dropdown to change the user role.
52
- // If the above condition is not met, redirect to default page of selected role
53
- if (!previousSelectedRole && selectedRole !== 'QPP User') {
51
+ //Redirect to role default page IF localStorage was not set (indicates initial login)
52
+ if (!selectedUserRole) {
54
53
  redirectPage(roleValue);
55
54
  }
56
55
  }, []);
@@ -21,7 +21,10 @@ const hasReviewerRole = (cmsInternalRoles) => {
21
21
  return cmsInternalRoles.some(
22
22
  (name) =>
23
23
  name === 'QPP Self-Nomination' ||
24
- name === 'QPP Targeted Review & Exceptions'
24
+ name === 'QPP Targeted Review & Exceptions' ||
25
+ name === 'QPP Case Management - PIMMS Reviewer' ||
26
+ name === 'QPP Case Management - ACO PAC Reviewer' ||
27
+ name === 'QPP Case Management - CMS Reviewer'
25
28
  );
26
29
  };
27
30
 
@@ -35,6 +38,17 @@ const hasHelpdeskRole = (cmsInternalRoles) => {
35
38
  return cmsInternalRoles.includes('QPP Helpdesk');
36
39
  };
37
40
 
41
+ const hasContentMgmtRole = (cmsInternalRoles) => {
42
+ if (!cmsInternalRoles) return false;
43
+ const cmsRoles = [
44
+ 'QPP Content Management - Author',
45
+ 'QPP Content Management - Approver',
46
+ 'QPP Content Management - Admin',
47
+ 'QPP Front-end - Author',
48
+ ];
49
+ return cmsInternalRoles.some((role) => cmsRoles.includes(role));
50
+ };
51
+
38
52
  /**
39
53
  * Transforms cookie values into optios format for use in role seelction dropdown
40
54
  * @param {array} values extracted & parsed vookie values
@@ -53,6 +67,9 @@ const transformCookieValues = (values) => {
53
67
  if (hasHelpdeskRole(cmsInternalRoles)) {
54
68
  optionValues.push({ name: 'Helpdesk Viewer', value: 'Helpdesk Viewer' });
55
69
  }
70
+ if (hasContentMgmtRole(cmsInternalRoles)) {
71
+ optionValues.push({ name: 'Content Manager', value: 'Content Manager' });
72
+ }
56
73
  return optionValues;
57
74
  };
58
75
 
@@ -70,6 +87,7 @@ const defaultPageByRole = {
70
87
  'QPP User': '/user/submissions',
71
88
  'Helpdesk Viewer': '/user/helpdesk-viewing-tool',
72
89
  Reviewer: '/user/reviewers',
90
+ 'Content Manager': '/user/content-management',
73
91
  };
74
92
 
75
93
  /**
@@ -89,8 +107,7 @@ export const redirectPage = (role) => {
89
107
  * @returns {object}
90
108
  */
91
109
  export const getLocalStorageRoleState = () => ({
92
- selectedRole: localStorage.getItem('selectedRole'),
93
- previousSelectedRole: localStorage.getItem('previousSelectedRole'),
110
+ selectedUserRole: localStorage.getItem('selectedUserRole'),
94
111
  });
95
112
 
96
113
  /**
@@ -101,20 +118,14 @@ export const getLocalStorageRoleState = () => ({
101
118
  export const initializeLocalStorageRoleState = (roleValue) => {
102
119
  const localStorageValues = getLocalStorageRoleState();
103
120
 
104
- if (!localStorageValues.selectedRole) {
105
- localStorage.setItem('selectedRole', roleValue);
106
- }
107
- if (!localStorageValues.previousSelectedRole) {
108
- localStorage.setItem('previousSelectedRole', '');
121
+ if (!localStorageValues.selectedUserRole) {
122
+ localStorage.setItem('selectedUserRole', roleValue);
109
123
  }
110
124
  };
111
125
 
112
126
  /**
113
127
  * Update role values in localStorage
114
- * @param {string} currentRole current/existing user role
115
128
  * @param {string} updatedRole new user role selected from dropdown
116
129
  */
117
- export const updateLocalStorageRoleState = (currentRole, updatedRole) => {
118
- localStorage.setItem('previousSelectedRole', currentRole);
119
- localStorage.setItem('selectedRole', updatedRole);
120
- };
130
+ export const updateLocalStorageRoleState = (updatedRole) =>
131
+ localStorage.setItem('selectedUserRole', updatedRole);
@@ -304,6 +304,7 @@ SideNavUI.propTypes = {
304
304
  devPre: PropTypes.arrayOf(PropTypes.object),
305
305
  internalReviewers: PropTypes.arrayOf(PropTypes.object),
306
306
  viewer: PropTypes.arrayOf(PropTypes.object),
307
+ contentManager: PropTypes.arrayOf(PropTypes.object),
307
308
  }),
308
309
  }),
309
310
  };
@@ -326,6 +327,7 @@ SideNavUI.defaultProps = {
326
327
  devPre: [],
327
328
  internalReviewers: [],
328
329
  viewer: [],
330
+ contentManager: [],
329
331
  },
330
332
  },
331
333
  };
@@ -93,7 +93,25 @@
93
93
  {
94
94
  "url": "/self-nomination",
95
95
  "label": "Self Nomination"
96
+ },
97
+ {
98
+ "url": "/cases/needs-review",
99
+ "label": "Review Skip Requests"
96
100
  }
97
101
  ],
98
- "viewer": []
102
+ "viewer": [],
103
+ "contentManager": [
104
+ {
105
+ "url": "/user/content-management",
106
+ "label": "Dashboard Home"
107
+ },
108
+ {
109
+ "url": "#",
110
+ "label": "Manage Documents"
111
+ },
112
+ {
113
+ "url": "#",
114
+ "label": "Author Content"
115
+ }
116
+ ]
99
117
  }
@@ -13,6 +13,8 @@ import {
13
13
  StarIcon,
14
14
  TargetIcon,
15
15
  IndividualReporting,
16
+ ManageDocumentsIcon,
17
+ AuthorContentIcon,
16
18
  } from '../../lib/SvgComponents';
17
19
 
18
20
  const submissionsUrl = '/user/submissions';
@@ -23,6 +25,7 @@ const physicianCompareUrl = `${submissionsUrl}/doctors-clinicians-preview`;
23
25
  const reportsPortalUrl = `${submissionsUrl}/reports`;
24
26
  const facilityBasedPreviewBaseUrl = `${submissionsUrl}/facility-based-preview`;
25
27
  const viewingToolUrl = '/user/helpdesk-viewing-tool';
28
+ const contentMgrDashboardUrl = '/user/content-management';
26
29
 
27
30
  const performanceFeedbackUrl = (performanceYear) => {
28
31
  if (performanceYear) {
@@ -58,7 +61,7 @@ const handleNavigation = (e, linkCallbackFunction, label) => {
58
61
  * @param {string} url
59
62
  * @returns svg icon
60
63
  */
61
- const getIcon = (url) => {
64
+ const getIcon = (url, linkLabel) => {
62
65
  const icons = {
63
66
  [dashboardUrl]: DashboardIcon,
64
67
  [feedbackUrl]: StarIcon,
@@ -79,17 +82,70 @@ const getIcon = (url) => {
79
82
  '/reviewer/exception': HardshipIcon,
80
83
  '/reviewer/targeted-review': TargetIcon,
81
84
  '/self-nomination': IndividualReporting,
85
+ '/cases/needs-review': FacilityBasedPreviewIcon,
86
+ [contentMgrDashboardUrl]: AccountHomeIcon,
87
+ 'Manage Documents': ManageDocumentsIcon,
88
+ 'Author Content': AuthorContentIcon,
82
89
  };
90
+
91
+ if (linkLabel) return icons[linkLabel];
83
92
  return icons[url];
84
93
  };
85
94
 
95
+ const singleRoleContentMap = {
96
+ 'QPP Content Management - Author': 'contentManager',
97
+ 'QPP Content Management - Approver': 'contentManager',
98
+ 'QPP Content Management - Admin': 'contentManager',
99
+ 'QPP Front-end - Author': 'contentManager',
100
+ 'QPP Self-Nomination': 'internalReviewers',
101
+ 'QPP Targeted Review & Exceptions': 'internalReviewers',
102
+ };
103
+
104
+ const multiRoleContentMap = {
105
+ Reviewer: 'internalReviewers',
106
+ 'Content Manager': 'contentManager',
107
+ };
108
+
109
+ const replaceDefaultContentMgrLinks = (defaultContent) => {
110
+ const host = window.location.host;
111
+ const updatedDefaultContent = {
112
+ ...defaultContent,
113
+ contentManager: [
114
+ defaultContent.contentManager.find(
115
+ (obj) => obj.label === 'Dashboard Home'
116
+ ),
117
+ {
118
+ url: `${host}.qpp.cms.gov/cm/`,
119
+ label: 'Manage Documents',
120
+ },
121
+ {
122
+ url: `${host}.qpp.cms.gov/content-management/`,
123
+ label: 'Author Content',
124
+ },
125
+ ],
126
+ };
127
+ return updatedDefaultContent;
128
+ };
129
+
86
130
  /**
87
- * Check if Reviewer or Self-Nom role
88
- * @param {string} name
89
- * @returns {boolean}
131
+ * Load the side nav content for the given role
132
+ * @param {sting} roleName role of given user from internalReviewerNames
133
+ * @param {object} navContent object of side nav links by role (levelOneContent & defaultContent)
134
+ * @returns {array} returns an array of objects (side nav menu links) from levelOneContent
135
+ * || defaultContent
90
136
  */
91
- const isReviewerOrSelfNomRole = (name) =>
92
- name === 'QPP Self-Nomination' || name === 'QPP Targeted Review & Exceptions';
137
+ const loadSideNavContent = (roleName, navContent, isMultiRoleUser = false) => {
138
+ const { levelOneContent, defaultContent } = navContent;
139
+ const updatedDefaultContent = replaceDefaultContentMgrLinks(defaultContent);
140
+ const roleContentMap = isMultiRoleUser
141
+ ? multiRoleContentMap
142
+ : singleRoleContentMap;
143
+ const contentByRole = roleContentMap[roleName];
144
+ if (levelOneContent) {
145
+ return levelOneContent[contentByRole] || levelOneContent.default;
146
+ }
147
+ return updatedDefaultContent[contentByRole] || updatedDefaultContent.default;
148
+ };
93
149
 
94
150
  /**
95
151
  * Check if user is currently impersonating
@@ -171,6 +227,11 @@ const permissionsByRole = {
171
227
  Impersonation: {
172
228
  internalReviewerNames: ['QPP Helpdesk'],
173
229
  },
230
+ 'Content Manager': {
231
+ hasAuthorizations: false,
232
+ hasApmPaymentss: false,
233
+ hasNonRegistryAuthorizations: false,
234
+ },
174
235
  };
175
236
 
176
237
  /**
@@ -230,6 +291,14 @@ const getUrlConditionMap = (userPermissions) => {
230
291
  'QPP Self-Nomination'
231
292
  ),
232
293
 
294
+ '/cases/needs-review': userPermissions.internalReviewerNames?.some((val) =>
295
+ [
296
+ 'QPP Case Management - PIMMS Reviewer',
297
+ 'QPP Case Management - ACO PAC Reviewer',
298
+ 'QPP Case Management - CMS Reviewer',
299
+ ].includes(val)
300
+ ),
301
+
233
302
  // dev pre
234
303
  '/user/applications': userPermissions.ehrAuthorized,
235
304
  '/user/test-data': userPermissions.ehrAuthorized,
@@ -257,8 +326,8 @@ module.exports = {
257
326
  loadUserPermissions,
258
327
  getUrlConditionMap,
259
328
  isMultiRoleUser,
260
- isReviewerOrSelfNomRole,
261
329
  getIcon,
262
330
  isImpersonating,
263
331
  isImpersonationLink,
332
+ loadSideNavContent,
264
333
  };