Skip to content
Merged
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
52 changes: 49 additions & 3 deletions src/plugin-slots/ContentIFrameLoaderSlot/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,56 @@
# Content iframe Loader Slot
# Content IFrame Loader Slot

### Slot ID: `org.openedx.frontend.learning.content_iframe_loader.v1`

### Slot ID Aliases
* `content_iframe_loader_slot`

### Props:
* `courseId`
* `defaultLoaderComponent`
* `courseId` - String identifier for the current course
* `defaultLoaderComponent` - React component used as the default loading indicator

## Description

This slot is used to customize the loading indicator displayed while course content is being loaded in an iframe. It appears when content is loading but hasn't fully rendered yet, providing a customizable loading experience for learners.

The default implementation shows a `PageLoading` component with a screen reader message.

## Example

The following `env.config.jsx` will replace the default loading spinner with a custom loading component that shows the course ID and a custom message.

![Content Iframe Loader Example](./images/loader-example.png)


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

const config = {
pluginSlots: {
'org.openedx.frontend.learning.content_iframe_loader.v1': {
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widgetId: 'default_contents',
widget: {
id: 'custom_iframe_loader',
type: DIRECT_PLUGIN,
RenderWidget: ({ courseId, defaultLoaderComponent }) => (
<div style={{ textAlign: 'center', padding: '2rem' }}>
<h3>Loading course content...</h3>
<p>Course: {courseId}</p>
<div style={{ margin: '1rem 0' }}>
{defaultLoaderComponent}
</div>
<p>Please wait while we prepare your learning experience</p>
</div>
),
},
},
]
}
},
}

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.
54 changes: 52 additions & 2 deletions src/plugin-slots/CourseOutlineTabNotificationsSlot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,55 @@
* `outline_tab_notifications_slot`

### Props:
* `courseId`
* `model`
* `courseId` - String identifier for the current course
* `model` - String indicating the context model (set to 'outline')

## Description

This slot is used to add custom notification components to the course outline tab sidebar. It appears in the right sidebar of the course outline/home tab, positioned between the Course Tools widget and the Course Dates widget.

The slot provides a flexible way to inject custom notifications, announcements, or informational components that are contextually relevant to the course outline view.

## Example

The following `env.config.jsx` will add a custom notification component to the course outline tab sidebar.

![Course notification example](./images/course-outline-notification-example.png)

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

const config = {
pluginSlots: {
'org.openedx.frontend.learning.course_outline_tab_notifications.v1': {
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'custom_outline_notification',
type: DIRECT_PLUGIN,
RenderWidget: ({ courseId, model }) => (
<div className="card mb-3">
<div className="card-body">
<h5 className="card-title">📢 Course Announcement</h5>
<p className="card-text">
Important updates for course {courseId}
</p>
<p className="text-muted small">
Context: {model}
</p>
<button className="btn btn-primary btn-sm">
View Details
</button>
</div>
</div>
),
},
},
]
}
},
}

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.
63 changes: 62 additions & 1 deletion src/plugin-slots/GatedUnitContentMessageSlot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,65 @@
* `gated_unit_content_message_slot`

### Props:
* `courseId`
* `courseId` - String identifier for the current course

## Description

This slot is used to customize the message displayed when course content is gated or locked for learners who haven't upgraded to a verified track. It appears when a unit contains content that requires a paid enrollment (such as graded assignments) and the learner is on the audit track.

The default implementation shows a `LockPaywall` component that displays an upgrade message with benefits of upgrading, including access to graded assignments, certificates, and full course features.

This slot is conditionally rendered only when `contentTypeGatingEnabled` is true and the unit `containsContentTypeGatedContent`.

## Example

The following `env.config.jsx` will replace the default paywall message with a custom gated content component.

![Gated unit message example](./images/gated-unit-message-example.png)

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

