Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
444 changes: 391 additions & 53 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"ts-jest": "^29.4.4"
},
"dependencies": {
"@edx/frontend-plugin-notifications": "^2.0.5",
"@fortawesome/fontawesome-svg-core": "6.7.2",
"@fortawesome/free-brands-svg-icons": "6.7.2",
"@fortawesome/free-regular-svg-icons": "6.7.2",
Expand Down
5 changes: 4 additions & 1 deletion src/Header.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { IntlProvider } from '@edx/frontend-platform/i18n';
import TestRenderer from 'react-test-renderer';
import { AppContext } from '@edx/frontend-platform/react';
import { Context as ResponsiveContext } from 'react-responsive';
import { MemoryRouter } from 'react-router-dom';

import Header from './index';

Expand All @@ -13,7 +14,9 @@ const HeaderComponent = ({ width, contextValue }) => (
<AppContext.Provider
value={contextValue}
>
<Header />
<MemoryRouter>
<Header />
</MemoryRouter>
</AppContext.Provider>
</IntlProvider>
</ResponsiveContext.Provider>
Expand Down
4 changes: 2 additions & 2 deletions src/learning-header/LearningHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import LogoSlot from '../plugin-slots/LogoSlot';
import CourseInfoSlot from '../plugin-slots/CourseInfoSlot';
import { courseInfoDataShape } from './LearningHeaderCourseInfo';
import messages from './messages';
import LearningHelpSlot from '../plugin-slots/LearningHelpSlot';
import LearningHeaderActionsSlot from '../plugin-slots/LearningHeaderActionsSlot';

const LearningHeader = ({
courseOrg,
Expand Down Expand Up @@ -39,7 +39,7 @@ const LearningHeader = ({
</div>
{showUserDropdown && authenticatedUser && (
<>
<LearningHelpSlot />
<LearningHeaderActionsSlot />
<AuthenticatedUserDropdown
username={authenticatedUser.username}
/>
Expand Down
39 changes: 39 additions & 0 deletions src/plugin-slots/DesktopSecondaryMenuSlot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,47 @@

This slot is used to replace/modify/hide the desktop secondary menu.

**Default Content:**
- **Notification Tray** (via `HeaderNotificationsSlot`) — Rendered before menu items
- **Secondary Menu Items** — Links like "New", "Help", etc.

### Why Include Notifications Here?

The `org.openedx.frontend.layout.header_notifications_tray.v1` slot is rendered in **multiple headers** (Desktop, Learning, and Studio). Modifying that slot directly would impact notifications across all header types.

By embedding notifications in this slot's default content, operators can:
- **Hide notifications in Desktop header only** — without affecting Learning or Studio headers
- **Customize the entire secondary menu area** — including both notifications and menu items
- **Maintain control** — each header type can be configured independently

To hide notifications in the Desktop header only, use `PLUGIN_OPERATIONS.Hide` with `widgetId: 'org.openedx.frontend.layout.header_notifications_tray.v1'` (see examples below).

## Examples

### Hide Notifications in Desktop Header Only

The following `env.config.jsx` will hide the notification bell in the Desktop header while keeping it in Learning and Studio headers:

```jsx
import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';

const config = {
pluginSlots: {
'org.openedx.frontend.layout.header_desktop_secondary_menu.v1': {
keepDefault: true,
plugins: [
{
op: PLUGIN_OPERATIONS.Hide,
widgetId: 'org.openedx.frontend.layout.header_notifications_tray.v1',
},
]
},
},
}

export default config;
```

### Modify Items

The following `env.config.jsx` will modify the items in the desktop secondary menu.
Expand Down
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/plugin-slots/DesktopSecondaryMenuSlot/index.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { PluginSlot } from '@openedx/frontend-plugin-framework';
import DesktopHeaderMainOrSecondaryMenu, { desktopHeaderMainOrSecondaryMenuDataShape } from '../../desktop-header/DesktopHeaderMainOrSecondaryMenu';
import HeaderNotificationsSlot from '../HeaderNotificationsSlot';

const DesktopSecondaryMenuSlot = ({
menu,
Expand All @@ -12,6 +13,7 @@ const DesktopSecondaryMenuSlot = ({
mergeProps: true,
}}
>
<HeaderNotificationsSlot />
<DesktopHeaderMainOrSecondaryMenu menu={menu} />
</PluginSlot>
);
Expand Down
131 changes: 131 additions & 0 deletions src/plugin-slots/HeaderNotificationsSlot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Header Notifications Slot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No screenshots are appearing in here when browsing https://github.com/awais-ansari/frontend-component-header/tree/aansari/notifications-79/src/plugin-slots/HeaderNotificationsSlot

All of the examples should have screenshots


### Slot ID: `org.openedx.frontend.layout.header_notifications_tray.v1`

## Description

This slot renders the notifications tray (bell icon + notification popover) from `@edx/frontend-plugin-notifications` by default.

**Important:** This slot is **not used standalone** in headers. Instead, it is embedded within the default content of three parent slots:

1. **Desktop Header** — via `org.openedx.frontend.layout.header_desktop_secondary_menu.v1`
Notifications appear before secondary menu items (e.g., "New", "Help")

2. **Learning Header** — via `org.openedx.frontend.layout.learning_header_actions.v1`
Notifications appear before the help link

3. **Studio Header** — via `org.openedx.frontend.layout.studio_header_actions.v1`
Notifications appear before the search button

## Slot Hierarchy

```
Desktop Header
└── org.openedx.frontend.layout.header_desktop_secondary_menu.v1
├── org.openedx.frontend.layout.header_notifications_tray.v1 ← This slot
└── (secondary menu items)

Learning Header
└── org.openedx.frontend.layout.learning_header_actions.v1
├── org.openedx.frontend.layout.header_notifications_tray.v1 ← This slot
└── org.openedx.frontend.layout.header_learning_help.v1

Studio Header
└── org.openedx.frontend.layout.studio_header_actions.v1
├── org.openedx.frontend.layout.header_notifications_tray.v1 ← This slot
└── org.openedx.frontend.layout.studio_header_search_button_slot.v1
```

## Examples

### Disable Notifications Globally (All Headers)

The following `env.config.jsx` will hide the notifications tray across all headers:

```jsx
import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';

const config = {
pluginSlots: {
'org.openedx.frontend.layout.header_notifications_tray.v1': {
keepDefault: true,
plugins: [
{
op: PLUGIN_OPERATIONS.Hide,
widgetId: 'default_contents',
},
]
},
},
}

export default config;
```

### Disable Notifications Per Header

To hide notifications in a specific header only, modify the parent wrapper slot:

- **Desktop Header:** See [DesktopSecondaryMenuSlot documentation](../DesktopSecondaryMenuSlot/)
- **Learning Header:** See [LearningHeaderActionsSlot documentation](../LearningHeaderActionsSlot/)
- **Studio Header:** See [StudioHeaderActionsSlot documentation](../StudioHeaderActionsSlot/)

### Replace Notifications with Custom Component (All Headers)

The following `env.config.jsx` will replace the default notifications tray with a custom component across all headers:

```jsx
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
import CustomNotifications from './CustomNotifications';

const config = {
pluginSlots: {
'org.openedx.frontend.layout.header_notifications_tray.v1': {
keepDefault: false,
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'custom_notifications_component',
type: DIRECT_PLUGIN,
RenderWidget: CustomNotifications,
},
},
]
},
},
}

export default config;
```

### Add Custom Alert Icon Before Notifications (All Headers)

The following `env.config.jsx` will insert a custom alert icon before the notifications bell:

```jsx
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';

const config = {
pluginSlots: {
'org.openedx.frontend.layout.header_notifications_tray.v1': {
keepDefault: true,
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'custom_alert_icon',
type: DIRECT_PLUGIN,
priority: 10,
RenderWidget: () => (
<button aria-label="Alerts">🚨</button>
),
},
},
]
},
},
}

export default config;
```
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions src/plugin-slots/HeaderNotificationsSlot/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { PluginSlot } from '@openedx/frontend-plugin-framework';
import NotificationsTray from '@edx/frontend-plugin-notifications';

const HeaderNotificationsSlot = () => (
<PluginSlot
id="org.openedx.frontend.layout.header_notifications_tray.v1"
>
<NotificationsTray />
</PluginSlot>
);

export default HeaderNotificationsSlot;
94 changes: 94 additions & 0 deletions src/plugin-slots/LearningHeaderActionsSlot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Learning Header Actions Slot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The screenshots added to ./images aren't here


### Slot ID: `org.openedx.frontend.layout.learning_header_actions.v1`

## Description

This slot wraps the notification tray and help link in the Learning header. It provides a single location for operators to customize the action area before the user menu in the Learning (course) header.

By default, this slot renders:
1. **HeaderNotificationsSlot** — The notification bell from `@edx/frontend-plugin-notifications`
2. **LearningHelpSlot** — The help link (question mark icon)

This wrapper slot ensures that:
- Notifications are enabled by default in the Learning header
- Operators can customize the entire action area using one slot ID
- The existing `org.openedx.frontend.layout.header_learning_help.v1` remains functional for backward compatibility

## Why This Wrapper Slot?

The `org.openedx.frontend.layout.header_notifications_tray.v1` slot is rendered in **multiple headers** (Desktop, Learning, and Studio). Modifying that slot directly would impact notifications across all header types.

This wrapper slot allows operators to:
- **Hide notifications in Learning header only** — without affecting Desktop or Studio
- **Customize the action area** — replace or extend both notifications and help link together
- **Maintain control** — each header type can be configured independently

## Examples

### Disable Notifications in Learning Header Only

The following `env.config.jsx` will hide the notification bell in the Learning header while keeping it in Desktop and Studio headers:

```jsx
import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';

const config = {
pluginSlots: {
'org.openedx.frontend.layout.learning_header_actions.v1': {
keepDefault: true,
plugins: [
{
op: PLUGIN_OPERATIONS.Hide,
widgetId: 'org.openedx.frontend.layout.header_notifications_tray.v1',
},
]
},
},
}

export default config;
```

### Replace the Entire Actions Area

The following `env.config.jsx` will replace both notifications and help link with a custom component:

```jsx
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';

const config = {
pluginSlots: {
'org.openedx.frontend.layout.learning_header_actions.v1': {
keepDefault: false,
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'custom_learning_actions',
type: DIRECT_PLUGIN,
RenderWidget: () => (
<div>
<button>Custom Action 1</button>
<button>Custom Action 2</button>
</div>
),
},
},
]
},
},
}

export default config;
```

### Modify Help Link Only

To customize just the help link while keeping notifications, see the [LearningHelpSlot documentation](../LearningHelpSlot/).

## Slot Hierarchy

This slot contains two child slots:
- `org.openedx.frontend.layout.header_notifications_tray.v1` (HeaderNotificationsSlot)
- `org.openedx.frontend.layout.header_learning_help.v1` (LearningHelpSlot)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions src/plugin-slots/LearningHeaderActionsSlot/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import { PluginSlot } from '@openedx/frontend-plugin-framework';
import HeaderNotificationsSlot from '../HeaderNotificationsSlot';
import LearningHelpSlot from '../LearningHelpSlot';

const LearningHeaderActionsSlot = () => (
<PluginSlot
id="org.openedx.frontend.layout.learning_header_actions.v1"
>
<HeaderNotificationsSlot />
<LearningHelpSlot />
</PluginSlot>
);

export default LearningHeaderActionsSlot;
3 changes: 3 additions & 0 deletions src/plugin-slots/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### Shared
* [`org.openedx.frontend.layout.header_logo.v1`](./LogoSlot/)
* [`org.openedx.frontend.layout.header_notifications_tray.v1`](./HeaderNotificationsSlot/)

### Desktop Header
* [`org.openedx.frontend.layout.header_desktop.v1`](./DesktopHeaderSlot/)
Expand All @@ -13,6 +14,7 @@

### Learning Header
* [`org.openedx.frontend.layout.header_learning_course_info.v1`](./CourseInfoSlot/)
* [`org.openedx.frontend.layout.learning_header_actions.v1`](./LearningHeaderActionsSlot/)
* [`org.openedx.frontend.layout.header_learning_help.v1`](./LearningHelpSlot/)
* [`org.openedx.frontend.layout.header_learning_logged_out_items.v1`](./LearningLoggedOutItemsSlot/)
* [`org.openedx.frontend.layout.header_learning_user_menu.v1`](./LearningUserMenuSlot/)
Expand All @@ -26,4 +28,5 @@
* [`org.openedx.frontend.layout.header_mobile_user_menu_trigger.v1`](./MobileUserMenuToggleSlot/)

### Studio Header
* [`org.openedx.frontend.layout.studio_header_actions.v1`](./StudioHeaderActionsSlot/)
* [`org.openedx.frontend.layout.studio_header_search_button_slot.v1`](./StudioHeaderSearchButtonSlot/)
Loading
Loading