diff --git a/src/Header.jsx b/src/Header.jsx
index 2f190f205..0aee2c839 100644
--- a/src/Header.jsx
+++ b/src/Header.jsx
@@ -45,9 +45,10 @@ subscribe(APP_CONFIG_INITIALIZED, () => {
* See the documentation for the structure of secondary menu item.
* @param {list} userMenuItems - The list of user menu items to display.
* See the documentation for the structure of user menu item.
+ * @param {string} logoDestination - The destination of the logo.
*/
const Header = ({
- intl, mainMenuItems, secondaryMenuItems, userMenuItems,
+ intl, mainMenuItems, secondaryMenuItems, userMenuItems, logoDestination,
}) => {
const { authenticatedUser, config } = useContext(AppContext);
@@ -110,7 +111,7 @@ const Header = ({
const props = {
logo: config.LOGO_URL,
logoAltText: config.SITE_NAME,
- logoDestination: `${config.LMS_BASE_URL}/dashboard`,
+ logoDestination: logoDestination || `${config.LMS_BASE_URL}/dashboard`,
loggedIn: authenticatedUser !== null,
username: authenticatedUser !== null ? authenticatedUser.username : null,
avatar: authenticatedUser !== null ? authenticatedUser.avatar : null,
@@ -136,6 +137,7 @@ Header.defaultProps = {
mainMenuItems: null,
secondaryMenuItems: null,
userMenuItems: null,
+ logoDestination: null,
};
Header.propTypes = {
@@ -157,6 +159,10 @@ Header.propTypes = {
isActive: PropTypes.bool,
})),
})),
+ logoDestination: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.oneOf([false, null]),
+ ]),
};
export default injectIntl(Header);
diff --git a/src/Header.test.jsx b/src/Header.test.jsx
index 51fef2089..abebbf833 100644
--- a/src/Header.test.jsx
+++ b/src/Header.test.jsx
@@ -101,4 +101,30 @@ describe('', () => {
expect(wrapper.toJSON()).toMatchSnapshot();
});
+
+ it('renders correctly with custom logoDestination', () => {
+ const contextValue = {
+ authenticatedUser: null,
+ config: {
+ LMS_BASE_URL: process.env.LMS_BASE_URL,
+ SITE_NAME: process.env.SITE_NAME,
+ LOGIN_URL: process.env.LOGIN_URL,
+ LOGOUT_URL: process.env.LOGOUT_URL,
+ LOGO_URL: process.env.LOGO_URL,
+ },
+ };
+ const customLogoDestination = '/custom-destination';
+ const component = (
+
+
+
+
+
+
+
+ );
+
+ const wrapper = TestRenderer.create(component);
+ expect(wrapper.toJSON()).toMatchSnapshot();
+ });
});
diff --git a/src/__snapshots__/Header.test.jsx.snap b/src/__snapshots__/Header.test.jsx.snap
index 781e7f729..9c0615bba 100644
--- a/src/__snapshots__/Header.test.jsx.snap
+++ b/src/__snapshots__/Header.test.jsx.snap
@@ -443,3 +443,63 @@ exports[` renders correctly for authenticated mobile 1`] = `
`;
+
+exports[` renders correctly with custom logoDestination 1`] = `
+
+`;
diff --git a/src/desktop-header/DesktopHeader.jsx b/src/desktop-header/DesktopHeader.jsx
index 4b5e4939f..6cc810217 100644
--- a/src/desktop-header/DesktopHeader.jsx
+++ b/src/desktop-header/DesktopHeader.jsx
@@ -115,7 +115,10 @@ export const desktopHeaderDataShape = {
loggedOutItems: desktopLoggedOutItemsDataShape,
logo: PropTypes.string,
logoAltText: PropTypes.string,
- logoDestination: PropTypes.string,
+ logoDestination: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.oneOf([false, null]),
+ ]),
avatar: PropTypes.string,
username: PropTypes.string,
loggedIn: PropTypes.bool,
@@ -128,7 +131,7 @@ DesktopHeader.propTypes = {
loggedOutItems: desktopHeaderDataShape.loggedOutItemsmainMenu,
logo: desktopHeaderDataShape.logomainMenu,
logoAltText: desktopHeaderDataShape.logoAltTextmainMenu,
- logoDestination: desktopHeaderDataShape.logoDestinationmainMenu,
+ logoDestination: desktopHeaderDataShape.logoDestination,
avatar: desktopHeaderDataShape.avatarmainMenu,
username: desktopHeaderDataShape.usernamemainMenu,
loggedIn: desktopHeaderDataShape.loggedInmainMenu,
diff --git a/src/mobile-header/MobileHeader.jsx b/src/mobile-header/MobileHeader.jsx
index 7a04ec7e7..b98ef801e 100644
--- a/src/mobile-header/MobileHeader.jsx
+++ b/src/mobile-header/MobileHeader.jsx
@@ -118,7 +118,10 @@ export const mobileHeaderDataShape = {
loggedOutItems: mobileHeaderLoggedOutItemsDataShape,
logo: PropTypes.string,
logoAltText: PropTypes.string,
- logoDestination: PropTypes.string,
+ logoDestination: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.oneOf([false, null]),
+ ]),
avatar: PropTypes.string,
username: PropTypes.string,
loggedIn: PropTypes.bool,
diff --git a/src/plugin-slots/DesktopMainMenuSlot/README.md b/src/plugin-slots/DesktopMainMenuSlot/README.md
index b266cdc6b..4650ead9c 100644
--- a/src/plugin-slots/DesktopMainMenuSlot/README.md
+++ b/src/plugin-slots/DesktopMainMenuSlot/README.md
@@ -135,3 +135,54 @@ const config = {
export default config;
```
+### Add Custom Marketing links
+
+This `env.config.jsx` will add new custom **Marketing links** to the desktop main menu.
+
+
+
+```jsx
+import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
+
+const modifyMainMenu = (widget) => {
+ const existingMenu = widget.RenderWidget.props.menu || [];
+
+ const newMarketingLinks = [
+ {
+ type: 'item',
+ href: 'https://example.com/how-it-works',
+ content: 'How it works',
+ },
+ {
+ type: 'item',
+ href: 'https://example.com/courses',
+ content: 'Courses',
+ },
+ {
+ type: 'item',
+ href: 'https://example.com/schools',
+ content: 'Schools',
+ }
+ ];
+
+ widget.content.menu = [...existingMenu, ...newMarketingLinks];
+ return widget;
+};
+
+const config = {
+ pluginSlots: {
+ 'org.openedx.frontend.layout.header_desktop_main_menu.v1': {
+ keepDefault: true,
+ plugins: [
+ {
+ op: PLUGIN_OPERATIONS.Modify,
+ widgetId: 'default_contents',
+ fn: modifyMainMenu,
+ },
+ ]
+ },
+ },
+}
+
+export default config;
+```
diff --git a/src/plugin-slots/DesktopMainMenuSlot/images/desktop_main_menu_marketing_links.png b/src/plugin-slots/DesktopMainMenuSlot/images/desktop_main_menu_marketing_links.png
new file mode 100644
index 000000000..3e3e6acb6
Binary files /dev/null and b/src/plugin-slots/DesktopMainMenuSlot/images/desktop_main_menu_marketing_links.png differ