const config = {
pluginSlots: {
'org.openedx.frontend.learning.gated_unit_content_message.v1': {
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widgetId: 'default_contents',
widget: {
id: 'custom_gated_message',
type: DIRECT_PLUGIN,
RenderWidget: ({ courseId }) => (
<div className="alert alert-warning" role="alert">
<div className="d-flex align-items-center mb-3">
<i className="fa fa-lock fa-2x me-3" aria-hidden="true"></i>
<div>
<h4 className="alert-heading mb-1">Premium Content</h4>
<p className="mb-0">This content is available to verified learners only.</p>
</div>
</div>
<hr />
<p className="mb-3">
Upgrade your enrollment for course {courseId} to access:
</p>
<ul className="mb-3">
<li>✅ Graded assignments and quizzes</li>
<li>🏆 Verified certificate upon completion</li>
<li>💬 Full discussion forum access</li>
<li>📱 Mobile app offline access</li>
</ul>
<button className="btn btn-success">
Upgrade Now
</button>
</div>
),
},
},
]
}
},
}

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.
92 changes: 89 additions & 3 deletions src/plugin-slots/NotificationTraySlot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,92 @@
* `notification_tray_slot`

### Props:
* `courseId`
* `notificationCurrentState`
* `setNotificationCurrentState`
* `courseId` - String identifier for the current course
* `model` - String indicating the context model (set to 'coursewareMeta')
* `notificationCurrentState` - Current state of upgrade notifications (UpgradeNotificationState)
* `setNotificationCurrentState` - Function to update the notification state

## Description

This slot is used to customize the notification tray that appears in the courseware sidebar. The notification tray displays upgrade-related notifications and alerts for learners in verified mode courses. It provides a way to show contextual notifications about course access, deadlines, and upgrade opportunities.

The slot is conditionally rendered only for learners in verified mode courses. For non-verified courses, a simple "no notifications" message is displayed instead.

The `notificationCurrentState` can be one of: `'accessLastHour'`, `'accessHoursLeft'`, `'accessDaysLeft'`, `'FPDdaysLeft'`, `'FPDLastHour'`, `'accessDateView'`, or `'PastExpirationDate'`.

## Example

The following `env.config.jsx` will customize the notification tray with additional notification types and styling.

![Notification tray slot example](./images/notification-tray-slot-example.png)
```js
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';

const config = {
pluginSlots: {
'org.openedx.frontend.learning.notification_tray.v1': {
plugins: [
{
// Insert custom notification content
op: PLUGIN_OPERATIONS.Replace,
widget: {
id: 'custom_notifications',
type: DIRECT_PLUGIN,
RenderWidget: ({
courseId,
model,
notificationCurrentState,
setNotificationCurrentState
}) => (
<div className="p-3">
<h5 className="mb-3">📬 Course Notifications</h5>

{notificationCurrentState === 'accessLastHour' && (
<div className="alert alert-warning mb-3">
<strong>⏰ Last Chance!</strong>
<p className="mb-0">Your access expires in less than an hour.</p>
</div>
)}

{notificationCurrentState === 'accessDaysLeft' && (
<div className="alert alert-info mb-3">
<strong>📅 Access Reminder</strong>
<p className="mb-0">Your course access expires in a few days.</p>
</div>
)}

<div className="notification-item p-2 mb-2 border rounded">
<div className="d-flex justify-content-between align-items-center">
<span>📚 New course material available</span>
<button
className="btn btn-sm btn-outline-primary"
onClick={() => setNotificationCurrentState('accessDateView')}
>
View
</button>
</div>
</div>

<div className="notification-item p-2 mb-2 border rounded">
<div className="d-flex justify-content-between align-items-center">
<span>🎯 Assignment due tomorrow</span>
<span className="badge bg-warning">Due Soon</span>
</div>
</div>

<div className="text-center mt-3">
<small className="text-muted">
Course: {courseId} | Model: {model}
</small>
</div>
</div>
),
},
},
]
}
},
}

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.
Loading