From f7005e298075031ab494bba61708d45cbe9f07ee Mon Sep 17 00:00:00 2001 From: "kshitij.sobti" Date: Tue, 19 May 2026 01:11:19 +0530 Subject: [PATCH 1/4] feat: Add `SequenceBottomNavigationSlot` for customizable sequence navigation Introduces a new plugin slot (`SequenceBottomNavigationSlot`) for extending or replacing the default bottom navigation in course sequences. Updates `Sequence` component to integrate with this slot. Includes documentation and examples for plugin usage. --- src/courseware/course/Course.test.jsx | 2 +- src/courseware/course/sequence/Sequence.jsx | 18 ++++- .../sequence-navigation/UnitNavigation.jsx | 2 +- src/courseware/course/test-utils.jsx | 22 +++--- .../SequenceBottomNavigationSlot/README.md | 66 ++++++++++++++++++ .../arrow-naviation.png | Bin 0 -> 18773 bytes .../default-navigation.png | Bin 0 -> 22352 bytes .../SequenceBottomNavigationSlot/index.tsx | 47 +++++++++++++ 8 files changed, 142 insertions(+), 15 deletions(-) create mode 100644 src/plugin-slots/SequenceBottomNavigationSlot/README.md create mode 100644 src/plugin-slots/SequenceBottomNavigationSlot/arrow-naviation.png create mode 100644 src/plugin-slots/SequenceBottomNavigationSlot/default-navigation.png create mode 100644 src/plugin-slots/SequenceBottomNavigationSlot/index.tsx diff --git a/src/courseware/course/Course.test.jsx b/src/courseware/course/Course.test.jsx index 1bf61f0eef..c4d5d57de1 100644 --- a/src/courseware/course/Course.test.jsx +++ b/src/courseware/course/Course.test.jsx @@ -188,7 +188,7 @@ describe('Course', () => { await setupDiscussionSidebar(); - const { rerender } = render(, { store: testStore }); + const { rerender } = render(, { store: testStore, wrapWithRouter: true }); loadUnit(); const sidebar = await screen.findByTestId('sidebar-DISCUSSIONS'); diff --git a/src/courseware/course/sequence/Sequence.jsx b/src/courseware/course/sequence/Sequence.jsx index e8bf9e2882..4b12cab2ac 100644 --- a/src/courseware/course/sequence/Sequence.jsx +++ b/src/courseware/course/sequence/Sequence.jsx @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-use-before-define */ +import SequenceBottomNavigationSlot from '@src/plugin-slots/SequenceBottomNavigationSlot'; import { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; @@ -224,7 +225,22 @@ const Sequence = ({ isOriginalUserStaff={originalUserIsStaff} renderUnitNavigation={renderUnitNavigation} /> - {unitHasLoaded && renderUnitNavigation(false)} + {unitHasLoaded && ( + { + logEvent('edx.ui.lms.sequence.previous_selected', 'bottom'); + handlePrevious(); + }} + nextHandler={() => { + logEvent('edx.ui.lms.sequence.next_selected', 'bottom'); + handleNext(); + }} + onNavigate={onNavigate} + /> + )} diff --git a/src/courseware/course/sequence/sequence-navigation/UnitNavigation.jsx b/src/courseware/course/sequence/sequence-navigation/UnitNavigation.jsx index ce8903dd4f..e0c9ad0188 100644 --- a/src/courseware/course/sequence/sequence-navigation/UnitNavigation.jsx +++ b/src/courseware/course/sequence/sequence-navigation/UnitNavigation.jsx @@ -2,13 +2,13 @@ import classNames from 'classnames'; import PropTypes from 'prop-types'; import { useIntl } from '@edx/frontend-platform/i18n'; +import { NextUnitTopNavTriggerSlot } from '@src/plugin-slots/NextUnitTopNavTriggerSlot'; import { GetCourseExitNavigation } from '../../course-exit'; import { useSequenceNavigationMetadata } from './hooks'; import messages from './messages'; import PreviousButton from './generic/PreviousButton'; import NextButton from './generic/NextButton'; -import { NextUnitTopNavTriggerSlot } from '../../../../plugin-slots/NextUnitTopNavTriggerSlot'; const UnitNavigation = ({ sequenceId, diff --git a/src/courseware/course/test-utils.jsx b/src/courseware/course/test-utils.jsx index 74afc67beb..43c5a13f43 100644 --- a/src/courseware/course/test-utils.jsx +++ b/src/courseware/course/test-utils.jsx @@ -1,12 +1,11 @@ -import React from 'react'; -import { Factory } from 'rosie'; import { getConfig, snakeCaseObject } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; -import MockAdapter from 'axios-mock-adapter'; import { breakpoints } from '@openedx/paragon'; -import { executeThunk } from '@src/utils'; import { initializeTestStore, render } from '@src/setupTest'; -import SidebarContext from '@src/courseware/course/sidebar/SidebarContext'; +import { executeThunk } from '@src/utils'; +import MockAdapter from 'axios-mock-adapter'; +import React from 'react'; +import { Factory } from 'rosie'; import { buildTopicsFromUnits } from '../data/__factories__/discussionTopics.factory'; import * as thunks from '../data/thunks'; import Course from './Course'; @@ -43,15 +42,14 @@ const setupDiscussionSidebar = async (HomeMetaParams) => { mockData.unitId = firstUnitId; const [firstSequenceId] = Object.keys(state.models.sequences); mockData.sequenceId = firstSequenceId; - const contextValue = { courseId: mockData.courseId, currentSidebar: null, toggleSidebar: jest.fn() }; - const wrapper = await render( - - - , - { store: testStore, wrapWithRouter: true }, + return render( + , + { + store: testStore, + wrapWithRouter: true, + }, ); - return wrapper; }; export default setupDiscussionSidebar; diff --git a/src/plugin-slots/SequenceBottomNavigationSlot/README.md b/src/plugin-slots/SequenceBottomNavigationSlot/README.md new file mode 100644 index 0000000000..4ca651ec5a --- /dev/null +++ b/src/plugin-slots/SequenceBottomNavigationSlot/README.md @@ -0,0 +1,66 @@ +# Sequence Bottom Navigation Slot + +### Slot ID: `org.openedx.frontend.learning.sequence_bottom_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 at the bottom of the page. + +## Example + +### Default Navigation +![Default Navigation](./default-navigation.png) + +### Replaced with top naviation arrows +![Top navigation at bottom](./arrow-navigation.png) + +```js +import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework'; + +const config = { + pluginSlots: { + 'org.openedx.frontend.learning.sequence_bottom_navigation.v1': { + keepDefault: false, + plugins: [ + { + op: PLUGIN_OPERATIONS.Insert, + widget: { + id: 'custom_sequence_navigation', + type: DIRECT_PLUGIN, + RenderWidget: ({ + sequenceId, + unitId, + nextHandler, + onNavigate, + previousHandler + }) => { + const { courseId } = useParams(); + return ( +
+ +
+ ); + }, + }, + }, + ], + }, + }, +}; + +export default config; +``` diff --git a/src/plugin-slots/SequenceBottomNavigationSlot/arrow-naviation.png b/src/plugin-slots/SequenceBottomNavigationSlot/arrow-naviation.png new file mode 100644 index 0000000000000000000000000000000000000000..0cfd615189c6d6d987dcbfb94318519cd364d4f8 GIT binary patch literal 18773 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 literal 0 HcmV?d00001 diff --git a/src/plugin-slots/SequenceBottomNavigationSlot/default-navigation.png b/src/plugin-slots/SequenceBottomNavigationSlot/default-navigation.png new file mode 100644 index 0000000000000000000000000000000000000000..d07c1be223f2ba1347f33d2e057a088f464655f6 GIT binary patch literal 22352 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 literal 0 HcmV?d00001 diff --git a/src/plugin-slots/SequenceBottomNavigationSlot/index.tsx b/src/plugin-slots/SequenceBottomNavigationSlot/index.tsx new file mode 100644 index 0000000000..ea9ff0cb0d --- /dev/null +++ b/src/plugin-slots/SequenceBottomNavigationSlot/index.tsx @@ -0,0 +1,47 @@ +import { UnitNavigation } from '@src/courseware/course/sequence/sequence-navigation'; +import React from 'react'; +import { PluginSlot } from '@openedx/frontend-plugin-framework'; + +export interface SequenceBottomNavigationSlotProps { + courseId: string; + sequenceId: string; + unitId: string; + nextHandler: () => void; + onNavigate: (unitId: string) => void; + previousHandler: () => void; +} + +const SequenceBottomNavigationSlot = ({ + courseId, + sequenceId, + unitId, + nextHandler, + onNavigate, + previousHandler, +}: SequenceBottomNavigationSlotProps) => ( + + + +); + +export default SequenceBottomNavigationSlot; From d1d1abbfbae8989c943de23a663b646fff78d32d Mon Sep 17 00:00:00 2001 From: Kshitij Sobti Date: Fri, 29 May 2026 08:21:13 +0530 Subject: [PATCH 2/4] fixup! feat: Add `SequenceBottomNavigationSlot` for customizable sequence navigation --- src/courseware/course/sequence/Sequence.jsx | 38 +++++++++------------ 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/src/courseware/course/sequence/Sequence.jsx b/src/courseware/course/sequence/Sequence.jsx index 4b12cab2ac..11c7900d26 100644 --- a/src/courseware/course/sequence/Sequence.jsx +++ b/src/courseware/course/sequence/Sequence.jsx @@ -167,20 +167,24 @@ const Sequence = ({ const gated = sequence && sequence.gatedContent !== undefined && sequence.gatedContent.gated; + const unitNavigationProps = { + courseId, + sequenceId, + unitId, + onClickPrevious() { + logEvent('edx.ui.lms.sequence.previous_selected', 'bottom'); + handlePrevious(); + }, + onClickNext() { + logEvent('edx.ui.lms.sequence.next_selected', 'bottom'); + handleNext(); + }, + }; + const renderUnitNavigation = (isAtTop) => ( { - logEvent('edx.ui.lms.sequence.previous_selected', 'bottom'); - handlePrevious(); - }} - onClickNext={() => { - logEvent('edx.ui.lms.sequence.next_selected', 'bottom'); - handleNext(); - }} + {...unitNavigationProps} /> ); @@ -227,17 +231,7 @@ const Sequence = ({ /> {unitHasLoaded && ( { - logEvent('edx.ui.lms.sequence.previous_selected', 'bottom'); - handlePrevious(); - }} - nextHandler={() => { - logEvent('edx.ui.lms.sequence.next_selected', 'bottom'); - handleNext(); - }} + {...unitNavigationProps} onNavigate={onNavigate} /> )} From 053013cdf290d2c9e96e5ff4c425fbd178148a57 Mon Sep 17 00:00:00 2001 From: Kshitij Sobti Date: Fri, 29 May 2026 09:08:01 +0530 Subject: [PATCH 3/4] fixup! fixup! feat: Add `SequenceBottomNavigationSlot` for customizable sequence navigation --- src/courseware/course/Course.test.jsx | 2 +- src/courseware/course/test-utils.jsx | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/courseware/course/Course.test.jsx b/src/courseware/course/Course.test.jsx index c4d5d57de1..1bf61f0eef 100644 --- a/src/courseware/course/Course.test.jsx +++ b/src/courseware/course/Course.test.jsx @@ -188,7 +188,7 @@ describe('Course', () => { await setupDiscussionSidebar(); - const { rerender } = render(, { store: testStore, wrapWithRouter: true }); + const { rerender } = render(, { store: testStore }); loadUnit(); const sidebar = await screen.findByTestId('sidebar-DISCUSSIONS'); diff --git a/src/courseware/course/test-utils.jsx b/src/courseware/course/test-utils.jsx index 43c5a13f43..74afc67beb 100644 --- a/src/courseware/course/test-utils.jsx +++ b/src/courseware/course/test-utils.jsx @@ -1,11 +1,12 @@ +import React from 'react'; +import { Factory } from 'rosie'; import { getConfig, snakeCaseObject } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import MockAdapter from 'axios-mock-adapter'; import { breakpoints } from '@openedx/paragon'; -import { initializeTestStore, render } from '@src/setupTest'; import { executeThunk } from '@src/utils'; -import MockAdapter from 'axios-mock-adapter'; -import React from 'react'; -import { Factory } from 'rosie'; +import { initializeTestStore, render } from '@src/setupTest'; +import SidebarContext from '@src/courseware/course/sidebar/SidebarContext'; import { buildTopicsFromUnits } from '../data/__factories__/discussionTopics.factory'; import * as thunks from '../data/thunks'; import Course from './Course'; @@ -42,14 +43,15 @@ const setupDiscussionSidebar = async (HomeMetaParams) => { mockData.unitId = firstUnitId; const [firstSequenceId] = Object.keys(state.models.sequences); mockData.sequenceId = firstSequenceId; + const contextValue = { courseId: mockData.courseId, currentSidebar: null, toggleSidebar: jest.fn() }; - return render( - , - { - store: testStore, - wrapWithRouter: true, - }, + const wrapper = await render( + + + , + { store: testStore, wrapWithRouter: true }, ); + return wrapper; }; export default setupDiscussionSidebar; From e1703df0965771112853babf50555818518a91d2 Mon Sep 17 00:00:00 2001 From: Kshitij Sobti Date: Fri, 29 May 2026 09:25:20 +0530 Subject: [PATCH 4/4] fixup! fixup! fixup! feat: Add `SequenceBottomNavigationSlot` for customizable sequence navigation --- src/courseware/course/sequence/Sequence.jsx | 30 +++++++++------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/courseware/course/sequence/Sequence.jsx b/src/courseware/course/sequence/Sequence.jsx index 11c7900d26..99ccd48adf 100644 --- a/src/courseware/course/sequence/Sequence.jsx +++ b/src/courseware/course/sequence/Sequence.jsx @@ -92,27 +92,27 @@ const Sequence = ({ }; /* istanbul ignore next */ - const nextHandler = () => { - logEvent('edx.ui.lms.sequence.next_selected', 'top'); + const nextHandler = (placement) => () => { + logEvent('edx.ui.lms.sequence.next_selected', placement); handleNext(); }; /* istanbul ignore next */ - const previousHandler = () => { - logEvent('edx.ui.lms.sequence.previous_selected', 'top'); + const previousHandler = (placement) => () => { + logEvent('edx.ui.lms.sequence.previous_selected', placement); handlePrevious(); }; /* istanbul ignore next */ - const onNavigate = (destinationUnitId) => { - logEvent('edx.ui.lms.sequence.tab_selected', 'top', destinationUnitId); + const onNavigate = (placement) => (destinationUnitId) => { + logEvent('edx.ui.lms.sequence.tab_selected', placement, destinationUnitId); handleNavigate(destinationUnitId); }; const sequenceNavProps = { - nextHandler, - previousHandler, - onNavigate, + nextHandler: nextHandler('top'), + previousHandler: previousHandler('top'), + onNavigate: onNavigate('top'), }; useSequenceBannerTextAlert(sequenceId); @@ -171,14 +171,8 @@ const Sequence = ({ courseId, sequenceId, unitId, - onClickPrevious() { - logEvent('edx.ui.lms.sequence.previous_selected', 'bottom'); - handlePrevious(); - }, - onClickNext() { - logEvent('edx.ui.lms.sequence.next_selected', 'bottom'); - handleNext(); - }, + onClickPrevious: previousHandler('bottom'), + onClickNext: nextHandler('bottom'), }; const renderUnitNavigation = (isAtTop) => ( @@ -232,7 +226,7 @@ const Sequence = ({ {unitHasLoaded && ( )}