feat: move sequence navigation to plugin slot (#1716)
This commit is contained in:
@@ -13,17 +13,18 @@ import SequenceExamWrapper from '@edx/frontend-lib-special-exams';
|
||||
import PageLoading from '@src/generic/PageLoading';
|
||||
import { useModel } from '@src/generic/model-store';
|
||||
import { useSequenceBannerTextAlert, useSequenceEntranceExamAlert } from '@src/alerts/sequence-alerts/hooks';
|
||||
import SequenceContainerSlot from '../../../plugin-slots/SequenceContainerSlot';
|
||||
import SequenceContainerSlot from '@src/plugin-slots/SequenceContainerSlot';
|
||||
import { CourseOutlineSidebarSlot } from '@src/plugin-slots/CourseOutlineSidebarSlot';
|
||||
import { CourseOutlineSidebarTriggerSlot } from '@src/plugin-slots/CourseOutlineSidebarTriggerSlot';
|
||||
import { NotificationsDiscussionsSidebarSlot } from '@src/plugin-slots/NotificationsDiscussionsSidebarSlot';
|
||||
import SequenceNavigationSlot from '@src/plugin-slots/SequenceNavigationSlot';
|
||||
|
||||
import { getCoursewareOutlineSidebarSettings } from '../../data/selectors';
|
||||
import CourseLicense from '../course-license';
|
||||
import { NotificationsDiscussionsSidebarSlot } from '../../../plugin-slots/NotificationsDiscussionsSidebarSlot';
|
||||
import messages from './messages';
|
||||
import HiddenAfterDue from './hidden-after-due';
|
||||
import { SequenceNavigation, UnitNavigation } from './sequence-navigation';
|
||||
import { UnitNavigation } from './sequence-navigation';
|
||||
import SequenceContent from './SequenceContent';
|
||||
import { CourseOutlineSidebarSlot } from '../../../plugin-slots/CourseOutlineSidebarSlot';
|
||||
import { CourseOutlineSidebarTriggerSlot } from '../../../plugin-slots/CourseOutlineSidebarTriggerSlot';
|
||||
|
||||
const Sequence = ({
|
||||
unitId,
|
||||
@@ -172,7 +173,7 @@ const Sequence = ({
|
||||
<div className="sequence w-100">
|
||||
{!isEnabledOutlineSidebar && (
|
||||
<div className="sequence-navigation-container">
|
||||
<SequenceNavigation
|
||||
<SequenceNavigationSlot
|
||||
sequenceId={sequenceId}
|
||||
unitId={unitId}
|
||||
nextHandler={() => {
|
||||
|
||||
@@ -23,4 +23,5 @@
|
||||
* [`org.openedx.frontend.learning.progress_tab_grade_breakdown.v1`](./ProgressTabGradeBreakdownSlot/)
|
||||
* [`org.openedx.frontend.learning.progress_tab_related_links.v1`](./ProgressTabRelatedLinksSlot/)
|
||||
* [`org.openedx.frontend.learning.sequence_container.v1`](./SequenceContainerSlot/)
|
||||
* [`org.openedx.frontend.learning.sequence_navigation.v1`](./SequenceNavigationSlot/)
|
||||
* [`org.openedx.frontend.learning.unit_title.v1`](./UnitTitleSlot/)
|
||||
|
||||
80
src/plugin-slots/SequenceNavigationSlot/README.md
Normal file
80
src/plugin-slots/SequenceNavigationSlot/README.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Sequence Navigation Slot
|
||||
|
||||
### Slot ID: `org.openedx.frontend.learning.sequence_navigation.v1`
|
||||
|
||||
### Props:
|
||||
* `sequenceId` (string) — Current sequence identifier
|
||||
* `unitId` (string) — Current unit identifier
|
||||
* `nextHandler` (function) — Handler for next navigation action
|
||||
* `onNavigate` (function) — Handler for direct unit navigation
|
||||
* `previousHandler` (function) — Handler for previous navigation action
|
||||
|
||||
## Description
|
||||
|
||||
This slot is used to replace/modify/hide the sequence navigation component that controls navigation between units within a course sequence.
|
||||
|
||||
## Example
|
||||
|
||||
### Default content
|
||||

|
||||
|
||||
### Replaced with custom component
|
||||

|
||||
|
||||
The following `env.config.jsx` will replace the sequence navigation with a custom implementation that uses all available props.
|
||||
|
||||
```js
|
||||
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
|
||||
|
||||
const config = {
|
||||
pluginSlots: {
|
||||
'org.openedx.frontend.learning.sequence_navigation.v1': {
|
||||
keepDefault: false,
|
||||
plugins: [
|
||||
{
|
||||
op: PLUGIN_OPERATIONS.Insert,
|
||||
widget: {
|
||||
id: 'custom_sequence_navigation',
|
||||
type: DIRECT_PLUGIN,
|
||||
RenderWidget: ({ sequenceId, unitId, nextHandler, onNavigate, previousHandler }) => {
|
||||
// Mock unit data for demonstration
|
||||
const units = ['unit-1', 'unit-2', 'unit-3'];
|
||||
|
||||
return (
|
||||
<Stack gap={2} direction="horizontal" className="p-3 bg-light w-100">
|
||||
<Button
|
||||
className="flex-grow-1"
|
||||
onClick={previousHandler}
|
||||
>
|
||||
⬅️ Previous
|
||||
</Button>
|
||||
<Stack gap={2} direction="horizontal">
|
||||
{units.map((unit, index) => (
|
||||
<Button
|
||||
variant="outline-primary"
|
||||
key={unit}
|
||||
className={`btn btn-sm ${unitId === unit ? 'btn-primary' : 'btn-outline-secondary'}`}
|
||||
onClick={() => onNavigate(unit)}
|
||||
>
|
||||
{index + 1}
|
||||
</Button>
|
||||
))}
|
||||
</Stack>
|
||||
<Button
|
||||
className="flex-grow-1"
|
||||
onClick={nextHandler}
|
||||
>
|
||||
Next ➡️
|
||||
</Button>
|
||||
</Stack>
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default config;
|
||||
```
|
||||
45
src/plugin-slots/SequenceNavigationSlot/index.jsx
Normal file
45
src/plugin-slots/SequenceNavigationSlot/index.jsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { PluginSlot } from '@openedx/frontend-plugin-framework';
|
||||
|
||||
import { SequenceNavigation } from '../../courseware/course/sequence/sequence-navigation';
|
||||
|
||||
const SequenceNavigationSlot = ({
|
||||
sequenceId,
|
||||
unitId,
|
||||
nextHandler,
|
||||
onNavigate,
|
||||
previousHandler,
|
||||
}) => (
|
||||
<PluginSlot
|
||||
id="org.openedx.frontend.learning.sequence_navigation.v1"
|
||||
slotOptions={{
|
||||
mergeProps: true,
|
||||
}}
|
||||
pluginProps={{
|
||||
sequenceId,
|
||||
unitId,
|
||||
nextHandler,
|
||||
onNavigate,
|
||||
previousHandler,
|
||||
}}
|
||||
>
|
||||
<SequenceNavigation
|
||||
sequenceId={sequenceId}
|
||||
unitId={unitId}
|
||||
nextHandler={nextHandler}
|
||||
onNavigate={onNavigate}
|
||||
previousHandler={previousHandler}
|
||||
/>
|
||||
</PluginSlot>
|
||||
);
|
||||
|
||||
SequenceNavigationSlot.propTypes = {
|
||||
sequenceId: PropTypes.string.isRequired,
|
||||
unitId: PropTypes.string.isRequired,
|
||||
nextHandler: PropTypes.func.isRequired,
|
||||
onNavigate: PropTypes.func.isRequired,
|
||||
previousHandler: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default SequenceNavigationSlot;
|
||||
BIN
src/plugin-slots/SequenceNavigationSlot/screenshot_custom.png
Normal file
BIN
src/plugin-slots/SequenceNavigationSlot/screenshot_custom.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 709 KiB |
BIN
src/plugin-slots/SequenceNavigationSlot/screenshot_default.png
Normal file
BIN
src/plugin-slots/SequenceNavigationSlot/screenshot_default.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 756 KiB |
Reference in New Issue
Block a user