feat: add career link to user dropdown (#152)
Co-authored-by: leangseu-edx <83240113+leangseu-edx@users.noreply.github.com>
This commit is contained in:
1
.env
1
.env
@@ -39,3 +39,4 @@ HOTJAR_DEBUG=''
|
||||
ACCOUNT_SETTINGS_URL=''
|
||||
ACCOUNT_PROFILE_URL=''
|
||||
ENABLE_NOTICES=''
|
||||
CAREER_LINK_URL=''
|
||||
|
||||
@@ -46,3 +46,4 @@ HOTJAR_DEBUG=''
|
||||
ACCOUNT_SETTINGS_URL='http://localhost:1997'
|
||||
ACCOUNT_PROFILE_URL='http://localhost:1995'
|
||||
ENABLE_NOTICES=''
|
||||
CAREER_LINK_URL=''
|
||||
|
||||
@@ -45,3 +45,4 @@ HOTJAR_DEBUG=''
|
||||
ACCOUNT_SETTINGS_URL='http://account-settings-url.test'
|
||||
ACCOUNT_PROFILE_URL='http://account-profile-url.test'
|
||||
ENABLE_NOTICES=''
|
||||
CAREER_LINK_URL=''
|
||||
|
||||
@@ -23,7 +23,7 @@ import ZendeskFab from 'components/ZendeskFab';
|
||||
import track from 'tracking';
|
||||
|
||||
import fakeData from 'data/services/lms/fakeData/courses';
|
||||
import LearnerDashboardHeaderVariant from './containers/LearnerDashboardHeaderVariant';
|
||||
import LearnerDashboardHeader from './containers/LearnerDashboardHeader';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
@@ -77,7 +77,7 @@ export const App = () => {
|
||||
<title>{formatMessage(messages.pageTitle)}</title>
|
||||
</Helmet>
|
||||
<div>
|
||||
<LearnerDashboardHeaderVariant />
|
||||
<LearnerDashboardHeader />
|
||||
<main>
|
||||
{hasNetworkFailure
|
||||
? (
|
||||
|
||||
@@ -12,14 +12,14 @@ import { Alert } from '@edx/paragon';
|
||||
import { RequestKeys } from 'data/constants/requests';
|
||||
import { reduxHooks } from 'hooks';
|
||||
import Dashboard from 'containers/Dashboard';
|
||||
import LearnerDashboardHeaderVariant from 'containers/LearnerDashboardHeaderVariant';
|
||||
import LearnerDashboardHeader from 'containers/LearnerDashboardHeader';
|
||||
import { App } from './App';
|
||||
import messages from './messages';
|
||||
|
||||
jest.mock('@edx/frontend-component-footer', () => 'Footer');
|
||||
|
||||
jest.mock('containers/Dashboard', () => 'Dashboard');
|
||||
jest.mock('containers/LearnerDashboardHeaderVariant', () => 'LearnerDashboardHeaderVariant');
|
||||
jest.mock('containers/LearnerDashboardHeader', () => 'LearnerDashboardHeader');
|
||||
jest.mock('components/ZendeskFab', () => 'ZendeskFab');
|
||||
jest.mock('data/redux', () => ({
|
||||
selectors: 'redux.selectors',
|
||||
@@ -54,7 +54,7 @@ describe('App router component', () => {
|
||||
expect(el.find(Helmet).find('title').text()).toEqual(useIntl().formatMessage(messages.pageTitle));
|
||||
});
|
||||
it('displays learner dashboard header', () => {
|
||||
expect(el.find(LearnerDashboardHeaderVariant).length).toEqual(1);
|
||||
expect(el.find(LearnerDashboardHeader).length).toEqual(1);
|
||||
});
|
||||
it('wraps the page in a browser router', () => {
|
||||
expect(el.find(Router)).toMatchObject(el);
|
||||
|
||||
@@ -11,7 +11,7 @@ exports[`App router component component initialize failure snapshot 1`] = `
|
||||
</title>
|
||||
</HelmetWrapper>
|
||||
<div>
|
||||
<LearnerDashboardHeaderVariant />
|
||||
<LearnerDashboardHeader />
|
||||
<main>
|
||||
<Alert
|
||||
variant="danger"
|
||||
@@ -40,7 +40,7 @@ exports[`App router component component no network failure snapshot 1`] = `
|
||||
</title>
|
||||
</HelmetWrapper>
|
||||
<div>
|
||||
<LearnerDashboardHeaderVariant />
|
||||
<LearnerDashboardHeader />
|
||||
<main>
|
||||
<Dashboard />
|
||||
</main>
|
||||
@@ -63,7 +63,7 @@ exports[`App router component component refresh failure snapshot 1`] = `
|
||||
</title>
|
||||
</HelmetWrapper>
|
||||
<div>
|
||||
<LearnerDashboardHeaderVariant />
|
||||
<LearnerDashboardHeader />
|
||||
<main>
|
||||
<Alert
|
||||
variant="danger"
|
||||
|
||||
@@ -15,6 +15,7 @@ const configuration = {
|
||||
ZENDESK_KEY: process.env.ZENDESK_KEY,
|
||||
SUPPORT_URL: process.env.SUPPORT_URL || null,
|
||||
ENABLE_NOTICES: process.env.ENABLE_NOTICES || null,
|
||||
CAREER_LINK_URL: process.env.CAREER_LINK_URL || null,
|
||||
};
|
||||
|
||||
const features = {};
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { AppContext } from '@edx/frontend-platform/react';
|
||||
import { AvatarButton, Dropdown } from '@edx/paragon';
|
||||
|
||||
import urls from 'data/services/lms/urls';
|
||||
import { reduxHooks } from 'hooks';
|
||||
|
||||
import { useIsCollapsed, findCoursesNavDropdownClicked } from './hooks';
|
||||
import messages from './messages';
|
||||
|
||||
export const AuthenticatedUserDropdown = ({ username }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { authenticatedUser } = React.useContext(AppContext);
|
||||
const dashboard = reduxHooks.useEnterpriseDashboardData();
|
||||
const { courseSearchUrl } = reduxHooks.usePlatformSettingsData();
|
||||
const isCollapsed = useIsCollapsed();
|
||||
const { profileImage } = authenticatedUser;
|
||||
|
||||
return (
|
||||
<Dropdown variant={isCollapsed ? 'light' : 'dark'} className="user-dropdown ml-1">
|
||||
<Dropdown.Toggle
|
||||
as={AvatarButton}
|
||||
src={profileImage}
|
||||
id="user"
|
||||
variant="primary"
|
||||
>
|
||||
<span data-hj-suppress className="d-none d-md-inline">
|
||||
{username}
|
||||
</span>
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu className="dropdown-menu-right">
|
||||
<Dropdown.Header>SWITCH DASHBOARD</Dropdown.Header>
|
||||
<Dropdown.Item as="a" href="/edx-dashboard" className="active">Personal</Dropdown.Item>
|
||||
{!!dashboard && (
|
||||
<Dropdown.Item
|
||||
as="a"
|
||||
href={dashboard.url}
|
||||
key={dashboard.label}
|
||||
>
|
||||
{dashboard.label} {formatMessage(messages.dashboard)}
|
||||
</Dropdown.Item>
|
||||
)}
|
||||
<Dropdown.Divider />
|
||||
<Dropdown.Item href={`${getConfig().ACCOUNT_PROFILE_URL}/u/${username}`}>
|
||||
{formatMessage(messages.profile)}
|
||||
</Dropdown.Item>
|
||||
{isCollapsed && (
|
||||
<>
|
||||
<Dropdown.Item href={urls.programsUrl}>
|
||||
{formatMessage(messages.viewPrograms)}
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item href={courseSearchUrl} onClick={findCoursesNavDropdownClicked(courseSearchUrl)}>
|
||||
{formatMessage(messages.exploreCourses)}
|
||||
</Dropdown.Item>
|
||||
</>
|
||||
)}
|
||||
<Dropdown.Item href={getConfig().ACCOUNT_SETTINGS_URL}>
|
||||
{formatMessage(messages.account)}
|
||||
</Dropdown.Item>
|
||||
{getConfig().ORDER_HISTORY_URL && (
|
||||
<Dropdown.Item href={getConfig().ORDER_HISTORY_URL}>
|
||||
{formatMessage(messages.orderHistory)}
|
||||
</Dropdown.Item>
|
||||
)}
|
||||
<Dropdown.Item href={getConfig().SUPPORT_URL}>
|
||||
{formatMessage(messages.help)}
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Divider />
|
||||
<Dropdown.Item href={getConfig().LOGOUT_URL}>
|
||||
{formatMessage(messages.signOut)}
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
||||
AuthenticatedUserDropdown.propTypes = {
|
||||
username: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default AuthenticatedUserDropdown;
|
||||
@@ -1,63 +0,0 @@
|
||||
import { shallow } from 'enzyme';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
import { reduxHooks } from 'hooks';
|
||||
import { AuthenticatedUserDropdown } from './AuthenticatedUserDropdown';
|
||||
import { useIsCollapsed } from './hooks';
|
||||
|
||||
jest.mock('@edx/frontend-platform', () => ({
|
||||
getConfig: jest.fn(),
|
||||
}));
|
||||
jest.mock('@edx/frontend-platform/react', () => ({
|
||||
AppContext: {
|
||||
authenticatedUser: {
|
||||
profileImage: 'profileImage',
|
||||
},
|
||||
},
|
||||
}));
|
||||
jest.mock('hooks', () => ({
|
||||
reduxHooks: {
|
||||
useEnterpriseDashboardData: jest.fn(),
|
||||
usePlatformSettingsData: jest.fn(() => ({
|
||||
courseSearchUrl: 'test-course-search-url',
|
||||
})),
|
||||
},
|
||||
}));
|
||||
jest.mock('containers/LearnerDashboardHeader/hooks', () => ({
|
||||
useIsCollapsed: jest.fn(),
|
||||
findCoursesNavDropdownClicked: (href) => jest.fn().mockName(`findCoursesNavDropdownClicked('${href}')`),
|
||||
}));
|
||||
|
||||
const config = {
|
||||
ACCOUNT_PROFILE_URL: 'http://account-profile-url.test',
|
||||
ACCOUNT_SETTINGS_URL: 'http://account-settings-url.test',
|
||||
LOGOUT_URL: 'http://logout-url.test',
|
||||
ORDER_HISTORY_URL: 'http://order-history-url.test',
|
||||
SUPPORT_URL: 'http://localhost:18000/support',
|
||||
};
|
||||
getConfig.mockReturnValue(config);
|
||||
|
||||
describe('AuthenticatedUserDropdown', () => {
|
||||
const props = {
|
||||
username: 'username',
|
||||
};
|
||||
const defaultDashboardData = {
|
||||
label: 'label',
|
||||
url: 'url',
|
||||
};
|
||||
|
||||
describe('snapshots', () => {
|
||||
test('with enterprise dashboard', () => {
|
||||
reduxHooks.useEnterpriseDashboardData.mockReturnValueOnce(defaultDashboardData);
|
||||
useIsCollapsed.mockReturnValueOnce(true);
|
||||
const wrapper = shallow(<AuthenticatedUserDropdown {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('without enterprise dashboard and expanded', () => {
|
||||
reduxHooks.useEnterpriseDashboardData.mockReturnValueOnce(null);
|
||||
useIsCollapsed.mockReturnValueOnce(false);
|
||||
const wrapper = shallow(<AuthenticatedUserDropdown {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5,7 +5,7 @@ import { getConfig } from '@edx/frontend-platform';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { AppContext } from '@edx/frontend-platform/react';
|
||||
|
||||
import { Button } from '@edx/paragon';
|
||||
import { Button, Badge } from '@edx/paragon';
|
||||
|
||||
import urls from 'data/services/lms/urls';
|
||||
import { reduxHooks } from 'hooks';
|
||||
@@ -45,11 +45,19 @@ export const CollapseMenuBody = ({ isOpen }) => {
|
||||
</Button>
|
||||
{authenticatedUser && (
|
||||
<>
|
||||
{dashboard && (
|
||||
{!!dashboard && (
|
||||
<Button as="a" href={dashboard.url} variant="inverse-primary">
|
||||
{formatMessage(messages.dashboard)}
|
||||
</Button>
|
||||
)}
|
||||
{!dashboard && getConfig().CAREER_LINK_URL && (
|
||||
<Button href={`${getConfig().CAREER_LINK_URL}`}>
|
||||
{formatMessage(messages.career)}
|
||||
<Badge className="px-2 mx-2" variant="warning">
|
||||
{formatMessage(messages.newAlert)}
|
||||
</Badge>
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
as="a"
|
||||
href={`${getConfig().LMS_BASE_URL}/u/${
|
||||
@@ -4,7 +4,7 @@ import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Menu, Close } from '@edx/paragon/icons';
|
||||
import { IconButton, Icon } from '@edx/paragon';
|
||||
|
||||
import { useLearnerDashboardHeaderVariantData, useIsCollapsed } from '../hooks';
|
||||
import { useLearnerDashboardHeaderData, useIsCollapsed } from '../hooks';
|
||||
|
||||
import CollapseMenuBody from './CollapseMenuBody';
|
||||
import BrandLogo from '../BrandLogo';
|
||||
@@ -14,7 +14,7 @@ import messages from '../messages';
|
||||
export const CollapsedHeader = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
const isCollapsed = useIsCollapsed();
|
||||
const { isOpen, toggleIsOpen } = useLearnerDashboardHeaderVariantData();
|
||||
const { isOpen, toggleIsOpen } = useLearnerDashboardHeaderData();
|
||||
|
||||
return (
|
||||
isCollapsed && (
|
||||
@@ -2,14 +2,14 @@ import { shallow } from 'enzyme';
|
||||
|
||||
import CollapsedHeader from '.';
|
||||
|
||||
import { useLearnerDashboardHeaderVariantData, useIsCollapsed } from '../hooks';
|
||||
import { useLearnerDashboardHeaderData, useIsCollapsed } from '../hooks';
|
||||
|
||||
jest.mock('../BrandLogo', () => jest.fn(() => 'BrandLogo'));
|
||||
jest.mock('./CollapseMenuBody', () => jest.fn(() => 'CollapseMenuBody'));
|
||||
|
||||
jest.mock('../hooks', () => ({
|
||||
useIsCollapsed: jest.fn(() => true),
|
||||
useLearnerDashboardHeaderVariantData: jest.fn(() => ({
|
||||
useLearnerDashboardHeaderData: jest.fn(() => ({
|
||||
isOpen: false,
|
||||
toggleIsOpen: jest.fn().mockName('toggleIsOpen'),
|
||||
})),
|
||||
@@ -28,7 +28,7 @@ describe('CollapsedHeader', () => {
|
||||
});
|
||||
|
||||
it('renders with isOpen true', () => {
|
||||
useLearnerDashboardHeaderVariantData.mockReturnValueOnce({
|
||||
useLearnerDashboardHeaderData.mockReturnValueOnce({
|
||||
isOpen: true,
|
||||
toggleIsOpen: jest.fn().mockName('toggleIsOpen'),
|
||||
});
|
||||
@@ -3,7 +3,7 @@ import React from 'react';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { AppContext } from '@edx/frontend-platform/react';
|
||||
import { AvatarButton, Dropdown } from '@edx/paragon';
|
||||
import { AvatarButton, Dropdown, Badge } from '@edx/paragon';
|
||||
|
||||
import { reduxHooks } from 'hooks';
|
||||
|
||||
@@ -39,6 +39,14 @@ export const AuthenticatedUserDropdown = () => {
|
||||
</Dropdown.Item>
|
||||
)}
|
||||
<Dropdown.Divider />
|
||||
{!dashboard && getConfig().CAREER_LINK_URL && (
|
||||
<Dropdown.Item href={`${getConfig().CAREER_LINK_URL}`}>
|
||||
{formatMessage(messages.career)}
|
||||
<Badge className="px-2 mx-2" variant="warning">
|
||||
{formatMessage(messages.newAlert)}
|
||||
</Badge>
|
||||
</Dropdown.Item>
|
||||
)}
|
||||
<Dropdown.Item href={`${getConfig().ACCOUNT_PROFILE_URL}/u/${authenticatedUser.username}`}>
|
||||
{formatMessage(messages.profile)}
|
||||
</Dropdown.Item>
|
||||
@@ -36,6 +36,7 @@ const config = {
|
||||
LOGOUT_URL: 'http://logout-url.test',
|
||||
ORDER_HISTORY_URL: 'http://order-history-url.test',
|
||||
SUPPORT_URL: 'http://localhost:18000/support',
|
||||
CAREER_LINK_URL: 'http://localhost:18000/career',
|
||||
};
|
||||
getConfig.mockReturnValue(config);
|
||||
|
||||
@@ -98,6 +98,17 @@ exports[`AuthenticatedUserDropdown snapshots without enterprise dashboard and ex
|
||||
Personal
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Divider />
|
||||
<Dropdown.Item
|
||||
href="http://localhost:18000/career"
|
||||
>
|
||||
Career
|
||||
<Badge
|
||||
className="px-2 mx-2"
|
||||
variant="warning"
|
||||
>
|
||||
New
|
||||
</Badge>
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="http://account-profile-url.test/u/username"
|
||||
>
|
||||
@@ -1,63 +0,0 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Image } from '@edx/paragon';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
export const GreetingBanner = ({ size }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
let greetMessage;
|
||||
const hour = new Date().getHours();
|
||||
|
||||
if (hour > 16) {
|
||||
greetMessage = messages.goodEvening;
|
||||
} else if (hour > 11) {
|
||||
greetMessage = messages.goodAfternoon;
|
||||
} else {
|
||||
greetMessage = messages.goodMorning;
|
||||
}
|
||||
|
||||
const isSmall = size === 'small';
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'd-flex align-items-center justify-content-center',
|
||||
{ 'pb-5': !isSmall, 'p-3.5': isSmall },
|
||||
)}
|
||||
>
|
||||
<a href={`${getConfig().LMS_BASE_URL}/dashboard`}>
|
||||
<Image
|
||||
style={{ width: isSmall ? '46px' : '148px' }}
|
||||
className="d-block"
|
||||
src={getConfig().LOGO_WHITE_URL}
|
||||
alt={getConfig().SITE_NAME}
|
||||
/>
|
||||
</a>
|
||||
<div className={`greetings-slash-container-${size} bg-brand-500`} />
|
||||
{isSmall
|
||||
? (
|
||||
<h5 role="presentation" className="text-center text-accent-b">
|
||||
{formatMessage(greetMessage)}
|
||||
</h5>
|
||||
) : (
|
||||
<h1
|
||||
role="presentation"
|
||||
className="text-center text-accent-b display-1"
|
||||
>
|
||||
{formatMessage(greetMessage)}
|
||||
</h1>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
GreetingBanner.propTypes = {
|
||||
size: PropTypes.oneOf(['small', 'large']).isRequired,
|
||||
};
|
||||
|
||||
export default GreetingBanner;
|
||||
@@ -1,29 +0,0 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { GreetingBanner } from './GreetingBanner';
|
||||
|
||||
describe('GreetingBanner', () => {
|
||||
const morning = new Date('2021-01-01T11:59:59.999');
|
||||
const afternoon = new Date('2021-01-01T16:59:59.999');
|
||||
const evening = new Date('2021-01-01T18:00:00');
|
||||
afterAll(() => jest.useRealTimers());
|
||||
describe('snapshots', () => {
|
||||
['small', 'large'].forEach((size) => {
|
||||
test(`with size ${size} and morning`, () => {
|
||||
jest.useFakeTimers('modern').setSystemTime(morning);
|
||||
const wrapper = shallow(<GreetingBanner size={size} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test(`with size ${size} and afternoon`, () => {
|
||||
jest.useFakeTimers('modern').setSystemTime(afternoon);
|
||||
const wrapper = shallow(<GreetingBanner size={size} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test(`with size ${size} and evening`, () => {
|
||||
jest.useFakeTimers('modern').setSystemTime(evening);
|
||||
const wrapper = shallow(<GreetingBanner size={size} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,143 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`AuthenticatedUserDropdown snapshots with enterprise dashboard 1`] = `
|
||||
<Dropdown
|
||||
className="user-dropdown ml-1"
|
||||
variant="light"
|
||||
>
|
||||
<Dropdown.Toggle
|
||||
id="user"
|
||||
src="profileImage"
|
||||
variant="primary"
|
||||
>
|
||||
<span
|
||||
className="d-none d-md-inline"
|
||||
data-hj-suppress={true}
|
||||
>
|
||||
username
|
||||
</span>
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu
|
||||
className="dropdown-menu-right"
|
||||
>
|
||||
<Dropdown.Header>
|
||||
SWITCH DASHBOARD
|
||||
</Dropdown.Header>
|
||||
<Dropdown.Item
|
||||
as="a"
|
||||
className="active"
|
||||
href="/edx-dashboard"
|
||||
>
|
||||
Personal
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
as="a"
|
||||
href="url"
|
||||
key="label"
|
||||
>
|
||||
label
|
||||
|
||||
Dashboard
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Divider />
|
||||
<Dropdown.Item
|
||||
href="http://account-profile-url.test/u/username"
|
||||
>
|
||||
Profile
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="http://localhost:18000/dashboard/programs"
|
||||
>
|
||||
View Programs
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="test-course-search-url"
|
||||
onClick={[MockFunction findCoursesNavDropdownClicked('test-course-search-url')]}
|
||||
>
|
||||
Explore courses
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="http://account-settings-url.test"
|
||||
>
|
||||
Account
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="http://order-history-url.test"
|
||||
>
|
||||
Order History
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="http://localhost:18000/support"
|
||||
>
|
||||
Help
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Divider />
|
||||
<Dropdown.Item
|
||||
href="http://logout-url.test"
|
||||
>
|
||||
Sign Out
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
`;
|
||||
|
||||
exports[`AuthenticatedUserDropdown snapshots without enterprise dashboard and expanded 1`] = `
|
||||
<Dropdown
|
||||
className="user-dropdown ml-1"
|
||||
variant="dark"
|
||||
>
|
||||
<Dropdown.Toggle
|
||||
id="user"
|
||||
src="profileImage"
|
||||
variant="primary"
|
||||
>
|
||||
<span
|
||||
className="d-none d-md-inline"
|
||||
data-hj-suppress={true}
|
||||
>
|
||||
username
|
||||
</span>
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu
|
||||
className="dropdown-menu-right"
|
||||
>
|
||||
<Dropdown.Header>
|
||||
SWITCH DASHBOARD
|
||||
</Dropdown.Header>
|
||||
<Dropdown.Item
|
||||
as="a"
|
||||
className="active"
|
||||
href="/edx-dashboard"
|
||||
>
|
||||
Personal
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Divider />
|
||||
<Dropdown.Item
|
||||
href="http://account-profile-url.test/u/username"
|
||||
>
|
||||
Profile
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="http://account-settings-url.test"
|
||||
>
|
||||
Account
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="http://order-history-url.test"
|
||||
>
|
||||
Order History
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="http://localhost:18000/support"
|
||||
>
|
||||
Help
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Divider />
|
||||
<Dropdown.Item
|
||||
href="http://logout-url.test"
|
||||
>
|
||||
Sign Out
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
`;
|
||||
@@ -1,181 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`GreetingBanner snapshots with size large and afternoon 1`] = `
|
||||
<div
|
||||
className="d-flex align-items-center justify-content-center pb-5"
|
||||
>
|
||||
<a
|
||||
href="http://localhost:18000/dashboard"
|
||||
>
|
||||
<Image
|
||||
alt="localhost"
|
||||
className="d-block"
|
||||
src="https://edx-cdn.org/v3/default/logo-white.svg"
|
||||
style={
|
||||
Object {
|
||||
"width": "148px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
className="greetings-slash-container-large bg-brand-500"
|
||||
/>
|
||||
<h1
|
||||
className="text-center text-accent-b display-1"
|
||||
role="presentation"
|
||||
>
|
||||
Good Afternoon!
|
||||
</h1>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`GreetingBanner snapshots with size large and evening 1`] = `
|
||||
<div
|
||||
className="d-flex align-items-center justify-content-center pb-5"
|
||||
>
|
||||
<a
|
||||
href="http://localhost:18000/dashboard"
|
||||
>
|
||||
<Image
|
||||
alt="localhost"
|
||||
className="d-block"
|
||||
src="https://edx-cdn.org/v3/default/logo-white.svg"
|
||||
style={
|
||||
Object {
|
||||
"width": "148px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
className="greetings-slash-container-large bg-brand-500"
|
||||
/>
|
||||
<h1
|
||||
className="text-center text-accent-b display-1"
|
||||
role="presentation"
|
||||
>
|
||||
Good Evening!
|
||||
</h1>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`GreetingBanner snapshots with size large and morning 1`] = `
|
||||
<div
|
||||
className="d-flex align-items-center justify-content-center pb-5"
|
||||
>
|
||||
<a
|
||||
href="http://localhost:18000/dashboard"
|
||||
>
|
||||
<Image
|
||||
alt="localhost"
|
||||
className="d-block"
|
||||
src="https://edx-cdn.org/v3/default/logo-white.svg"
|
||||
style={
|
||||
Object {
|
||||
"width": "148px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
className="greetings-slash-container-large bg-brand-500"
|
||||
/>
|
||||
<h1
|
||||
className="text-center text-accent-b display-1"
|
||||
role="presentation"
|
||||
>
|
||||
Good Morning!
|
||||
</h1>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`GreetingBanner snapshots with size small and afternoon 1`] = `
|
||||
<div
|
||||
className="d-flex align-items-center justify-content-center p-3.5"
|
||||
>
|
||||
<a
|
||||
href="http://localhost:18000/dashboard"
|
||||
>
|
||||
<Image
|
||||
alt="localhost"
|
||||
className="d-block"
|
||||
src="https://edx-cdn.org/v3/default/logo-white.svg"
|
||||
style={
|
||||
Object {
|
||||
"width": "46px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
className="greetings-slash-container-small bg-brand-500"
|
||||
/>
|
||||
<h5
|
||||
className="text-center text-accent-b"
|
||||
role="presentation"
|
||||
>
|
||||
Good Afternoon!
|
||||
</h5>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`GreetingBanner snapshots with size small and evening 1`] = `
|
||||
<div
|
||||
className="d-flex align-items-center justify-content-center p-3.5"
|
||||
>
|
||||
<a
|
||||
href="http://localhost:18000/dashboard"
|
||||
>
|
||||
<Image
|
||||
alt="localhost"
|
||||
className="d-block"
|
||||
src="https://edx-cdn.org/v3/default/logo-white.svg"
|
||||
style={
|
||||
Object {
|
||||
"width": "46px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
className="greetings-slash-container-small bg-brand-500"
|
||||
/>
|
||||
<h5
|
||||
className="text-center text-accent-b"
|
||||
role="presentation"
|
||||
>
|
||||
Good Evening!
|
||||
</h5>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`GreetingBanner snapshots with size small and morning 1`] = `
|
||||
<div
|
||||
className="d-flex align-items-center justify-content-center p-3.5"
|
||||
>
|
||||
<a
|
||||
href="http://localhost:18000/dashboard"
|
||||
>
|
||||
<Image
|
||||
alt="localhost"
|
||||
className="d-block"
|
||||
src="https://edx-cdn.org/v3/default/logo-white.svg"
|
||||
style={
|
||||
Object {
|
||||
"width": "46px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
className="greetings-slash-container-small bg-brand-500"
|
||||
/>
|
||||
<h5
|
||||
className="text-center text-accent-b"
|
||||
role="presentation"
|
||||
>
|
||||
Good Morning!
|
||||
</h5>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,97 +1,10 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LearnerDashboardHeader UserMenu snapshots with authenticated user 1`] = `
|
||||
<AuthenticatedUserDropdown
|
||||
username="test-username"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`LearnerDashboardHeader UserMenu snapshots without authenticated user 1`] = `""`;
|
||||
|
||||
exports[`LearnerDashboardHeader snapshots with collapsed 1`] = `
|
||||
exports[`LearnerDashboardHeader render 1`] = `
|
||||
<Fragment>
|
||||
<ConfirmEmailBanner />
|
||||
<div
|
||||
className="flex-column bg-primary"
|
||||
>
|
||||
<header
|
||||
className="learner-dashboard-header"
|
||||
>
|
||||
<div
|
||||
className="d-flex"
|
||||
>
|
||||
<div
|
||||
className="flex-grow-1"
|
||||
>
|
||||
<GreetingBanner
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="my-auto ml-1 d-flex"
|
||||
>
|
||||
<IconButton
|
||||
alt="Course search"
|
||||
as="a"
|
||||
href="test-course-search-url"
|
||||
iconAs="Icon"
|
||||
invertColors={true}
|
||||
onClick={[MockFunction findCoursesNavClicked('test-course-search-url')]}
|
||||
src={[MockFunction icons.Search]}
|
||||
variant="primary"
|
||||
/>
|
||||
<UserMenu />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</div>
|
||||
<MasqueradeBar />
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`LearnerDashboardHeader snapshots without collapsed 1`] = `
|
||||
<Fragment>
|
||||
<ConfirmEmailBanner />
|
||||
<div
|
||||
className="flex-column bg-primary"
|
||||
>
|
||||
<Image
|
||||
className="d-block w-100 mb-4"
|
||||
src="icon/mock/path"
|
||||
/>
|
||||
<header
|
||||
className="learner-dashboard-header"
|
||||
>
|
||||
<div
|
||||
className="d-flex"
|
||||
>
|
||||
<Button
|
||||
as="a"
|
||||
href="http://localhost:18000/dashboard/programs"
|
||||
iconBefore={[MockFunction icons.Program]}
|
||||
variant="inverse-tertiary"
|
||||
>
|
||||
Switch to Programs
|
||||
</Button>
|
||||
<div
|
||||
className="flex-grow-1"
|
||||
/>
|
||||
<Button
|
||||
as="a"
|
||||
href="test-course-search-url"
|
||||
iconBefore={[MockFunction icons.Search]}
|
||||
onClick={[MockFunction findCoursesNavClicked('test-course-search-url')]}
|
||||
variant="inverse-tertiary"
|
||||
>
|
||||
Explore courses
|
||||
</Button>
|
||||
<UserMenu />
|
||||
</div>
|
||||
</header>
|
||||
<GreetingBanner
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<CollapsedHeader />
|
||||
<ExpandedHeader />
|
||||
<MasqueradeBar />
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import React from 'react';
|
||||
import { useWindowSize, breakpoints } from '@edx/paragon';
|
||||
import track from 'tracking';
|
||||
import { StrictDict } from 'utils';
|
||||
import { linkNames } from 'tracking/constants';
|
||||
|
||||
import * as module from './hooks';
|
||||
|
||||
export const state = StrictDict({
|
||||
isOpen: (val) => React.useState(val), // eslint-disable-line
|
||||
});
|
||||
|
||||
export const useIsCollapsed = () => {
|
||||
const { width } = useWindowSize();
|
||||
const isCollapsed = React.useMemo(() => (width <= breakpoints.large.maxWidth), [width]);
|
||||
const isCollapsed = React.useMemo(() => (width <= breakpoints.large.minWidth), [width]);
|
||||
return isCollapsed;
|
||||
};
|
||||
|
||||
@@ -17,8 +24,19 @@ export const findCoursesNavDropdownClicked = (href) => track.findCourses.findCou
|
||||
linkName: linkNames.learnerHomeNavDropdownExplore,
|
||||
});
|
||||
|
||||
export const useLearnerDashboardHeaderData = () => {
|
||||
const [isOpen, setIsOpen] = module.state.isOpen(false);
|
||||
const toggleIsOpen = () => setIsOpen(!isOpen);
|
||||
|
||||
return {
|
||||
isOpen,
|
||||
toggleIsOpen,
|
||||
};
|
||||
};
|
||||
|
||||
export default {
|
||||
useIsCollapsed,
|
||||
findCoursesNavClicked,
|
||||
findCoursesNavDropdownClicked,
|
||||
useLearnerDashboardHeaderData,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
import { useWindowSize, breakpoints } from '@edx/paragon';
|
||||
import track from 'tracking';
|
||||
import { linkNames } from 'tracking/constants';
|
||||
import { useIsCollapsed, findCoursesNavClicked, findCoursesNavDropdownClicked } from './hooks';
|
||||
|
||||
import { MockUseState } from 'testUtils';
|
||||
|
||||
import * as hooks from './hooks';
|
||||
|
||||
const state = new MockUseState(hooks);
|
||||
|
||||
const {
|
||||
useIsCollapsed,
|
||||
findCoursesNavClicked,
|
||||
findCoursesNavDropdownClicked,
|
||||
useLearnerDashboardHeaderData,
|
||||
} = hooks;
|
||||
|
||||
jest.mock('tracking', () => ({
|
||||
findCourses: {
|
||||
@@ -12,13 +24,17 @@ jest.mock('tracking', () => ({
|
||||
const url = 'http://example.com';
|
||||
|
||||
describe('LearnerDashboardHeader hooks', () => {
|
||||
describe('state values', () => {
|
||||
state.testGetter(state.keys.isOpen);
|
||||
});
|
||||
|
||||
describe('useIsCollapsed', () => {
|
||||
test('large screen is not collapsed', () => {
|
||||
useWindowSize.mockReturnValueOnce({ width: breakpoints.large.maxWidth + 1 });
|
||||
useWindowSize.mockReturnValueOnce({ width: breakpoints.large.minWidth + 1 });
|
||||
expect(useIsCollapsed()).toEqual(false);
|
||||
});
|
||||
test('small screen is collapsed', () => {
|
||||
useWindowSize.mockReturnValueOnce({ width: breakpoints.large.maxWidth - 1 });
|
||||
useWindowSize.mockReturnValueOnce({ width: breakpoints.large.minWidth - 1 });
|
||||
expect(useIsCollapsed()).toEqual(true);
|
||||
});
|
||||
});
|
||||
@@ -40,4 +56,14 @@ describe('LearnerDashboardHeader hooks', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('useLearnerDashboardHeaderData', () => {
|
||||
test('default state', () => {
|
||||
state.mock();
|
||||
const out = useLearnerDashboardHeaderData();
|
||||
state.expectInitializedWith(state.keys.isOpen, false);
|
||||
out.toggleIsOpen();
|
||||
expect(state.values.isOpen).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,92 +1,22 @@
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { AppContext } from '@edx/frontend-platform/react';
|
||||
import { Program, Search } from '@edx/paragon/icons';
|
||||
import {
|
||||
Button, Image, IconButton, Icon,
|
||||
} from '@edx/paragon';
|
||||
|
||||
import topBanner from 'assets/top_stripe.svg';
|
||||
import MasqueradeBar from 'containers/MasqueradeBar';
|
||||
import urls from 'data/services/lms/urls';
|
||||
import { reduxHooks } from 'hooks';
|
||||
|
||||
import AuthenticatedUserDropdown from './AuthenticatedUserDropdown';
|
||||
import GreetingBanner from './GreetingBanner';
|
||||
import ConfirmEmailBanner from './ConfirmEmailBanner';
|
||||
|
||||
import { useIsCollapsed, findCoursesNavClicked } from './hooks';
|
||||
import messages from './messages';
|
||||
import CollapsedHeader from './CollapsedHeader';
|
||||
import ExpandedHeader from './ExpandedHeader';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
export const UserMenu = () => {
|
||||
const { authenticatedUser } = useContext(AppContext);
|
||||
return authenticatedUser ? (<AuthenticatedUserDropdown username={authenticatedUser.username} />) : null;
|
||||
};
|
||||
export const LearnerDashboardHeader = () => (
|
||||
<>
|
||||
<ConfirmEmailBanner />
|
||||
<CollapsedHeader />
|
||||
<ExpandedHeader />
|
||||
<MasqueradeBar />
|
||||
</>
|
||||
);
|
||||
|
||||
export const LearnerDashboardHeader = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
const isCollapsed = useIsCollapsed();
|
||||
const { courseSearchUrl } = reduxHooks.usePlatformSettingsData();
|
||||
|
||||
const exploreCoursesClick = findCoursesNavClicked(courseSearchUrl);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ConfirmEmailBanner />
|
||||
<div className="flex-column bg-primary">
|
||||
{!(isCollapsed) && (
|
||||
<Image className="d-block w-100 mb-4" src={topBanner} />
|
||||
)}
|
||||
<header className="learner-dashboard-header">
|
||||
<div className="d-flex">
|
||||
{(!isCollapsed) && (
|
||||
<Button as="a" href={urls.programsUrl} variant="inverse-tertiary" iconBefore={Program}>
|
||||
{formatMessage(messages.switchToProgram)}
|
||||
</Button>
|
||||
)}
|
||||
<div className="flex-grow-1">
|
||||
{isCollapsed && <GreetingBanner size="small" />}
|
||||
</div>
|
||||
{isCollapsed ? (
|
||||
<div className="my-auto ml-1 d-flex">
|
||||
<IconButton
|
||||
alt={formatMessage(messages.courseSearchAlt)}
|
||||
as="a"
|
||||
href={courseSearchUrl}
|
||||
variant="primary"
|
||||
invertColors
|
||||
src={Search}
|
||||
iconAs={Icon}
|
||||
onClick={exploreCoursesClick}
|
||||
/>
|
||||
<UserMenu />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<Button
|
||||
as="a"
|
||||
href={courseSearchUrl}
|
||||
variant="inverse-tertiary"
|
||||
iconBefore={Search}
|
||||
onClick={exploreCoursesClick}
|
||||
>
|
||||
{formatMessage(messages.exploreCourses)}
|
||||
</Button>
|
||||
<UserMenu />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
{!isCollapsed && <GreetingBanner size="large" />}
|
||||
</div>
|
||||
<MasqueradeBar />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
LearnerDashboardHeader.propTypes = {
|
||||
};
|
||||
LearnerDashboardHeader.propTypes = {};
|
||||
|
||||
export default LearnerDashboardHeader;
|
||||
|
||||
@@ -1,12 +1,38 @@
|
||||
.greetings-slash-container-small {
|
||||
height: 4px;
|
||||
width: 40px;
|
||||
transform-origin: center;
|
||||
transform: rotate(-70deg);
|
||||
.dropdown-menu-collapse {
|
||||
width: 100vw;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
.greetings-slash-container-large {
|
||||
height: 8px;
|
||||
width: 120px;
|
||||
transform-origin: center;
|
||||
transform: rotate(-70deg);
|
||||
|
||||
.learner-variant-header {
|
||||
a {
|
||||
// needed to make the link not resize the header
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
.course-link {
|
||||
border-bottom: 2px solid !important;
|
||||
}
|
||||
|
||||
.course-link:hover {
|
||||
border-bottom: inherit !important;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-small-menu {
|
||||
> * {
|
||||
justify-content: flex-start !important;
|
||||
|
||||
border-radius: 0 !important;
|
||||
border-top: 1px solid #ddd !important;
|
||||
|
||||
&::after {
|
||||
content: '\00BB';
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
// copy from legacy dashboard
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
@@ -1,59 +1,18 @@
|
||||
import { shallow } from 'enzyme';
|
||||
import { AppContext } from '@edx/frontend-platform/react';
|
||||
import LearnerDashboardHeader from '.';
|
||||
|
||||
import LearnerDashboardHeader, { UserMenu } from '.';
|
||||
|
||||
import { useIsCollapsed } from './hooks';
|
||||
|
||||
jest.mock('@edx/frontend-platform/react', () => ({
|
||||
AppContext: {
|
||||
authenticatedUser: {
|
||||
username: 'test-username',
|
||||
},
|
||||
},
|
||||
}));
|
||||
jest.mock('./hooks', () => ({
|
||||
useIsCollapsed: jest.fn(),
|
||||
findCoursesNavClicked: (href) => jest.fn().mockName(`findCoursesNavClicked('${href}')`),
|
||||
}));
|
||||
jest.mock('hooks', () => ({
|
||||
reduxHooks: {
|
||||
usePlatformSettingsData: jest.fn(() => ({
|
||||
courseSearchUrl: 'test-course-search-url',
|
||||
})),
|
||||
},
|
||||
}));
|
||||
jest.mock('containers/MasqueradeBar', () => 'MasqueradeBar');
|
||||
|
||||
jest.mock('./CollapsedHeader', () => 'CollapsedHeader');
|
||||
jest.mock('./ConfirmEmailBanner', () => 'ConfirmEmailBanner');
|
||||
jest.mock('./AuthenticatedUserDropdown', () => 'AuthenticatedUserDropdown');
|
||||
jest.mock('./GreetingBanner', () => 'GreetingBanner');
|
||||
jest.mock('./ExpandedHeader', () => 'ExpandedHeader');
|
||||
|
||||
describe('LearnerDashboardHeader', () => {
|
||||
describe('snapshots', () => {
|
||||
test('with collapsed', () => {
|
||||
useIsCollapsed.mockReturnValueOnce(true);
|
||||
const wrapper = shallow(<LearnerDashboardHeader />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('without collapsed', () => {
|
||||
useIsCollapsed.mockReturnValueOnce(false);
|
||||
const wrapper = shallow(<LearnerDashboardHeader />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('UserMenu', () => {
|
||||
describe('snapshots', () => {
|
||||
test('with authenticated user', () => {
|
||||
const wrapper = shallow(<UserMenu />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('without authenticated user', () => {
|
||||
AppContext.authenticatedUser = null;
|
||||
const wrapper = shallow(<UserMenu />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
test('render', () => {
|
||||
const wrapper = shallow(<LearnerDashboardHeader />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.find('ConfirmEmailBanner')).toHaveLength(1);
|
||||
expect(wrapper.find('MasqueradeBar')).toHaveLength(1);
|
||||
expect(wrapper.find('CollapsedHeader')).toHaveLength(1);
|
||||
expect(wrapper.find('ExpandedHeader')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,70 +2,79 @@ import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
dashboard: {
|
||||
id: 'leanerDashboard.menu.dashboard.label',
|
||||
id: 'learnerVariantDashboard.menu.dashboard.label',
|
||||
defaultMessage: 'Dashboard',
|
||||
description: 'The text for the user menu Dashboard navigation link.',
|
||||
},
|
||||
help: {
|
||||
id: 'leanerDashboard.help.label',
|
||||
id: 'learnerVariantDashboard.help.label',
|
||||
defaultMessage: 'Help',
|
||||
description: 'The text for the link to the Help Center',
|
||||
},
|
||||
profile: {
|
||||
id: 'leanerDashboard.menu.profile.label',
|
||||
id: 'learnerVariantDashboard.menu.profile.label',
|
||||
defaultMessage: 'Profile',
|
||||
description: 'The text for the user menu Profile navigation link.',
|
||||
},
|
||||
viewPrograms: {
|
||||
id: 'leanerDashboard.menu.viewPrograms.label',
|
||||
id: 'learnerVariantDashboard.menu.viewPrograms.label',
|
||||
defaultMessage: 'View Programs',
|
||||
description: 'The text for the user menu View Programs navigation link.',
|
||||
},
|
||||
account: {
|
||||
id: 'leanerDashboard.menu.account.label',
|
||||
id: 'learnerVariantDashboard.menu.account.label',
|
||||
defaultMessage: 'Account',
|
||||
description: 'The text for the user menu Account navigation link.',
|
||||
},
|
||||
orderHistory: {
|
||||
id: 'leanerDashboard.menu.orderHistory.label',
|
||||
id: 'learnerVariantDashboard.menu.orderHistory.label',
|
||||
defaultMessage: 'Order History',
|
||||
description: 'The text for the user menu Order History navigation link.',
|
||||
},
|
||||
signOut: {
|
||||
id: 'leanerDashboard.menu.signOut.label',
|
||||
id: 'learnerVariantDashboard.menu.signOut.label',
|
||||
defaultMessage: 'Sign Out',
|
||||
description: 'The label for the user menu Sign Out action.',
|
||||
},
|
||||
|
||||
goodMorning: {
|
||||
id: 'greeting.morning',
|
||||
defaultMessage: 'Good Morning!',
|
||||
description: 'Good Morning',
|
||||
course: {
|
||||
id: 'learnerVariantDashboard.course',
|
||||
defaultMessage: 'Courses',
|
||||
description: 'Header link for switching to dashboard page.',
|
||||
},
|
||||
goodAfternoon: {
|
||||
id: 'greeting.afternoon',
|
||||
defaultMessage: 'Good Afternoon!',
|
||||
description: 'Good Afternoon',
|
||||
},
|
||||
goodEvening: {
|
||||
id: 'greeting.evening',
|
||||
defaultMessage: 'Good Evening!',
|
||||
description: 'Good Evening',
|
||||
},
|
||||
switchToProgram: {
|
||||
id: 'leanerDashboard.switchToProgram',
|
||||
defaultMessage: 'Switch to Programs',
|
||||
program: {
|
||||
id: 'learnerVariantDashboard.program',
|
||||
defaultMessage: 'Programs',
|
||||
description: 'Header link for switching to program page.',
|
||||
},
|
||||
exploreCourses: {
|
||||
id: 'leanerDashboard.exploreCourses',
|
||||
defaultMessage: 'Explore courses',
|
||||
description: 'Header link for switching to course page.',
|
||||
discoverNew: {
|
||||
id: 'learnerVariantDashboard.discoverNew',
|
||||
defaultMessage: 'Discover New',
|
||||
description: 'Header link for switching to discover page.',
|
||||
},
|
||||
courseSearchAlt: {
|
||||
id: 'leanerDashboard.courseSearchAlt',
|
||||
defaultMessage: 'Course search',
|
||||
description: 'Alt-text for course search icon button',
|
||||
logoAltText: {
|
||||
id: 'learnerVariantDashboard.logoAltText',
|
||||
defaultMessage: 'edX, Inc. Dashboard',
|
||||
description: 'Alt text for the edX logo.',
|
||||
},
|
||||
collapseMenuOpenAltText: {
|
||||
id: 'learnerVariantDashboard.collapseMenuOpenAltText',
|
||||
defaultMessage: 'Menu',
|
||||
description: 'Alt text for the collapse menu icon when the menu is open.',
|
||||
},
|
||||
collapseMenuClosedAltText: {
|
||||
id: 'learnerVariantDashboard.collapseMenuClosedAltText',
|
||||
defaultMessage: 'Close',
|
||||
description: 'Alt text for the collapse menu icon when the menu is closed.',
|
||||
},
|
||||
career: {
|
||||
id: 'leanerDashboard.menu.career.label',
|
||||
defaultMessage: 'Career',
|
||||
description: 'The text for the user menu Career navigation link.',
|
||||
},
|
||||
newAlert: {
|
||||
id: 'header.menu.new.label',
|
||||
defaultMessage: 'New',
|
||||
description: 'The text announcing that an item in the user menu is New',
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LearnerDashboardHeaderVariant render 1`] = `
|
||||
<Fragment>
|
||||
<ConfirmEmailBanner />
|
||||
<CollapsedHeader />
|
||||
<ExpandedHeader />
|
||||
<MasqueradeBar />
|
||||
</Fragment>
|
||||
`;
|
||||
@@ -1,42 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useWindowSize, breakpoints } from '@edx/paragon';
|
||||
import track from 'tracking';
|
||||
import { StrictDict } from 'utils';
|
||||
import { linkNames } from 'tracking/constants';
|
||||
|
||||
import * as module from './hooks';
|
||||
|
||||
export const state = StrictDict({
|
||||
isOpen: (val) => React.useState(val), // eslint-disable-line
|
||||
});
|
||||
|
||||
export const useIsCollapsed = () => {
|
||||
const { width } = useWindowSize();
|
||||
const isCollapsed = React.useMemo(() => (width <= breakpoints.large.minWidth), [width]);
|
||||
return isCollapsed;
|
||||
};
|
||||
|
||||
export const findCoursesNavClicked = (href) => track.findCourses.findCoursesClicked(href, {
|
||||
linkName: linkNames.learnerHomeNavExplore,
|
||||
});
|
||||
|
||||
export const findCoursesNavDropdownClicked = (href) => track.findCourses.findCoursesClicked(href, {
|
||||
linkName: linkNames.learnerHomeNavDropdownExplore,
|
||||
});
|
||||
|
||||
export const useLearnerDashboardHeaderVariantData = () => {
|
||||
const [isOpen, setIsOpen] = module.state.isOpen(false);
|
||||
const toggleIsOpen = () => setIsOpen(!isOpen);
|
||||
|
||||
return {
|
||||
isOpen,
|
||||
toggleIsOpen,
|
||||
};
|
||||
};
|
||||
|
||||
export default {
|
||||
useIsCollapsed,
|
||||
findCoursesNavClicked,
|
||||
findCoursesNavDropdownClicked,
|
||||
useLearnerDashboardHeaderVariantData,
|
||||
};
|
||||
@@ -1,69 +0,0 @@
|
||||
import { useWindowSize, breakpoints } from '@edx/paragon';
|
||||
import track from 'tracking';
|
||||
import { linkNames } from 'tracking/constants';
|
||||
|
||||
import { MockUseState } from 'testUtils';
|
||||
|
||||
import * as hooks from './hooks';
|
||||
|
||||
const state = new MockUseState(hooks);
|
||||
|
||||
const {
|
||||
useIsCollapsed,
|
||||
findCoursesNavClicked,
|
||||
findCoursesNavDropdownClicked,
|
||||
useLearnerDashboardHeaderVariantData,
|
||||
} = hooks;
|
||||
|
||||
jest.mock('tracking', () => ({
|
||||
findCourses: {
|
||||
findCoursesClicked: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const url = 'http://example.com';
|
||||
|
||||
describe('LearnerDashboardHeaderVariant hooks', () => {
|
||||
describe('state values', () => {
|
||||
state.testGetter(state.keys.isOpen);
|
||||
});
|
||||
|
||||
describe('useIsCollapsed', () => {
|
||||
test('large screen is not collapsed', () => {
|
||||
useWindowSize.mockReturnValueOnce({ width: breakpoints.large.minWidth + 1 });
|
||||
expect(useIsCollapsed()).toEqual(false);
|
||||
});
|
||||
test('small screen is collapsed', () => {
|
||||
useWindowSize.mockReturnValueOnce({ width: breakpoints.large.minWidth - 1 });
|
||||
expect(useIsCollapsed()).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findCoursesNavClicked', () => {
|
||||
test('calls tracking with nav link name', () => {
|
||||
findCoursesNavClicked(url);
|
||||
expect(track.findCourses.findCoursesClicked).toHaveBeenCalledWith(url, {
|
||||
linkName: linkNames.learnerHomeNavExplore,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('findCoursesNavDropdownClicked', () => {
|
||||
test('calls tracking with dropdown link name', () => {
|
||||
findCoursesNavDropdownClicked(url);
|
||||
expect(track.findCourses.findCoursesClicked).toHaveBeenCalledWith(url, {
|
||||
linkName: linkNames.learnerHomeNavDropdownExplore,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('useLearnerDashboardHeaderVariantData', () => {
|
||||
test('default state', () => {
|
||||
state.mock();
|
||||
const out = useLearnerDashboardHeaderVariantData();
|
||||
state.expectInitializedWith(state.keys.isOpen, false);
|
||||
out.toggleIsOpen();
|
||||
expect(state.values.isOpen).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,22 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import MasqueradeBar from 'containers/MasqueradeBar';
|
||||
import ConfirmEmailBanner from 'containers/LearnerDashboardHeader/ConfirmEmailBanner';
|
||||
|
||||
import CollapsedHeader from './CollapsedHeader';
|
||||
import ExpandedHeader from './ExpandedHeader';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
export const LearnerDashboardHeaderVariant = () => (
|
||||
<>
|
||||
<ConfirmEmailBanner />
|
||||
<CollapsedHeader />
|
||||
<ExpandedHeader />
|
||||
<MasqueradeBar />
|
||||
</>
|
||||
);
|
||||
|
||||
LearnerDashboardHeaderVariant.propTypes = {};
|
||||
|
||||
export default LearnerDashboardHeaderVariant;
|
||||
@@ -1,38 +0,0 @@
|
||||
.dropdown-menu-collapse {
|
||||
width: 100vw;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.learner-variant-header {
|
||||
a {
|
||||
// needed to make the link not resize the header
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
.course-link {
|
||||
border-bottom: 2px solid !important;
|
||||
}
|
||||
|
||||
.course-link:hover {
|
||||
border-bottom: inherit !important;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-small-menu {
|
||||
> * {
|
||||
justify-content: flex-start !important;
|
||||
|
||||
border-radius: 0 !important;
|
||||
border-top: 1px solid #ddd !important;
|
||||
|
||||
&::after {
|
||||
content: '\00BB';
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
// copy from legacy dashboard
|
||||
height: 40px;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { shallow } from 'enzyme';
|
||||
import LearnerDashboardHeaderVariant from '.';
|
||||
|
||||
jest.mock('containers/LearnerDashboardHeader/ConfirmEmailBanner', () => 'ConfirmEmailBanner');
|
||||
jest.mock('containers/MasqueradeBar', () => 'MasqueradeBar');
|
||||
jest.mock('./CollapsedHeader', () => 'CollapsedHeader');
|
||||
jest.mock('./ExpandedHeader', () => 'ExpandedHeader');
|
||||
|
||||
describe('LearnerDashboardHeaderVariant', () => {
|
||||
test('render', () => {
|
||||
const wrapper = shallow(<LearnerDashboardHeaderVariant />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.find('ConfirmEmailBanner')).toHaveLength(1);
|
||||
expect(wrapper.find('MasqueradeBar')).toHaveLength(1);
|
||||
expect(wrapper.find('CollapsedHeader')).toHaveLength(1);
|
||||
expect(wrapper.find('ExpandedHeader')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -1,71 +0,0 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
dashboard: {
|
||||
id: 'learnerVariantDashboard.menu.dashboard.label',
|
||||
defaultMessage: 'Dashboard',
|
||||
description: 'The text for the user menu Dashboard navigation link.',
|
||||
},
|
||||
help: {
|
||||
id: 'learnerVariantDashboard.help.label',
|
||||
defaultMessage: 'Help',
|
||||
description: 'The text for the link to the Help Center',
|
||||
},
|
||||
profile: {
|
||||
id: 'learnerVariantDashboard.menu.profile.label',
|
||||
defaultMessage: 'Profile',
|
||||
description: 'The text for the user menu Profile navigation link.',
|
||||
},
|
||||
viewPrograms: {
|
||||
id: 'learnerVariantDashboard.menu.viewPrograms.label',
|
||||
defaultMessage: 'View Programs',
|
||||
description: 'The text for the user menu View Programs navigation link.',
|
||||
},
|
||||
account: {
|
||||
id: 'learnerVariantDashboard.menu.account.label',
|
||||
defaultMessage: 'Account',
|
||||
description: 'The text for the user menu Account navigation link.',
|
||||
},
|
||||
orderHistory: {
|
||||
id: 'learnerVariantDashboard.menu.orderHistory.label',
|
||||
defaultMessage: 'Order History',
|
||||
description: 'The text for the user menu Order History navigation link.',
|
||||
},
|
||||
signOut: {
|
||||
id: 'learnerVariantDashboard.menu.signOut.label',
|
||||
defaultMessage: 'Sign Out',
|
||||
description: 'The label for the user menu Sign Out action.',
|
||||
},
|
||||
course: {
|
||||
id: 'learnerVariantDashboard.course',
|
||||
defaultMessage: 'Courses',
|
||||
description: 'Header link for switching to dashboard page.',
|
||||
},
|
||||
program: {
|
||||
id: 'learnerVariantDashboard.program',
|
||||
defaultMessage: 'Programs',
|
||||
description: 'Header link for switching to program page.',
|
||||
},
|
||||
discoverNew: {
|
||||
id: 'learnerVariantDashboard.discoverNew',
|
||||
defaultMessage: 'Discover New',
|
||||
description: 'Header link for switching to discover page.',
|
||||
},
|
||||
logoAltText: {
|
||||
id: 'learnerVariantDashboard.logoAltText',
|
||||
defaultMessage: 'edX, Inc. Dashboard',
|
||||
description: 'Alt text for the edX logo.',
|
||||
},
|
||||
collapseMenuOpenAltText: {
|
||||
id: 'learnerVariantDashboard.collapseMenuOpenAltText',
|
||||
defaultMessage: 'Menu',
|
||||
description: 'Alt text for the collapse menu icon when the menu is open.',
|
||||
},
|
||||
collapseMenuClosedAltText: {
|
||||
id: 'learnerVariantDashboard.collapseMenuClosedAltText',
|
||||
defaultMessage: 'Close',
|
||||
description: 'Alt text for the collapse menu icon when the menu is closed.',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
Reference in New Issue
Block a user