Skip to content

Commit a71152b

Browse files
feat: move sequence navigation to plugin slot (#1716)
1 parent d14c2a9 commit a71152b

File tree

6 files changed

+133
-6
lines changed

6 files changed

+133
-6
lines changed

src/courseware/course/sequence/Sequence.jsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,18 @@ import SequenceExamWrapper from '@edx/frontend-lib-special-exams';
1313
import PageLoading from '@src/generic/PageLoading';
1414
import { useModel } from '@src/generic/model-store';
1515
import { useSequenceBannerTextAlert, useSequenceEntranceExamAlert } from '@src/alerts/sequence-alerts/hooks';
16-
import SequenceContainerSlot from '../../../plugin-slots/SequenceContainerSlot';
16+
import SequenceContainerSlot from '@src/plugin-slots/SequenceContainerSlot';
17+
import { CourseOutlineSidebarSlot } from '@src/plugin-slots/CourseOutlineSidebarSlot';
18+
import { CourseOutlineSidebarTriggerSlot } from '@src/plugin-slots/CourseOutlineSidebarTriggerSlot';
19+
import { NotificationsDiscussionsSidebarSlot } from '@src/plugin-slots/NotificationsDiscussionsSidebarSlot';
20+
import SequenceNavigationSlot from '@src/plugin-slots/SequenceNavigationSlot';
1721

1822
import { getCoursewareOutlineSidebarSettings } from '../../data/selectors';
1923
import CourseLicense from '../course-license';
20-
import { NotificationsDiscussionsSidebarSlot } from '../../../plugin-slots/NotificationsDiscussionsSidebarSlot';
2124
import messages from './messages';
2225
import HiddenAfterDue from './hidden-after-due';
23-
import { SequenceNavigation, UnitNavigation } from './sequence-navigation';
26+
import { UnitNavigation } from './sequence-navigation';
2427
import SequenceContent from './SequenceContent';
25-
import { CourseOutlineSidebarSlot } from '../../../plugin-slots/CourseOutlineSidebarSlot';
26-
import { CourseOutlineSidebarTriggerSlot } from '../../../plugin-slots/CourseOutlineSidebarTriggerSlot';
2728

2829
const Sequence = ({
2930
unitId,
@@ -172,7 +173,7 @@ const Sequence = ({
172173
<div className="sequence w-100">
173174
{!isEnabledOutlineSidebar && (
174175
<div className="sequence-navigation-container">
175-
<SequenceNavigation
176+
<SequenceNavigationSlot
176177
sequenceId={sequenceId}
177178
unitId={unitId}
178179
nextHandler={() => {

src/plugin-slots/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@
2323
* [`org.openedx.frontend.learning.progress_tab_grade_breakdown.v1`](./ProgressTabGradeBreakdownSlot/)
2424
* [`org.openedx.frontend.learning.progress_tab_related_links.v1`](./ProgressTabRelatedLinksSlot/)
2525
* [`org.openedx.frontend.learning.sequence_container.v1`](./SequenceContainerSlot/)
26+
* [`org.openedx.frontend.learning.sequence_navigation.v1`](./SequenceNavigationSlot/)
2627
* [`org.openedx.frontend.learning.unit_title.v1`](./UnitTitleSlot/)
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Sequence Navigation Slot
2+
3+
### Slot ID: `org.openedx.frontend.learning.sequence_navigation.v1`
4+
5+
### Props:
6+
* `sequenceId` (string) — Current sequence identifier
7+
* `unitId` (string) — Current unit identifier
8+
* `nextHandler` (function) — Handler for next navigation action
9+
* `onNavigate` (function) — Handler for direct unit navigation
10+
* `previousHandler` (function) — Handler for previous navigation action
11+
12+
## Description
13+
14+
This slot is used to replace/modify/hide the sequence navigation component that controls navigation between units within a course sequence.
15+
16+
## Example
17+
18+
### Default content
19+
![Sequence navigation slot with default content](./screenshot_default.png)
20+
21+
### Replaced with custom component
22+
![📖 in sequence navigation slot](./screenshot_custom.png)
23+
24+
The following `env.config.jsx` will replace the sequence navigation with a custom implementation that uses all available props.
25+
26+
```js
27+
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
28+
29+
const config = {
30+
pluginSlots: {
31+
'org.openedx.frontend.learning.sequence_navigation.v1': {
32+
keepDefault: false,
33+
plugins: [
34+
{
35+
op: PLUGIN_OPERATIONS.Insert,
36+
widget: {
37+
id: 'custom_sequence_navigation',
38+
type: DIRECT_PLUGIN,
39+
RenderWidget: ({ sequenceId, unitId, nextHandler, onNavigate, previousHandler }) => {
40+
// Mock unit data for demonstration
41+
const units = ['unit-1', 'unit-2', 'unit-3'];
42+
43+
return (
44+
<Stack gap={2} direction="horizontal" className="p-3 bg-light w-100">
45+
<Button
46+
className="flex-grow-1"
47+
onClick={previousHandler}
48+
>
49+
⬅️ Previous
50+
</Button>
51+
<Stack gap={2} direction="horizontal">
52+
{units.map((unit, index) => (
53+
<Button
54+
variant="outline-primary"
55+
key={unit}
56+
className={`btn btn-sm ${unitId === unit ? 'btn-primary' : 'btn-outline-secondary'}`}
57+
onClick={() => onNavigate(unit)}
58+
>
59+
{index + 1}
60+
</Button>
61+
))}
62+
</Stack>
63+
<Button
64+
className="flex-grow-1"
65+
onClick={nextHandler}
66+
>
67+
Next ➡️
68+
</Button>
69+
</Stack>
70+
)
71+
},
72+
},
73+
},
74+
]
75+
}
76+
},
77+
}
78+
79+
export default config;
80+
```
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { PluginSlot } from '@openedx/frontend-plugin-framework';
4+
5+
import { SequenceNavigation } from '../../courseware/course/sequence/sequence-navigation';
6+
7+
const SequenceNavigationSlot = ({
8+
sequenceId,
9+
unitId,
10+
nextHandler,
11+
onNavigate,
12+
previousHandler,
13+
}) => (
14+
<PluginSlot
15+
id="org.openedx.frontend.learning.sequence_navigation.v1"
16+
slotOptions={{
17+
mergeProps: true,
18+
}}
19+
pluginProps={{
20+
sequenceId,
21+
unitId,
22+
nextHandler,
23+
onNavigate,
24+
previousHandler,
25+
}}
26+
>
27+
<SequenceNavigation
28+
sequenceId={sequenceId}
29+
unitId={unitId}
30+
nextHandler={nextHandler}
31+
onNavigate={onNavigate}
32+
previousHandler={previousHandler}
33+
/>
34+
</PluginSlot>
35+
);
36+
37+
SequenceNavigationSlot.propTypes = {
38+
sequenceId: PropTypes.string.isRequired,
39+
unitId: PropTypes.string.isRequired,
40+
nextHandler: PropTypes.func.isRequired,
41+
onNavigate: PropTypes.func.isRequired,
42+
previousHandler: PropTypes.func.isRequired,
43+
};
44+
45+
export default SequenceNavigationSlot;
Loading
Loading

0 commit comments

Comments
 (0)