Skip to content

Commit

Permalink
temp: introduce feature flag
Browse files Browse the repository at this point in the history
hide username from header would be based on HIDE_USERNAME_FROM_HEADER flag.
  • Loading branch information
mubbsharanwar committed Feb 16, 2024
1 parent 2399197 commit 12a9436
Show file tree
Hide file tree
Showing 13 changed files with 82 additions and 15 deletions.
2 changes: 2 additions & 0 deletions example/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ subscribe(APP_READY, () => {
<AppContext.Provider value={{
authenticatedUser: {
userId: '123abc',
username: 'test user',
name: 'test user',
roles: [],
administrator: false,
Expand All @@ -38,6 +39,7 @@ subscribe(APP_READY, () => {
authenticatedUser: {
userId: '123abc',
name: 'test name',
username: 'test user',
roles: [],
administrator: false,
},
Expand Down
11 changes: 9 additions & 2 deletions src/DesktopHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ class DesktopHeader extends React.Component {
const {
userMenu,
avatar,
username,
name,
intl,
} = this.props;
const hideUsername = getConfig().HIDE_USERNAME_FROM_HEADER;
const usernameOrName = hideUsername ? name : username;

return (
<Dropdown>
Expand All @@ -69,9 +72,11 @@ class DesktopHeader extends React.Component {
as={AvatarButton}
src={avatar}
alt=""
aria-label={intl.formatMessage(messages['header.label.account.menu.for'], { name })}
aria-label={intl.formatMessage(messages['header.label.account.menu.for'], { username: usernameOrName })}
data-hj-suppress
/>
>
{!hideUsername && username}
</Dropdown.Toggle>

<Dropdown.Menu alignRight>
{userMenu.map(({ type, href, content }) => (
Expand Down Expand Up @@ -153,6 +158,7 @@ DesktopHeader.propTypes = {
logoAltText: PropTypes.string,
logoDestination: PropTypes.string,
avatar: PropTypes.string,
username: PropTypes.string,
name: PropTypes.string,
loggedIn: PropTypes.bool,

Expand All @@ -168,6 +174,7 @@ DesktopHeader.defaultProps = {
logoAltText: null,
logoDestination: null,
avatar: null,
username: null,
name: null,
loggedIn: false,
};
Expand Down
4 changes: 4 additions & 0 deletions src/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ subscribe(APP_CONFIG_INITIALIZED, () => {
MINIMAL_HEADER: !!process.env.MINIMAL_HEADER,
ENTERPRISE_LEARNER_PORTAL_HOSTNAME: process.env.ENTERPRISE_LEARNER_PORTAL_HOSTNAME,
AUTHN_MINIMAL_HEADER: !!process.env.AUTHN_MINIMAL_HEADER,
// this flag is introduced to unblock for new release.
// the code behind flag would be removed in follow up PR
HIDE_USERNAME_FROM_HEADER: !!process.env.HIDE_USERNAME_FROM_HEADER,
}, 'Header additional config');
});

Expand Down Expand Up @@ -154,6 +157,7 @@ const Header = ({ intl }) => {
siteName: 'edX',
logoDestination: getConfig().MINIMAL_HEADER ? null : `${config.LMS_BASE_URL}/dashboard`,
loggedIn: authenticatedUser !== null,
username: authenticatedUser !== null ? authenticatedUser.username : null,
name: authenticatedUser !== null ? authenticatedUser.name : null,
avatar: authenticatedUser !== null ? authenticatedUser.avatar : null,
mainMenu: getConfig().MINIMAL_HEADER || getConfig().AUTHN_MINIMAL_HEADER ? [] : mainMenu,
Expand Down
4 changes: 2 additions & 2 deletions src/Header.messages.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ const messages = defineMessages({
},
'header.label.account.menu.for': {
id: 'header.label.account.menu.for',
defaultMessage: 'Account menu for {name}',
description: 'The aria label for the account menu trigger when the name is displayed in it',
defaultMessage: 'Account menu for {username}',
description: 'The aria label for the account menu trigger when the username is displayed in it',
},
'header.label.main.nav': {
id: 'header.label.main.nav',
Expand Down
1 change: 1 addition & 0 deletions src/Header.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ describe('<Header />', () => {
const contextValue = {
authenticatedUser: {
userId: 'abc123',
username: 'edX',
name: 'edX',
roles: [],
administrator: false,
Expand Down
6 changes: 4 additions & 2 deletions src/__snapshots__/Header.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ exports[`<Header /> minimal renders correctly for authenticated users when minim
alt=""
aria-expanded={false}
aria-haspopup={true}
aria-label="Account menu for "
aria-label="Account menu for edX"
className="btn-avatar pgn__avatar-button-avatar pgn__avatar-button-avatar-md dropdown-toggle btn btn-tertiary btn-md"
data-hj-suppress={true}
disabled={false}
Expand All @@ -50,6 +50,7 @@ exports[`<Header /> minimal renders correctly for authenticated users when minim
className="pgn__avatar pgn__avatar-sm"
src="icon/mock/path"
/>
edX
</button>
</div>
</nav>
Expand Down Expand Up @@ -179,6 +180,7 @@ exports[`<Header /> renders correctly for authenticated users on desktop 1`] = `
className="pgn__avatar pgn__avatar-sm"
src="icon/mock/path"
/>
edX
</button>
</div>
</nav>
Expand Down Expand Up @@ -291,7 +293,7 @@ exports[`<Header /> renders correctly for authenticated users on mobile 1`] = `
type="button"
>
<img
alt={null}
alt="edX"
className="pgn__avatar pgn__avatar-sm"
src="icon/mock/path"
/>
Expand Down
18 changes: 14 additions & 4 deletions src/learning-header/AuthenticatedUserDropdown.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,25 @@ const AuthenticatedUserDropdown = (props) => {
careersMenuItem = '';
}

const dropdownToggle = (
<Dropdown.Toggle variant="outline-primary" id="user-dropdown">
<FontAwesomeIcon icon={faUserCircle} className="d-md-none" size="lg" />
{getConfig().HIDE_USERNAME_FROM_HEADER ? (
<Avatar size="sm" alt={name} className="mr-2" />
) : (
<span data-hj-suppress className="d-none d-md-inline" data-testid="username">
{username}
</span>
)}
</Dropdown.Toggle>
);

return (
<>
<a className="text-gray-700" href={`${getConfig().SUPPORT_URL}`}>{intl.formatMessage(messages.help)}</a>
{showNotificationsTray && <Notifications />}
<Dropdown className="user-dropdown ml-3">
<Dropdown.Toggle variant="outline-primary" id="user-dropdown">
<FontAwesomeIcon icon={faUserCircle} className="d-md-none" size="lg" />
<Avatar size="sm" alt={name} className="mr-2" />
</Dropdown.Toggle>
{dropdownToggle}
<Dropdown.Menu className="dropdown-menu-right zIndex-2">
{dashboardMenuItem}
{careersMenuItem}
Expand Down
1 change: 1 addition & 0 deletions src/learning-header/LearningHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ subscribe(APP_CONFIG_INITIALIZED, () => {
mergeConfig({
ACCOUNT_SETTINGS_URL: process.env.ACCOUNT_SETTINGS_URL || '',
NOTIFICATION_FEEDBACK_URL: process.env.NOTIFICATION_FEEDBACK_URL || '',
HIDE_USERNAME_FROM_HEADER: !!process.env.HIDE_USERNAME_FROM_HEADER,
}, 'Learning Header additional config');
});

Expand Down
16 changes: 14 additions & 2 deletions src/learning-header/LearningHeader.test.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { getConfig, mergeConfig } from '@edx/frontend-platform';
import {
initializeMockApp, render, screen,
authenticatedUser, initializeMockApp, render, screen,
} from '../setupTest';
import { LearningHeader as Header } from '../index';

Expand All @@ -12,7 +13,18 @@ describe('Header', () => {

it('displays user button', () => {
render(<Header />);
expect(screen.getByRole('button', { className: 'd-md-none' })).toBeInTheDocument();
expect(screen.getByText(authenticatedUser.username)).toBeInTheDocument();
});

it('displays user button without username', () => {
const config = getConfig();
mergeConfig({
...config,
HIDE_USERNAME_FROM_HEADER: true,
});
const { queryByTestId } = render(<Header />);
const userName = queryByTestId('username');
expect(userName).not.toBeInTheDocument();
});

it('displays course data', () => {
Expand Down
4 changes: 4 additions & 0 deletions src/studio-header/HeaderBody.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const HeaderBody = ({
number,
org,
title,
username,
name,
isAdmin,
studioBaseUrl,
Expand Down Expand Up @@ -99,6 +100,7 @@ const HeaderBody = ({
<Nav>
<UserMenu
{...{
username,
name,
studioBaseUrl,
logoutUrl,
Expand All @@ -124,6 +126,7 @@ HeaderBody.propTypes = {
logo: PropTypes.string,
logoAltText: PropTypes.string,
authenticatedUserAvatar: PropTypes.string,
username: PropTypes.string,
name: PropTypes.string,
isAdmin: PropTypes.bool,
isMobile: PropTypes.bool,
Expand All @@ -149,6 +152,7 @@ HeaderBody.defaultProps = {
org: '',
title: '',
authenticatedUserAvatar: null,
username: null,
name: null,
isAdmin: false,
isMobile: false,
Expand Down
1 change: 1 addition & 0 deletions src/studio-header/StudioHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const StudioHeader = ({
number,
org,
title,
username: authenticatedUser?.username,
name: authenticatedUser?.name,
isAdmin: authenticatedUser?.administrator,
authenticatedUserAvatar: authenticatedUser?.avatar,
Expand Down
12 changes: 12 additions & 0 deletions src/studio-header/StudioHeader.test.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable react/prop-types */
import React, { useMemo } from 'react';
import { getConfig, mergeConfig } from '@edx/frontend-platform';
import {
render,
fireEvent,
Expand Down Expand Up @@ -129,6 +130,17 @@ describe('Header', () => {
expect(avatarIcon).toBeVisible();
});

it('user menu should not contain username', async () => {
const config = getConfig();
mergeConfig({
...config,
HIDE_USERNAME_FROM_HEADER: true,
});
const { container } = render(<RootWrapper {...props} />);
const userMenue = container.querySelector('#user-dropdown-menu');
expect(userMenue.textContent).toContain('');
});

it('should hide nav items if prop isHiddenMainMenu true', async () => {
const initialProps = { ...props, isHiddenMainMenu: true };
const { queryByTestId } = render(<RootWrapper {...initialProps} />);
Expand Down
17 changes: 14 additions & 3 deletions src/studio-header/UserMenu.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform';
import {
Avatar,
} from '@openedx/paragon';
Expand All @@ -9,32 +10,38 @@ import getUserMenuItems from './utils';

const UserMenu = ({
name,
username,
studioBaseUrl,
logoutUrl,
authenticatedUserAvatar,
isMobile,
isAdmin,
// injected
intl,
}) => {
const hideUsername = getConfig().HIDE_USERNAME_FROM_HEADER;
const avatarAlt = hideUsername ? name : username;
const avatar = authenticatedUserAvatar ? (
<img
className="d-block w-100 h-100"
src={authenticatedUserAvatar}
alt={name}
alt={avatarAlt}
data-testid="avatar-image"
/>
) : (
<Avatar
size="sm"
className="mr-2"
alt={name}
alt={avatarAlt}
data-testid="avatar-icon"
/>
);

const title = (isMobile || hideUsername) ? avatar : <>{avatar}{username}</>;

return (
<NavDropdownMenu
buttonTitle={avatar}
buttonTitle={title}
id="user-dropdown-menu"
items={getUserMenuItems({
studioBaseUrl,
Expand All @@ -47,18 +54,22 @@ const UserMenu = ({
};

UserMenu.propTypes = {
username: PropTypes.string,
name: PropTypes.string,
studioBaseUrl: PropTypes.string.isRequired,
logoutUrl: PropTypes.string.isRequired,
authenticatedUserAvatar: PropTypes.string,
isMobile: PropTypes.bool,
isAdmin: PropTypes.bool,
// injected
intl: intlShape.isRequired,
};

UserMenu.defaultProps = {
isMobile: false,
isAdmin: false,
authenticatedUserAvatar: null,
username: null,
name: null,
};

Expand Down

0 comments on commit 12a9436

Please sign in to comment.