header component (#101)
* chore: use LearningHeader instead course header * chore: remove course header debris
This commit is contained in:
62
package-lock.json
generated
62
package-lock.json
generated
@@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@edx/brand": "npm:@edx/brand-edx.org@^2.0.3",
|
||||
"@edx/frontend-component-footer": "10.1.6",
|
||||
"@edx/frontend-component-header": "^2.4.6",
|
||||
"@edx/frontend-platform": "^1.15.6",
|
||||
"@edx/paragon": "16.14.4",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
||||
@@ -3521,6 +3522,28 @@
|
||||
"react": ">=16.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header": {
|
||||
"version": "2.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-2.4.6.tgz",
|
||||
"integrity": "sha512-bwEP3B37N4lIDPM4cz/Dg1egQHWf14qj+3VU44BOf5DC/bNhASKeeEJEvDn6XTZdFCpGioHRBtqlEJQJsp0WqA==",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
||||
"@fortawesome/free-brands-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-regular-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "5.15.4",
|
||||
"@fortawesome/react-fontawesome": "^0.1.14",
|
||||
"babel-polyfill": "6.26.0",
|
||||
"react-responsive": "8.2.0",
|
||||
"react-transition-group": "4.4.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@edx/frontend-platform": "^1.8.0",
|
||||
"@edx/paragon": ">= 7.0.0 < 20.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^16.9.0",
|
||||
"react-dom": "^16.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-platform": {
|
||||
"version": "1.15.6",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-1.15.6.tgz",
|
||||
@@ -8514,7 +8537,6 @@
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
|
||||
"integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"babel-runtime": "^6.26.0",
|
||||
"core-js": "^2.5.0",
|
||||
@@ -8526,14 +8548,12 @@
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
|
||||
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
|
||||
"deprecated": "core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.",
|
||||
"dev": true,
|
||||
"hasInstallScript": true
|
||||
},
|
||||
"node_modules/babel-polyfill/node_modules/regenerator-runtime": {
|
||||
"version": "0.10.5",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
|
||||
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
|
||||
"dev": true
|
||||
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
|
||||
},
|
||||
"node_modules/babel-preset-current-node-syntax": {
|
||||
"version": "1.0.1",
|
||||
@@ -8578,7 +8598,6 @@
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
|
||||
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"core-js": "^2.4.0",
|
||||
"regenerator-runtime": "^0.11.0"
|
||||
@@ -8589,14 +8608,12 @@
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
|
||||
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
|
||||
"deprecated": "core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.",
|
||||
"dev": true,
|
||||
"hasInstallScript": true
|
||||
},
|
||||
"node_modules/babel-runtime/node_modules/regenerator-runtime": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
|
||||
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
@@ -36088,6 +36105,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@edx/frontend-component-header": {
|
||||
"version": "2.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-2.4.6.tgz",
|
||||
"integrity": "sha512-bwEP3B37N4lIDPM4cz/Dg1egQHWf14qj+3VU44BOf5DC/bNhASKeeEJEvDn6XTZdFCpGioHRBtqlEJQJsp0WqA==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
||||
"@fortawesome/free-brands-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-regular-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "5.15.4",
|
||||
"@fortawesome/react-fontawesome": "^0.1.14",
|
||||
"babel-polyfill": "6.26.0",
|
||||
"react-responsive": "8.2.0",
|
||||
"react-transition-group": "4.4.2"
|
||||
}
|
||||
},
|
||||
"@edx/frontend-platform": {
|
||||
"version": "1.15.6",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-1.15.6.tgz",
|
||||
@@ -39986,7 +40018,6 @@
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
|
||||
"integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-runtime": "^6.26.0",
|
||||
"core-js": "^2.5.0",
|
||||
@@ -39996,14 +40027,12 @@
|
||||
"core-js": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
|
||||
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.10.5",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
|
||||
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
|
||||
"dev": true
|
||||
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -40041,7 +40070,6 @@
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
|
||||
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-js": "^2.4.0",
|
||||
"regenerator-runtime": "^0.11.0"
|
||||
@@ -40050,14 +40078,12 @@
|
||||
"core-js": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
|
||||
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
|
||||
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"dependencies": {
|
||||
"@edx/brand": "npm:@edx/brand-edx.org@^2.0.3",
|
||||
"@edx/frontend-component-footer": "10.1.6",
|
||||
"@edx/frontend-component-header": "^2.4.6",
|
||||
"@edx/frontend-platform": "^1.15.6",
|
||||
"@edx/paragon": "16.14.4",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
||||
|
||||
@@ -4,11 +4,11 @@ import { connect } from 'react-redux';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
|
||||
import Footer from '@edx/frontend-component-footer';
|
||||
import { LearningHeader as Header } from '@edx/frontend-component-header';
|
||||
|
||||
import { selectors } from 'data/redux';
|
||||
|
||||
import DemoWarning from 'containers/DemoWarning';
|
||||
import CourseHeader from 'containers/CourseHeader';
|
||||
import ListView from 'containers/ListView';
|
||||
|
||||
import './App.scss';
|
||||
@@ -16,7 +16,7 @@ import './App.scss';
|
||||
export const App = ({ courseMetadata, isEnabled }) => (
|
||||
<Router>
|
||||
<div>
|
||||
<CourseHeader
|
||||
<Header
|
||||
courseTitle={courseMetadata.title}
|
||||
courseNumber={courseMetadata.number}
|
||||
courseOrg={courseMetadata.org}
|
||||
|
||||
26
src/App.scss
26
src/App.scss
@@ -42,32 +42,6 @@ $input-focus-box-shadow: $input-box-shadow; // hack to get upgrade to paragon 4.
|
||||
}
|
||||
}
|
||||
|
||||
.course-header {
|
||||
min-width: 0;
|
||||
border-bottom: 1px solid black;
|
||||
|
||||
.course-title-lockup {
|
||||
min-width: 0;
|
||||
|
||||
span {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-bottom: 0.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.user-dropdown {
|
||||
.btn {
|
||||
height: 3rem;
|
||||
@media (max-width: -1 + map-get($grid-breakpoints, "sm")) {
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#paragon-portal-root {
|
||||
.pgn__modal-layer {
|
||||
.pgn__modal-close-container {
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import Footer from '@edx/frontend-component-footer';
|
||||
import { LearningHeader as Header } from '@edx/frontend-component-header';
|
||||
|
||||
import ListView from 'containers/ListView';
|
||||
|
||||
@@ -16,11 +17,13 @@ jest.mock('data/redux', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('@edx/frontend-component-header', () => ({
|
||||
LearningHeader: 'Header',
|
||||
}));
|
||||
jest.mock('@edx/frontend-component-footer', () => 'Footer');
|
||||
|
||||
jest.mock('containers/DemoWarning', () => 'DemoWarning');
|
||||
jest.mock('containers/ListView', () => 'ListView');
|
||||
jest.mock('containers/CourseHeader', () => 'CourseHeader');
|
||||
|
||||
const logo = 'fakeLogo.png';
|
||||
let el;
|
||||
@@ -57,5 +60,16 @@ describe('App router component', () => {
|
||||
test('Footer logo drawn from env variable', () => {
|
||||
expect(router.find(Footer).props().logo).toEqual(logo);
|
||||
});
|
||||
|
||||
test('Header to use courseMetadata props', () => {
|
||||
const {
|
||||
courseTitle,
|
||||
courseNumber,
|
||||
courseOrg,
|
||||
} = router.find(Header).props();
|
||||
expect(courseTitle).toEqual(props.courseMetadata.title);
|
||||
expect(courseNumber).toEqual(props.courseMetadata.number);
|
||||
expect(courseOrg).toEqual(props.courseMetadata.org);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
exports[`App router component snapshot: disabled (show demo warning) 1`] = `
|
||||
<BrowserRouter>
|
||||
<div>
|
||||
<CourseHeader
|
||||
<Header
|
||||
courseNumber="course-number"
|
||||
courseOrg="course-org"
|
||||
courseTitle="course-title"
|
||||
@@ -22,7 +22,7 @@ exports[`App router component snapshot: disabled (show demo warning) 1`] = `
|
||||
exports[`App router component snapshot: enabled 1`] = `
|
||||
<BrowserRouter>
|
||||
<div>
|
||||
<CourseHeader
|
||||
<Header
|
||||
courseNumber="course-number"
|
||||
courseOrg="course-org"
|
||||
courseTitle="course-title"
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { getLoginRedirectUrl } from '@edx/frontend-platform/auth';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Button } from '@edx/paragon';
|
||||
|
||||
import message from './messages';
|
||||
|
||||
export const getRegisterUrl = () => {
|
||||
const { LMS_BASE_URL } = getConfig();
|
||||
const locationHref = encodeURIComponent(global.location.href);
|
||||
return `${LMS_BASE_URL}/register?next=${locationHref}`;
|
||||
};
|
||||
|
||||
export const AnonymousUserMenu = ({ intl }) => (
|
||||
<div>
|
||||
<Button
|
||||
className="mr-3"
|
||||
variant="outline-primary"
|
||||
href={getRegisterUrl()}
|
||||
>
|
||||
{intl.formatMessage(message.registerSentenceCase)}
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
href={`${getLoginRedirectUrl(global.location.href)}`}
|
||||
>
|
||||
{intl.formatMessage(message.signInSentenceCase)}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
AnonymousUserMenu.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(AnonymousUserMenu);
|
||||
@@ -1,24 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { AnonymousUserMenu } from './AnonymousUserMenu';
|
||||
|
||||
jest.mock('@edx/frontend-platform', () => ({
|
||||
getConfig: () => ({
|
||||
LMS_BASE_URL: '<LMS_BASE_URL>',
|
||||
}),
|
||||
}));
|
||||
jest.mock('@edx/frontend-platform/auth', () => ({
|
||||
getLoginRedirectUrl: (url) => `redirect:${url}`,
|
||||
}));
|
||||
|
||||
describe('Header AnonymousUserMenu component', () => {
|
||||
const props = {
|
||||
intl: { formatMessage: (msg) => msg.defaultMessage },
|
||||
};
|
||||
test('snapshot', () => {
|
||||
expect(
|
||||
shallow(<AnonymousUserMenu {...props} />),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faUserCircle } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import { Dropdown } from '@edx/paragon';
|
||||
|
||||
export const UserAvatar = ({ username }) => (
|
||||
<Dropdown.Toggle variant="outline-primary">
|
||||
<FontAwesomeIcon
|
||||
icon={faUserCircle}
|
||||
className="d-md-none"
|
||||
size="lg"
|
||||
/>
|
||||
<span data-hj-suppress className="d-none d-md-inline">
|
||||
{username}
|
||||
</span>
|
||||
</Dropdown.Toggle>
|
||||
);
|
||||
UserAvatar.propTypes = {
|
||||
username: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
UserAvatar.defaultProps = {};
|
||||
|
||||
export default UserAvatar;
|
||||
@@ -1,23 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import UserAvatar from './UserAvatar';
|
||||
|
||||
jest.mock('@edx/frontend-platform', () => ({
|
||||
getConfig: () => ({
|
||||
LMS_BASE_URL: '<LMS_BASE_URL>',
|
||||
LOGOUT_URL: '<LOGOUT_URL>',
|
||||
SUPPORT_URL: '<SUPPORT_URL>',
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('Header AuthenticatedUserDropdown UserAvatar component', () => {
|
||||
const props = {
|
||||
username: 'test-username',
|
||||
};
|
||||
test('snapshot', () => {
|
||||
expect(
|
||||
shallow(<UserAvatar {...props} />),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,40 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Dropdown } from '@edx/paragon';
|
||||
|
||||
import messages from '../messages';
|
||||
|
||||
export class UserMenu extends React.Component {
|
||||
menuItem(href, message) {
|
||||
return (
|
||||
<Dropdown.Item href={href}>
|
||||
{this.props.intl.formatMessage(message)}
|
||||
</Dropdown.Item>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { username } = this.props;
|
||||
const { LMS_BASE_URL, LOGOUT_URL } = getConfig();
|
||||
return (
|
||||
<Dropdown.Menu className="dropdown-menu-right">
|
||||
{this.menuItem(`${LMS_BASE_URL}/dashboard`, messages.dashboard)}
|
||||
{this.menuItem(`${LMS_BASE_URL}/u/${username}`, messages.profile)}
|
||||
{this.menuItem(`${LMS_BASE_URL}/account/settings`, messages.account)}
|
||||
{this.menuItem(LOGOUT_URL, messages.signOut)}
|
||||
</Dropdown.Menu>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
UserMenu.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
username: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
UserMenu.defaultProps = {};
|
||||
|
||||
export default injectIntl(UserMenu);
|
||||
@@ -1,24 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { UserMenu } from './UserMenu';
|
||||
|
||||
jest.mock('@edx/frontend-platform', () => ({
|
||||
getConfig: () => ({
|
||||
LMS_BASE_URL: '<LMS_BASE_URL>',
|
||||
LOGOUT_URL: '<LOGOUT_URL>',
|
||||
SUPPORT_URL: '<SUPPORT_URL>',
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('Header AuthenticatedUserDropdown UserMenu component', () => {
|
||||
const props = {
|
||||
intl: { formatMessage: (msg) => msg.defaultMessage },
|
||||
username: 'test-username',
|
||||
};
|
||||
test('snapshot', () => {
|
||||
expect(
|
||||
shallow(<UserMenu {...props} />),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,31 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Header AuthenticatedUserDropdown UserAvatar component snapshot 1`] = `
|
||||
<Dropdown.Toggle
|
||||
variant="outline-primary"
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
className="d-md-none"
|
||||
icon={
|
||||
Object {
|
||||
"icon": Array [
|
||||
496,
|
||||
512,
|
||||
Array [],
|
||||
"f2bd",
|
||||
"M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 96c48.6 0 88 39.4 88 88s-39.4 88-88 88-88-39.4-88-88 39.4-88 88-88zm0 344c-58.7 0-111.3-26.6-146.5-68.2 18.8-35.4 55.6-59.8 98.5-59.8 2.4 0 4.8.4 7.1 1.1 13 4.2 26.6 6.9 40.9 6.9 14.3 0 28-2.7 40.9-6.9 2.3-.7 4.7-1.1 7.1-1.1 42.9 0 79.7 24.4 98.5 59.8C359.3 421.4 306.7 448 248 448z",
|
||||
],
|
||||
"iconName": "user-circle",
|
||||
"prefix": "fas",
|
||||
}
|
||||
}
|
||||
size="lg"
|
||||
/>
|
||||
<span
|
||||
className="d-none d-md-inline"
|
||||
data-hj-suppress={true}
|
||||
>
|
||||
test-username
|
||||
</span>
|
||||
</Dropdown.Toggle>
|
||||
`;
|
||||
@@ -1,28 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Header AuthenticatedUserDropdown UserMenu component snapshot 1`] = `
|
||||
<Dropdown.Menu
|
||||
className="dropdown-menu-right"
|
||||
>
|
||||
<Dropdown.Item
|
||||
href="<LMS_BASE_URL>/dashboard"
|
||||
>
|
||||
Dashboard
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="<LMS_BASE_URL>/u/test-username"
|
||||
>
|
||||
Profile
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="<LMS_BASE_URL>/account/settings"
|
||||
>
|
||||
Account
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="<LOGOUT_URL>"
|
||||
>
|
||||
Sign Out
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Menu>
|
||||
`;
|
||||
@@ -1,22 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Header AuthenticatedUserDropdown component snapshot 1`] = `
|
||||
<Fragment>
|
||||
<a
|
||||
className="text-gray-700 mr-3"
|
||||
href="<SUPPORT_URL>"
|
||||
>
|
||||
Help
|
||||
</a>
|
||||
<Dropdown
|
||||
className="user-dropdown"
|
||||
>
|
||||
<UserAvatar
|
||||
username="test-username"
|
||||
/>
|
||||
<UserMenu
|
||||
username="test-username"
|
||||
/>
|
||||
</Dropdown>
|
||||
</Fragment>
|
||||
`;
|
||||
@@ -1,35 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Dropdown } from '@edx/paragon';
|
||||
|
||||
import UserMenu from './UserMenu';
|
||||
import UserAvatar from './UserAvatar';
|
||||
|
||||
import messages from '../messages';
|
||||
|
||||
export const AuthenticatedUserDropdown = ({
|
||||
intl,
|
||||
username,
|
||||
}) => (
|
||||
<>
|
||||
<a className="text-gray-700 mr-3" href={`${getConfig().SUPPORT_URL}`}>
|
||||
{intl.formatMessage(messages.help)}
|
||||
</a>
|
||||
<Dropdown className="user-dropdown">
|
||||
<UserAvatar username={username} />
|
||||
<UserMenu username={username} />
|
||||
</Dropdown>
|
||||
</>
|
||||
);
|
||||
|
||||
AuthenticatedUserDropdown.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
username: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
AuthenticatedUserDropdown.defaultProps = {};
|
||||
|
||||
export default injectIntl(AuthenticatedUserDropdown);
|
||||
@@ -1,24 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { AuthenticatedUserDropdown } from '.';
|
||||
|
||||
jest.mock('@edx/frontend-platform', () => ({
|
||||
getConfig: () => ({
|
||||
SUPPORT_URL: '<SUPPORT_URL>',
|
||||
}),
|
||||
}));
|
||||
jest.mock('./UserAvatar', () => 'UserAvatar');
|
||||
jest.mock('./UserMenu', () => 'UserMenu');
|
||||
|
||||
describe('Header AuthenticatedUserDropdown component', () => {
|
||||
const props = {
|
||||
intl: { formatMessage: (msg) => msg.defaultMessage },
|
||||
username: 'test-username',
|
||||
};
|
||||
test('snapshot', () => {
|
||||
expect(
|
||||
shallow(<AuthenticatedUserDropdown {...props} />),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,32 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export const CourseLabel = ({
|
||||
courseOrg,
|
||||
courseNumber,
|
||||
courseTitle,
|
||||
}) => (
|
||||
<div
|
||||
className="flex-grow-1 course-title-lockup"
|
||||
style={{ lineHeight: 1 }}
|
||||
>
|
||||
<span className="d-block small m-0">
|
||||
{courseOrg} {courseNumber}
|
||||
</span>
|
||||
<span className="d-block m-0 font-weight-bold course-title">
|
||||
{courseTitle}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
CourseLabel.propTypes = {
|
||||
courseOrg: PropTypes.string,
|
||||
courseNumber: PropTypes.string,
|
||||
courseTitle: PropTypes.string,
|
||||
};
|
||||
CourseLabel.defaultProps = {
|
||||
courseOrg: null,
|
||||
courseNumber: null,
|
||||
courseTitle: null,
|
||||
};
|
||||
|
||||
export default CourseLabel;
|
||||
@@ -1,18 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import CourseLabel from './CourseLabel';
|
||||
|
||||
const courseData = {
|
||||
courseOrg: 'course-org',
|
||||
courseNumber: 'course-number',
|
||||
courseTitle: 'course-title',
|
||||
};
|
||||
|
||||
describe('Header CourseLabel component', () => {
|
||||
test('snapshot', () => {
|
||||
expect(
|
||||
shallow(<CourseLabel {...courseData} />),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
import React from 'react';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
const LinkedLogo = () => (
|
||||
<a
|
||||
className="logo"
|
||||
href={`${getConfig().LMS_BASE_URL}/dashboard`}
|
||||
>
|
||||
<img
|
||||
className="d-block"
|
||||
src={getConfig().LOGO_URL}
|
||||
alt={getConfig().SITE_NAME}
|
||||
/>
|
||||
</a>
|
||||
);
|
||||
|
||||
export default LinkedLogo;
|
||||
@@ -1,20 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import LinkedLogo from './LinkedLogo';
|
||||
|
||||
jest.mock('@edx/frontend-platform', () => ({
|
||||
getConfig: () => ({
|
||||
LMS_BASE_URL: '<getConfig().LMS_BASE_URL>',
|
||||
LOGO_URL: '<getConfig().LOGO_URL>',
|
||||
SITE_NAME: '<getConfig().SITE_NAME>',
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('Header CourseLabel component', () => {
|
||||
test('snapshot', () => {
|
||||
expect(
|
||||
shallow(<LinkedLogo />),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Header AnonymousUserMenu component snapshot 1`] = `
|
||||
<div>
|
||||
<Button
|
||||
className="mr-3"
|
||||
href="<LMS_BASE_URL>/register?next=http%3A%2F%2Flocalhost%2F"
|
||||
variant="outline-primary"
|
||||
>
|
||||
Register
|
||||
</Button>
|
||||
<Button
|
||||
href="redirect:http://localhost/"
|
||||
variant="primary"
|
||||
>
|
||||
Sign in
|
||||
</Button>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,25 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Header CourseLabel component snapshot 1`] = `
|
||||
<div
|
||||
className="flex-grow-1 course-title-lockup"
|
||||
style={
|
||||
Object {
|
||||
"lineHeight": 1,
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="d-block small m-0"
|
||||
>
|
||||
course-org
|
||||
|
||||
course-number
|
||||
</span>
|
||||
<span
|
||||
className="d-block m-0 font-weight-bold course-title"
|
||||
>
|
||||
course-title
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,14 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Header CourseLabel component snapshot 1`] = `
|
||||
<a
|
||||
className="logo"
|
||||
href="<getConfig().LMS_BASE_URL>/dashboard"
|
||||
>
|
||||
<img
|
||||
alt="<getConfig().SITE_NAME>"
|
||||
className="d-block"
|
||||
src="<getConfig().LOGO_URL>"
|
||||
/>
|
||||
</a>
|
||||
`;
|
||||
@@ -1,51 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Header component snapshot 1`] = `
|
||||
<header
|
||||
className="course-header"
|
||||
>
|
||||
<a
|
||||
className="sr-only sr-only-focusable"
|
||||
href="#main-content"
|
||||
>
|
||||
Skip to main content.
|
||||
</a>
|
||||
<div
|
||||
className="container-xl py-2 d-flex align-items-center"
|
||||
>
|
||||
<LinkedLogo />
|
||||
<CourseLabel
|
||||
courseNumber="course-number"
|
||||
courseOrg="course-org"
|
||||
courseTitle="course-title"
|
||||
/>
|
||||
<AnonymousUserMenu />
|
||||
</div>
|
||||
</header>
|
||||
`;
|
||||
|
||||
exports[`Header component snapshot with authenticatedUser 1`] = `
|
||||
<header
|
||||
className="course-header"
|
||||
>
|
||||
<a
|
||||
className="sr-only sr-only-focusable"
|
||||
href="#main-content"
|
||||
>
|
||||
Skip to main content.
|
||||
</a>
|
||||
<div
|
||||
className="container-xl py-2 d-flex align-items-center"
|
||||
>
|
||||
<LinkedLogo />
|
||||
<CourseLabel
|
||||
courseNumber="course-number"
|
||||
courseOrg="course-org"
|
||||
courseTitle="course-title"
|
||||
/>
|
||||
<AuthenticatedUserDropdown
|
||||
username="test"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
`;
|
||||
@@ -1,47 +0,0 @@
|
||||
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 AnonymousUserMenu from './AnonymousUserMenu';
|
||||
import AuthenticatedUserDropdown from './AuthenticatedUserDropdown';
|
||||
import LinkedLogo from './LinkedLogo';
|
||||
import CourseLabel from './CourseLabel';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
export const Header = ({
|
||||
courseOrg,
|
||||
courseNumber,
|
||||
courseTitle,
|
||||
intl,
|
||||
}) => {
|
||||
const { authenticatedUser } = useContext(AppContext);
|
||||
return (
|
||||
<header className="course-header">
|
||||
<a className="sr-only sr-only-focusable" href="#main-content">
|
||||
{intl.formatMessage(messages.skipNavLink)}
|
||||
</a>
|
||||
<div className="container-xl py-2 d-flex align-items-center">
|
||||
<LinkedLogo />
|
||||
<CourseLabel {...{ courseOrg, courseNumber, courseTitle }} />
|
||||
{authenticatedUser
|
||||
? (<AuthenticatedUserDropdown username={authenticatedUser.username} />)
|
||||
: (<AnonymousUserMenu />)}
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
Header.propTypes = {
|
||||
courseOrg: PropTypes.string,
|
||||
courseNumber: PropTypes.string,
|
||||
courseTitle: PropTypes.string,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
Header.defaultProps = {
|
||||
courseOrg: null,
|
||||
courseNumber: null,
|
||||
courseTitle: null,
|
||||
};
|
||||
|
||||
export default injectIntl(Header);
|
||||
@@ -1,38 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { AppContext } from '@edx/frontend-platform/react';
|
||||
import { Header } from '.';
|
||||
|
||||
jest.mock('./AnonymousUserMenu', () => 'AnonymousUserMenu');
|
||||
jest.mock('./AuthenticatedUserDropdown', () => 'AuthenticatedUserDropdown');
|
||||
jest.mock('./LinkedLogo', () => 'LinkedLogo');
|
||||
jest.mock('./CourseLabel', () => 'CourseLabel');
|
||||
|
||||
jest.mock('@edx/frontend-platform/react', () => ({
|
||||
AppContext: { authenticatedUser: null },
|
||||
}));
|
||||
jest.mock('react', () => ({
|
||||
...jest.requireActual('react'),
|
||||
useContext: (context) => context,
|
||||
}));
|
||||
|
||||
const courseData = {
|
||||
courseOrg: 'course-org',
|
||||
courseNumber: 'course-number',
|
||||
courseTitle: 'course-title',
|
||||
};
|
||||
|
||||
describe('Header component', () => {
|
||||
const props = {
|
||||
...courseData,
|
||||
intl: { formatMessage: (msg) => msg.defaultMessage },
|
||||
};
|
||||
test('snapshot', () => {
|
||||
expect(shallow(<Header {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
test('snapshot with authenticatedUser', () => {
|
||||
AppContext.authenticatedUser = { username: 'test' };
|
||||
expect(shallow(<Header {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,56 +0,0 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
courseMaterial: {
|
||||
id: 'learn.navigation.course.tabs.label',
|
||||
defaultMessage: 'Course Material',
|
||||
description: 'The accessible label for course tabs navigation',
|
||||
},
|
||||
dashboard: {
|
||||
id: 'header.menu.dashboard.label',
|
||||
defaultMessage: 'Dashboard',
|
||||
description: 'The text for the user menu Dashboard navigation link.',
|
||||
},
|
||||
help: {
|
||||
id: 'header.help.label',
|
||||
defaultMessage: 'Help',
|
||||
description: 'The text for the link to the Help Center',
|
||||
},
|
||||
profile: {
|
||||
id: 'header.menu.profile.label',
|
||||
defaultMessage: 'Profile',
|
||||
description: 'The text for the user menu Profile navigation link.',
|
||||
},
|
||||
account: {
|
||||
id: 'header.menu.account.label',
|
||||
defaultMessage: 'Account',
|
||||
description: 'The text for the user menu Account navigation link.',
|
||||
},
|
||||
orderHistory: {
|
||||
id: 'header.menu.orderHistory.label',
|
||||
defaultMessage: 'Order History',
|
||||
description: 'The text for the user menu Order History navigation link.',
|
||||
},
|
||||
skipNavLink: {
|
||||
id: 'header.navigation.skipNavLink',
|
||||
defaultMessage: 'Skip to main content.',
|
||||
description: 'A link used by screen readers to allow users to skip to the main content of the page.',
|
||||
},
|
||||
signOut: {
|
||||
id: 'header.menu.signOut.label',
|
||||
defaultMessage: 'Sign Out',
|
||||
description: 'The label for the user menu Sign Out action.',
|
||||
},
|
||||
registerSentenceCase: {
|
||||
id: 'header.register.sentenceCase',
|
||||
defaultMessage: 'Register',
|
||||
description: 'Text in a button, prompting the user to register.',
|
||||
},
|
||||
signInSentenceCase: {
|
||||
id: 'header.signIn.sentenceCase',
|
||||
defaultMessage: 'Sign in',
|
||||
description: 'Text in a button, prompting the user to log in.',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -11,8 +11,12 @@ import {
|
||||
APP_INIT_ERROR,
|
||||
initialize,
|
||||
subscribe,
|
||||
mergeConfig,
|
||||
} from '@edx/frontend-platform';
|
||||
|
||||
import { messages as footerMessages } from '@edx/frontend-component-footer';
|
||||
import { messages as headerMesssages } from '@edx/frontend-component-header';
|
||||
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import messages from './i18n';
|
||||
@@ -38,8 +42,16 @@ subscribe(APP_INIT_ERROR, (error) => {
|
||||
});
|
||||
|
||||
initialize({
|
||||
handlers: {
|
||||
config: () => {
|
||||
mergeConfig({
|
||||
SUPPORT_URL: process.env.SUPPORT_URL || null,
|
||||
}, 'OraGradingAppConfig');
|
||||
},
|
||||
},
|
||||
messages: [
|
||||
messages,
|
||||
headerMesssages,
|
||||
footerMessages,
|
||||
],
|
||||
requireAuthenticatedUser: true,
|
||||
|
||||
@@ -6,7 +6,9 @@ import {
|
||||
initialize,
|
||||
subscribe,
|
||||
} from '@edx/frontend-platform';
|
||||
|
||||
import { messages as footerMessages } from '@edx/frontend-component-footer';
|
||||
import { messages as headerMesssages } from '@edx/frontend-component-header';
|
||||
|
||||
import appMessages from './i18n';
|
||||
import App from './App';
|
||||
@@ -36,17 +38,18 @@ describe('app registry', () => {
|
||||
afterAll(() => {
|
||||
window.document.getElementById = getElement;
|
||||
});
|
||||
|
||||
test('subscribe is called for APP_READY, linking App to root element', () => {
|
||||
const callArgs = subscribe.mock.calls[0];
|
||||
const callArgs = subscribe.mock.calls[1];
|
||||
expect(callArgs[0]).toEqual(APP_READY);
|
||||
expect(callArgs[1]()).toEqual(
|
||||
ReactDOM.render(<App />, document.getElementById('root')),
|
||||
);
|
||||
});
|
||||
test('initialize is called with footerMessages and requireAuthenticatedUser', () => {
|
||||
expect(initialize).toHaveBeenCalledWith({
|
||||
messages: [appMessages, footerMessages],
|
||||
requireAuthenticatedUser: true,
|
||||
});
|
||||
expect(initialize).toHaveBeenCalledTimes(1);
|
||||
const initializeArg = initialize.mock.calls[0][0];
|
||||
expect(initializeArg.messages).toEqual([appMessages, headerMesssages, footerMessages]);
|
||||
expect(initializeArg.requireAuthenticatedUser).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import InfoPopover from 'components/InfoPopover/messages';
|
||||
import ResponseDisplay from 'containers/ResponseDisplay/messages';
|
||||
import ResponseDisplayComponents from 'containers/ResponseDisplay/components/messages';
|
||||
import CourseHeader from 'containers/CourseHeader/messages';
|
||||
import CriterionContainer from 'containers/CriterionContainer/messages';
|
||||
import ListView from 'containers/ListView/messages';
|
||||
import ReviewActions from 'containers/ReviewActions/messages';
|
||||
@@ -20,7 +19,6 @@ export default {
|
||||
InfoPopover: mapMessages(InfoPopover),
|
||||
ResponseDisplay: mapMessages(ResponseDisplay),
|
||||
ResponseDisplayComponents: mapMessages(ResponseDisplayComponents),
|
||||
CourseHeader: mapMessages(CourseHeader),
|
||||
CriterionContainer: mapMessages(CriterionContainer),
|
||||
ListView: mapMessages(ListView),
|
||||
ReviewActions: mapMessages(ReviewActions),
|
||||
|
||||
Reference in New Issue
Block a user