Skip to content

Commit 1e9af3c

Browse files
feat: remove username from header (#551)
Remove username from header and add name for screen reader VAN-1804
1 parent 011b25d commit 1e9af3c

11 files changed

Lines changed: 80 additions & 13 deletions

example/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ subscribe(APP_READY, () => {
2626
authenticatedUser: {
2727
userId: '123abc',
2828
username: 'testuser',
29+
name: 'test user',
2930
roles: [],
3031
administrator: false,
3132
},
@@ -37,6 +38,7 @@ subscribe(APP_READY, () => {
3738
<AppContext.Provider value={{
3839
authenticatedUser: {
3940
userId: '123abc',
41+
name: 'test name',
4042
username: 'testuser',
4143
roles: [],
4244
administrator: false,

src/DesktopHeader.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,11 @@ class DesktopHeader extends React.Component {
5959
userMenu,
6060
avatar,
6161
username,
62+
name,
6263
intl,
6364
} = this.props;
65+
const hideUsername = getConfig().HIDE_USERNAME_FROM_HEADER;
66+
const usernameOrName = hideUsername ? name : username;
6467

6568
return (
6669
<Dropdown>
@@ -69,10 +72,10 @@ class DesktopHeader extends React.Component {
6972
as={AvatarButton}
7073
src={avatar}
7174
alt=""
72-
aria-label={intl.formatMessage(messages['header.label.account.menu.for'], { username })}
75+
aria-label={intl.formatMessage(messages['header.label.account.menu.for'], { username: usernameOrName })}
7376
data-hj-suppress
7477
>
75-
{username}
78+
{!hideUsername && username}
7679
</Dropdown.Toggle>
7780

7881
<Dropdown.Menu alignRight>
@@ -156,6 +159,7 @@ DesktopHeader.propTypes = {
156159
logoDestination: PropTypes.string,
157160
avatar: PropTypes.string,
158161
username: PropTypes.string,
162+
name: PropTypes.string,
159163
loggedIn: PropTypes.bool,
160164

161165
// i18n
@@ -171,6 +175,7 @@ DesktopHeader.defaultProps = {
171175
logoDestination: null,
172176
avatar: null,
173177
username: null,
178+
name: '',
174179
loggedIn: false,
175180
};
176181

src/Header.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ subscribe(APP_CONFIG_INITIALIZED, () => {
3232
MINIMAL_HEADER: !!process.env.MINIMAL_HEADER,
3333
ENTERPRISE_LEARNER_PORTAL_HOSTNAME: process.env.ENTERPRISE_LEARNER_PORTAL_HOSTNAME,
3434
AUTHN_MINIMAL_HEADER: !!process.env.AUTHN_MINIMAL_HEADER,
35+
// this flag is introduced to unblock for new release.
36+
// the flag would be removed in follow up PR
37+
HIDE_USERNAME_FROM_HEADER: !!process.env.HIDE_USERNAME_FROM_HEADER,
3538
}, 'Header additional config');
3639
});
3740

@@ -155,6 +158,7 @@ const Header = ({ intl }) => {
155158
logoDestination: getConfig().MINIMAL_HEADER ? null : `${config.LMS_BASE_URL}/dashboard`,
156159
loggedIn: authenticatedUser !== null,
157160
username: authenticatedUser !== null ? authenticatedUser.username : null,
161+
name: authenticatedUser !== null ? authenticatedUser.name : null,
158162
avatar: authenticatedUser !== null ? authenticatedUser.avatar : null,
159163
mainMenu: getConfig().MINIMAL_HEADER || getConfig().AUTHN_MINIMAL_HEADER ? [] : mainMenu,
160164
userMenu: getConfig().AUTHN_MINIMAL_HEADER ? [] : userMenu,

src/Header.test.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ describe('<Header />', () => {
7474
authenticatedUser: {
7575
userId: 'abc123',
7676
username: 'edX',
77+
name: 'edX',
7778
roles: [],
7879
administrator: false,
7980
},

src/learning-header/AuthenticatedUserDropdown.jsx

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@ import { faUserCircle } from '@fortawesome/free-solid-svg-icons';
77

88
import { getConfig } from '@edx/frontend-platform';
99
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
10-
import { Dropdown, Badge } from '@openedx/paragon';
10+
import { Avatar, Dropdown, Badge } from '@openedx/paragon';
1111

1212
import messages from './messages';
1313
import Notifications from '../Notifications';
1414
import { selectShowNotificationTray } from '../Notifications/data/selectors';
1515
import { fetchAppsNotificationCount } from '../Notifications/data/thunks';
1616

17-
const AuthenticatedUserDropdown = ({ enterpriseLearnerPortalLink, intl, username }) => {
17+
const AuthenticatedUserDropdown = (props) => {
18+
const {
19+
intl,
20+
enterpriseLearnerPortalLink,
21+
username,
22+
name,
23+
} = props;
1824
const dispatch = useDispatch();
1925
const showNotificationsTray = useSelector(selectShowNotificationTray);
2026

@@ -47,17 +53,25 @@ const AuthenticatedUserDropdown = ({ enterpriseLearnerPortalLink, intl, username
4753
careersMenuItem = '';
4854
}
4955

56+
const dropdownToggle = (
57+
<Dropdown.Toggle variant="outline-primary" id="user-dropdown">
58+
<FontAwesomeIcon icon={faUserCircle} className="d-md-none" size="lg" />
59+
{getConfig().HIDE_USERNAME_FROM_HEADER ? (
60+
<Avatar size="sm" alt={name} className="mr-2" />
61+
) : (
62+
<span data-hj-suppress className="d-none d-md-inline" data-testid="username">
63+
{username}
64+
</span>
65+
)}
66+
</Dropdown.Toggle>
67+
);
68+
5069
return (
5170
<>
5271
<a className="text-gray-700" href={`${getConfig().SUPPORT_URL}`}>{intl.formatMessage(messages.help)}</a>
5372
{showNotificationsTray && <Notifications />}
5473
<Dropdown className="user-dropdown ml-3">
55-
<Dropdown.Toggle variant="outline-primary" id="user-dropdown">
56-
<FontAwesomeIcon icon={faUserCircle} className="d-md-none" size="lg" />
57-
<span data-hj-suppress className="d-none d-md-inline">
58-
{username}
59-
</span>
60-
</Dropdown.Toggle>
74+
{dropdownToggle}
6175
<Dropdown.Menu className="dropdown-menu-right zIndex-2">
6276
{dashboardMenuItem}
6377
{careersMenuItem}
@@ -89,10 +103,12 @@ AuthenticatedUserDropdown.propTypes = {
89103
enterpriseLearnerPortalLink: PropTypes.string,
90104
intl: intlShape.isRequired,
91105
username: PropTypes.string.isRequired,
106+
name: PropTypes.string,
92107
};
93108

94109
AuthenticatedUserDropdown.defaultProps = {
95110
enterpriseLearnerPortalLink: '',
111+
name: '',
96112
};
97113

98114
export default injectIntl(AuthenticatedUserDropdown);

src/learning-header/LearningHeader.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ subscribe(APP_CONFIG_INITIALIZED, () => {
2323
mergeConfig({
2424
ACCOUNT_SETTINGS_URL: process.env.ACCOUNT_SETTINGS_URL || '',
2525
NOTIFICATION_FEEDBACK_URL: process.env.NOTIFICATION_FEEDBACK_URL || '',
26+
HIDE_USERNAME_FROM_HEADER: !!process.env.HIDE_USERNAME_FROM_HEADER,
2627
}, 'Learning Header additional config');
2728
});
2829

@@ -92,6 +93,7 @@ const LearningHeader = ({
9293
<AuthenticatedUserDropdown
9394
enterpriseLearnerPortalLink={enterpriseLearnerPortalLink}
9495
username={authenticatedUser.username}
96+
name={authenticatedUser.name}
9597
/>
9698
)}
9799
{showUserDropdown && !authenticatedUser && (

src/learning-header/LearningHeader.test.jsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React from 'react';
2+
import { getConfig, mergeConfig } from '@edx/frontend-platform';
23
import {
34
authenticatedUser, initializeMockApp, render, screen,
45
} from '../setupTest';
@@ -15,6 +16,17 @@ describe('Header', () => {
1516
expect(screen.getByText(authenticatedUser.username)).toBeInTheDocument();
1617
});
1718

19+
it('displays user button without username', () => {
20+
const config = getConfig();
21+
mergeConfig({
22+
...config,
23+
HIDE_USERNAME_FROM_HEADER: true,
24+
});
25+
const { queryByTestId } = render(<Header />);
26+
const username = queryByTestId('username');
27+
expect(username).not.toBeInTheDocument();
28+
});
29+
1830
it('displays course data', () => {
1931
const courseData = {
2032
courseOrg: 'course-org',

src/studio-header/HeaderBody.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const HeaderBody = ({
2121
org,
2222
title,
2323
username,
24+
name,
2425
isAdmin,
2526
studioBaseUrl,
2627
logoutUrl,
@@ -100,6 +101,7 @@ const HeaderBody = ({
100101
<UserMenu
101102
{...{
102103
username,
104+
name,
103105
studioBaseUrl,
104106
logoutUrl,
105107
authenticatedUserAvatar,
@@ -125,6 +127,7 @@ HeaderBody.propTypes = {
125127
logoAltText: PropTypes.string,
126128
authenticatedUserAvatar: PropTypes.string,
127129
username: PropTypes.string,
130+
name: PropTypes.string,
128131
isAdmin: PropTypes.bool,
129132
isMobile: PropTypes.bool,
130133
isHiddenMainMenu: PropTypes.bool,
@@ -150,6 +153,7 @@ HeaderBody.defaultProps = {
150153
title: '',
151154
authenticatedUserAvatar: null,
152155
username: null,
156+
name: '',
153157
isAdmin: false,
154158
isMobile: false,
155159
isHiddenMainMenu: false,

src/studio-header/StudioHeader.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const StudioHeader = ({
2626
org,
2727
title,
2828
username: authenticatedUser?.username,
29+
name: authenticatedUser?.name,
2930
isAdmin: authenticatedUser?.administrator,
3031
authenticatedUserAvatar: authenticatedUser?.avatar,
3132
studioBaseUrl: config.STUDIO_BASE_URL,

src/studio-header/StudioHeader.test.jsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable react/prop-types */
22
import React, { useMemo } from 'react';
3+
import { getConfig, mergeConfig } from '@edx/frontend-platform';
34
import {
45
render,
56
fireEvent,
@@ -16,6 +17,7 @@ import messages from './messages';
1617
const authenticatedUser = {
1718
userId: 3,
1819
username: 'abc123',
20+
name: 'test',
1921
administrator: true,
2022
roles: [],
2123
avatar: '/imges/test.png',
@@ -128,6 +130,17 @@ describe('Header', () => {
128130
expect(avatarIcon).toBeVisible();
129131
});
130132

133+
it('user menu should not contain username', async () => {
134+
const config = getConfig();
135+
mergeConfig({
136+
...config,
137+
HIDE_USERNAME_FROM_HEADER: true,
138+
});
139+
const { container } = render(<RootWrapper {...props} />);
140+
const userMenu = container.querySelector('#user-dropdown-menu');
141+
expect(userMenu.textContent).toContain('');
142+
});
143+
131144
it('should hide nav items if prop isHiddenMainMenu true', async () => {
132145
const initialProps = { ...props, isHiddenMainMenu: true };
133146
const { queryByTestId } = render(<RootWrapper {...initialProps} />);

0 commit comments

Comments
 (0)