diff --git a/package-lock.json b/package-lock.json index 307b02fcd..1e6d1f874 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,8 @@ "classnames": "^2.5.1", "jest-environment-jsdom": "^29.7.0", "react-responsive": "8.2.0", - "react-transition-group": "4.4.5" + "react-transition-group": "4.4.5", + "universal-cookie": "^7.2.0" }, "devDependencies": { "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", @@ -2089,6 +2090,12 @@ "redux": "^4.0.4" } }, + "node_modules/@edx/frontend-platform/node_modules/@types/cookie": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz", + "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==", + "dev": true + }, "node_modules/@edx/frontend-platform/node_modules/axios": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", @@ -2100,6 +2107,25 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/@edx/frontend-platform/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@edx/frontend-platform/node_modules/universal-cookie": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz", + "integrity": "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==", + "dev": true, + "dependencies": { + "@types/cookie": "^0.3.3", + "cookie": "^0.4.0" + } + }, "node_modules/@edx/new-relic-source-map-webpack-plugin": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@edx/new-relic-source-map-webpack-plugin/-/new-relic-source-map-webpack-plugin-2.1.0.tgz", @@ -4107,9 +4133,9 @@ } }, "node_modules/@types/cookie": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz", - "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" }, "node_modules/@types/eslint": { "version": "8.56.12", @@ -16490,22 +16516,12 @@ "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz", "integrity": "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==", "dependencies": { - "@types/cookie": "^0.3.3", - "cookie": "^0.4.0" - } - }, - "node_modules/universal-cookie/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "engines": { - "node": ">= 0.6" + "@types/cookie": "^0.3.3" } }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "engines": { "node": ">= 10.0.0" } diff --git a/package.json b/package.json index 16c061ee2..dad87f3e5 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,8 @@ "classnames": "^2.5.1", "jest-environment-jsdom": "^29.7.0", "react-responsive": "8.2.0", - "react-transition-group": "4.4.5" + "react-transition-group": "4.4.5", + "universal-cookie": "^7.2.0" }, "peerDependencies": { "@edx/frontend-platform": "^7.0.0 || ^8.0.0", diff --git a/src/DesktopHeader.jsx b/src/DesktopHeader.jsx new file mode 100644 index 000000000..d915f7812 --- /dev/null +++ b/src/DesktopHeader.jsx @@ -0,0 +1,224 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { getConfig } from '@edx/frontend-platform'; +import ThemeToggleButton from './ThemeToggleButton'; + +// Local Components +import { Menu, MenuTrigger, MenuContent } from './Menu'; +import Avatar from './Avatar'; +import { LinkedLogo, Logo } from './Logo'; + +// i18n +import messages from './Header.messages'; + +// Assets +import { CaretIcon } from './Icons'; + +class DesktopHeader extends React.Component { + constructor(props) { // eslint-disable-line no-useless-constructor + super(props); + } + + renderMenu(menu) { + // Nodes are accepted as a prop + if (!Array.isArray(menu)) { + return menu; + } + + return menu.map((menuItem) => { + const { + type, + href, + content, + submenuContent, + disabled, + isActive, + onClick, + } = menuItem; + + if (type === 'item') { + return ( + + {content} + + ); + } + + return ( +
+ ); + }); + } + + renderMainMenu() { + const { mainMenu } = this.props; + return this.renderMenu(mainMenu); + } + + renderSecondaryMenu() { + const { secondaryMenu } = this.props; + return this.renderMenu(secondaryMenu); + } + + renderUserMenu() { + const { + userMenu, + avatar, + username, + intl, + } = this.props; + + return ( + + ); + } + + renderLoggedOutItems() { + const { loggedOutItems } = this.props; + + return loggedOutItems.map((item, i, arr) => ( + + {item.content} + + )); + } + + render() { + const { + logo, + logoAltText, + logoDestination, + loggedIn, + intl, + } = this.props; + const logoProps = { src: logo, alt: logoAltText, href: logoDestination }; + const logoClasses = getConfig().AUTHN_MINIMAL_HEADER ? 'mw-100' : null; + + return ( +