From a54f099d68b2b2771964da3326e0e7acb8383a47 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Wed, 19 Oct 2022 09:48:18 -0400 Subject: [PATCH] refactor: make studio header more flexible --- src/StudioHeader.jsx | 158 +++++-- src/StudioHeader.test.jsx | 97 ++-- src/__snapshots__/StudioHeader.test.jsx.snap | 457 ++++++------------- 3 files changed, 288 insertions(+), 424 deletions(-) diff --git a/src/StudioHeader.jsx b/src/StudioHeader.jsx index 6f95e2c9e..daa789114 100644 --- a/src/StudioHeader.jsx +++ b/src/StudioHeader.jsx @@ -5,11 +5,17 @@ import { AppContext } from '@edx/frontend-platform/react'; import { APP_CONFIG_INITIALIZED, ensureConfig, + getConfig, mergeConfig, subscribe, } from '@edx/frontend-platform'; +import { ActionRow } from '@edx/paragon'; -import DesktopHeader from './DesktopHeader'; +import { Menu, MenuTrigger, MenuContent } from './Menu'; +import Avatar from './Avatar'; +import { LinkedLogo, Logo } from './Logo'; + +import { CaretIcon } from './Icons'; import messages from './Header.messages'; @@ -28,7 +34,124 @@ subscribe(APP_CONFIG_INITIALIZED, () => { }, 'StudioHeader additional config'); }); -function StudioHeader({ intl, mainMenu, appMenu }) { +class StudioDesktopHeaderBase extends React.Component { + constructor(props) { // eslint-disable-line no-useless-constructor + super(props); + } + + renderUserMenu() { + const { + userMenu, + avatar, + username, + intl, + } = this.props; + + return ( + + + + {username} + + + {userMenu.map(({ type, href, content }) => ( + {content} + ))} + + + ); + } + + renderLoggedOutItems() { + const { loggedOutItems } = this.props; + + return loggedOutItems.map((item, i, arr) => ( + + {item.content} + + )); + } + + render() { + const { + logo, + logoAltText, + logoDestination, + loggedIn, + intl, + actionRowContent, + } = this.props; + const logoProps = { src: logo, alt: logoAltText, href: logoDestination }; + const logoClasses = getConfig().AUTHN_MINIMAL_HEADER ? 'mw-100' : null; + + return ( +
+ {intl.formatMessage(messages['header.label.skip.nav'])} +
+
+ {logoDestination === null ? : } + + {actionRowContent} + + +
+
+
+ ); + } +} + +StudioDesktopHeaderBase.propTypes = { + userMenu: PropTypes.arrayOf(PropTypes.shape({ + type: PropTypes.oneOf(['item', 'menu']), + href: PropTypes.string, + content: PropTypes.string, + })), + loggedOutItems: PropTypes.arrayOf(PropTypes.shape({ + type: PropTypes.oneOf(['item', 'menu']), + href: PropTypes.string, + content: PropTypes.string, + })), + logo: PropTypes.string, + logoAltText: PropTypes.string, + logoDestination: PropTypes.string, + avatar: PropTypes.string, + username: PropTypes.string, + loggedIn: PropTypes.bool, + actionRowContent: PropTypes.element, + + // i18n + intl: intlShape.isRequired, +}; + +StudioDesktopHeaderBase.defaultProps = { + userMenu: [], + loggedOutItems: [], + logo: null, + logoAltText: null, + logoDestination: null, + avatar: null, + username: null, + loggedIn: false, + actionRowContent: null, +}; + +const StudioDesktopHeader = injectIntl(StudioDesktopHeaderBase); + +function StudioHeader({ intl, actionRowContent }) { const { authenticatedUser, config } = useContext(AppContext); const userMenu = authenticatedUser === null ? [] : [ @@ -56,44 +179,21 @@ function StudioHeader({ intl, mainMenu, appMenu }) { loggedIn: authenticatedUser !== null, username: authenticatedUser !== null ? authenticatedUser.username : null, avatar: authenticatedUser !== null ? authenticatedUser.avatar : null, - mainMenu, + actionRowContent, userMenu, - appMenu, loggedOutItems: [], }; - return ; + return ; } StudioHeader.propTypes = { intl: intlShape.isRequired, - appMenu: PropTypes.shape( - { - content: PropTypes.string, - href: PropTypes.string, - menuItems: PropTypes.arrayOf( - PropTypes.shape({ - type: PropTypes.string, - href: PropTypes.string, - content: PropTypes.string, - }), - ), - }, - ), - mainMenu: PropTypes.arrayOf( - PropTypes.shape( - { - type: PropTypes.string, - href: PropTypes.string, - content: PropTypes.string, - }, - ), - ), + actionRowContent: PropTypes.element, }; StudioHeader.defaultProps = { - appMenu: null, - mainMenu: [], + actionRowContent: <>, }; export default injectIntl(StudioHeader); diff --git a/src/StudioHeader.test.jsx b/src/StudioHeader.test.jsx index 28f75abfe..cf38ca1b6 100644 --- a/src/StudioHeader.test.jsx +++ b/src/StudioHeader.test.jsx @@ -1,7 +1,13 @@ import React from 'react'; import { IntlProvider } from '@edx/frontend-platform/i18n'; import TestRenderer from 'react-test-renderer'; +import { Link } from 'react-router-dom'; import { AppContext } from '@edx/frontend-platform/react'; +import { + ActionRow, + Button, + Dropdown, +} from '@edx/paragon'; import { StudioHeader } from './index'; @@ -36,74 +42,31 @@ describe('', () => { expect(wrapper.toJSON()).toMatchSnapshot(); }); - it('renders correctly with the optional app menu', () => { - const appMenu = { - content: 'App Menu', - menuItems: [ - { - type: 'dropdown', - href: 'https://menu-href-url.org', - content: 'Content 1', - }, - { - type: 'dropdown', - href: 'https://menu-href-url.org', - content: 'Content 2', - }, - { - type: 'dropdown', - href: 'https://menu-href-url.org', - content: 'Content 3', - }, - ], - }; - const component = ( - - - - - + it('renders correctly with optional action row content', () => { + const actionRowContent = ( + <> + + + Settings + + + Dropdown Item 1 + Dropdown Item 2 + Dropdown Item 3 + + + + + ); - const wrapper = TestRenderer.create(component); - - expect(wrapper.toJSON()).toMatchSnapshot(); - }); - - it('renders correctly with the optional main menu', () => { - const mainMenu = [ - { - type: 'dropdown', - href: 'https://menu-href-url.org', - content: 'Content 1', - }, - { - type: 'dropdown', - href: 'https://menu-href-url.org', - content: 'Content 2', - }, - { - type: 'dropdown', - href: 'https://menu-href-url.org', - content: 'Content 3', - }, - ]; const component = ( ', () => { }, }} > - + ); diff --git a/src/__snapshots__/StudioHeader.test.jsx.snap b/src/__snapshots__/StudioHeader.test.jsx.snap index ad4585ff0..800271b1c 100644 --- a/src/__snapshots__/StudioHeader.test.jsx.snap +++ b/src/__snapshots__/StudioHeader.test.jsx.snap @@ -21,216 +21,83 @@ exports[` renders correctly 1`] = ` className="logo" src="https://edx-cdn.org/v3/default/logo.svg" /> - + `; -exports[` renders correctly with the optional main menu 1`] = ` +exports[` renders correctly with optional action row content 1`] = `
@@ -251,174 +118,108 @@ exports[` renders correctly with the optional main menu 1`] = ` className="logo" src="https://edx-cdn.org/v3/default/logo.svg" /> - - + + + +