-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add StudioHeader with optional AppMenu (#199)
* feat: Add StudioHeader with optional AppMenu StudioHeader is a graft of Header with an additional optional AppMenu. Some Frontend Apps use Menus in their custom headers to provide more functionality in their apps. By adding this functionality in StudioHeader, it will be easier for frontend apps in Studio to adopt this component without it affecting the main Header component. * test: Add tests for StudioHeader and AppMenu * fix: Remove orderHistory * fix: Remove Responsive components * fix: Redefine User Menu for Studio The userMenu in StudioHeader will be used more for Studio related items such as Studio Home and Studio Maintenance. This requires new messages and reestablishing the url destinations of these menu items. * fix: Remove loggedOutItems * fix: Remove AUTHN_MINIMAL_HEADER items * fix: Remove unnecessary tests Anonymous sessions do not exist in the Studio. And Studio is not Mobile Ready. Tests of these kind are superfluous and have been removed. * feat: Turn mainMenu into an optional prop * test: Add test for optional mainMenu prop * feat: Update snapshots * fix: Remove ResponsiveContext * fix: Remove href and update appMenu prop Dropping the href because having a link that also works as a dropdown can be mildly confusing. Changing menu (type, href, content ) triplet to stick to the pattern; so we removed "menu". Also adding brackets around the triplet. Lastly, updating test and snapshot. Co-authored-by: Carlos Muniz <[email protected]>
- Loading branch information
Carlos Muniz
and
Carlos Muniz
authored
Apr 21, 2022
1 parent
a8d5a0b
commit c35df7e
Showing
7 changed files
with
719 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import React, { useContext } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; | ||
import { AppContext } from '@edx/frontend-platform/react'; | ||
import { | ||
APP_CONFIG_INITIALIZED, | ||
ensureConfig, | ||
mergeConfig, | ||
subscribe, | ||
} from '@edx/frontend-platform'; | ||
|
||
import DesktopHeader from './DesktopHeader'; | ||
|
||
import messages from './Header.messages'; | ||
|
||
ensureConfig([ | ||
'STUDIO_BASE_URL', | ||
'LOGOUT_URL', | ||
'LOGIN_URL', | ||
'SITE_NAME', | ||
'LOGO_URL', | ||
'ORDER_HISTORY_URL', | ||
], 'StudioHeader component'); | ||
|
||
subscribe(APP_CONFIG_INITIALIZED, () => { | ||
mergeConfig({ | ||
AUTHN_MINIMAL_HEADER: !!process.env.AUTHN_MINIMAL_HEADER, | ||
}, 'StudioHeader additional config'); | ||
}); | ||
|
||
function StudioHeader({ intl, mainMenu, appMenu }) { | ||
const { authenticatedUser, config } = useContext(AppContext); | ||
|
||
const userMenu = authenticatedUser === null ? [] : [ | ||
{ | ||
type: 'item', | ||
href: `${config.STUDIO_BASE_URL}`, | ||
content: intl.formatMessage(messages['header.user.menu.studio.home']), | ||
}, | ||
{ | ||
type: 'item', | ||
href: `${config.STUDIO_BASE_URL}/maintenance`, | ||
content: intl.formatMessage(messages['header.user.menu.studio.maintenance']), | ||
}, | ||
{ | ||
type: 'item', | ||
href: config.LOGOUT_URL, | ||
content: intl.formatMessage(messages['header.user.menu.logout']), | ||
}, | ||
]; | ||
|
||
const props = { | ||
logo: config.LOGO_URL, | ||
logoAltText: config.SITE_NAME, | ||
logoDestination: config.STUDIO_BASE_URL, | ||
loggedIn: authenticatedUser !== null, | ||
username: authenticatedUser !== null ? authenticatedUser.username : null, | ||
avatar: authenticatedUser !== null ? authenticatedUser.avatar : null, | ||
mainMenu, | ||
userMenu, | ||
appMenu, | ||
loggedOutItems: [], | ||
}; | ||
|
||
return <DesktopHeader {...props} />; | ||
} | ||
|
||
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, | ||
}, | ||
), | ||
), | ||
}; | ||
|
||
StudioHeader.defaultProps = { | ||
appMenu: null, | ||
mainMenu: [], | ||
}; | ||
|
||
export default injectIntl(StudioHeader); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import React from 'react'; | ||
import { IntlProvider } from '@edx/frontend-platform/i18n'; | ||
import TestRenderer from 'react-test-renderer'; | ||
import { AppContext } from '@edx/frontend-platform/react'; | ||
|
||
import { StudioHeader } from './index'; | ||
|
||
describe('<StudioHeader />', () => { | ||
it('renders correctly', () => { | ||
const component = ( | ||
<IntlProvider locale="en" messages={{}}> | ||
<AppContext.Provider | ||
value={{ | ||
authenticatedUser: { | ||
userId: 'abc123', | ||
username: 'edX', | ||
roles: [], | ||
administrator: false, | ||
}, | ||
config: { | ||
STUDIO_BASE_URL: process.env.STUDIO_BASE_URL, | ||
SITE_NAME: process.env.SITE_NAME, | ||
LOGIN_URL: process.env.LOGIN_URL, | ||
LOGOUT_URL: process.env.LOGOUT_URL, | ||
LOGO_URL: process.env.LOGO_URL, | ||
}, | ||
}} | ||
> | ||
<StudioHeader /> | ||
</AppContext.Provider> | ||
</IntlProvider> | ||
); | ||
|
||
const wrapper = TestRenderer.create(component); | ||
|
||
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 = ( | ||
<IntlProvider locale="en" messages={{}}> | ||
<AppContext.Provider | ||
value={{ | ||
authenticatedUser: { | ||
userId: 'abc123', | ||
username: 'edX', | ||
roles: [], | ||
administrator: false, | ||
}, | ||
config: { | ||
STUDIO_BASE_URL: process.env.STUDIO_BASE_URL, | ||
SITE_NAME: process.env.SITE_NAME, | ||
LOGIN_URL: process.env.LOGIN_URL, | ||
LOGOUT_URL: process.env.LOGOUT_URL, | ||
LOGO_URL: process.env.LOGO_URL, | ||
}, | ||
}} | ||
> | ||
<StudioHeader appMenu={appMenu} /> | ||
</AppContext.Provider> | ||
</IntlProvider> | ||
); | ||
|
||
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 = ( | ||
<IntlProvider locale="en" messages={{}}> | ||
<AppContext.Provider | ||
value={{ | ||
authenticatedUser: { | ||
userId: 'abc123', | ||
username: 'edX', | ||
roles: [], | ||
administrator: false, | ||
}, | ||
config: { | ||
STUDIO_BASE_URL: process.env.STUDIO_BASE_URL, | ||
SITE_NAME: process.env.SITE_NAME, | ||
LOGIN_URL: process.env.LOGIN_URL, | ||
LOGOUT_URL: process.env.LOGOUT_URL, | ||
LOGO_URL: process.env.LOGO_URL, | ||
}, | ||
}} | ||
> | ||
<StudioHeader mainMenu={mainMenu} /> | ||
</AppContext.Provider> | ||
</IntlProvider> | ||
); | ||
|
||
const wrapper = TestRenderer.create(component); | ||
|
||
expect(wrapper.toJSON()).toMatchSnapshot(); | ||
}); | ||
}); |
Oops, something went wrong.