feat: update next unit button plugin for left sidebar navigation usage (#1578)

* feat: move unit next button slot to plugins folder

* feat: update unit navigation at top to use next unit plugin

* fix: remove 2u plugin specific code
This commit is contained in:
Kristin Aoki
2025-01-28 13:01:18 -05:00
committed by GitHub
parent 7865fadec2
commit 8823cfaa0a
11 changed files with 158 additions and 57 deletions

View File

@@ -9,7 +9,6 @@ import {
import { useIntl } from '@edx/frontend-platform/i18n';
import { useSelector } from 'react-redux';
import SequenceExamWrapper from '@edx/frontend-lib-special-exams';
import { useToggle } from '@openedx/paragon';
import PageLoading from '@src/generic/PageLoading';
import { useModel } from '@src/generic/model-store';
@@ -35,7 +34,6 @@ const Sequence = ({
previousSequenceHandler,
}) => {
const intl = useIntl();
const [isOpen, open, close] = useToggle();
const {
canAccessProctoredExams,
license,
@@ -145,6 +143,7 @@ const Sequence = ({
const renderUnitNavigation = (isAtTop) => (
<UnitNavigation
courseId={courseId}
sequenceId={sequenceId}
unitId={unitId}
isAtTop={isAtTop}
@@ -185,9 +184,6 @@ const Sequence = ({
{...{
nextSequenceHandler,
handleNavigate,
isOpen,
open,
close,
}}
/>
</div>

View File

@@ -1,9 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { breakpoints, useWindowSize } from '@openedx/paragon';
import classNames from 'classnames';
import { useIntl } from '@edx/frontend-platform/i18n';
import { PluginSlot } from '@openedx/frontend-plugin-framework';
import { useSelector } from 'react-redux';
import { LOADED } from '@src/constants';
@@ -15,7 +13,7 @@ import { useModel } from '../../../../generic/model-store';
import messages from './messages';
import PreviousButton from './generic/PreviousButton';
import NextButton from './generic/NextButton';
import { NextUnitTopNavTriggerSlot } from '../../../../plugin-slots/NextUnitTopNavTriggerSlot';
const SequenceNavigation = ({
unitId,
@@ -24,11 +22,6 @@ const SequenceNavigation = ({
onNavigate,
nextHandler,
previousHandler,
nextSequenceHandler,
handleNavigate,
isOpen,
open,
close,
}) => {
const intl = useIntl();
const sequence = useModel('sequences', sequenceId);
@@ -83,36 +76,28 @@ const SequenceNavigation = ({
);
const renderNextButton = () => {
let buttonText;
const { exitActive, exitText } = GetCourseExitNavigation(courseId, intl);
const buttonText = (isLastUnit && exitText) ? exitText : intl.formatMessage(messages.nextButton);
const disabled = isLastUnit && !exitActive;
if (isLastUnit && exitText) {
buttonText = exitText;
} else if (!shouldDisplayNotificationTriggerInSequence) {
buttonText = intl.formatMessage(messages.nextButton);
}
return navigationDisabledNextSequence || (
<PluginSlot
id="next_button_slot"
pluginProps={{
<NextUnitTopNavTriggerSlot
{...{
courseId,
disabled,
buttonText: shouldDisplayNotificationTriggerInSequence ? null : buttonText,
buttonText,
nextLink,
sequenceId,
unitId,
nextSequenceHandler,
handleNavigate,
isOpen,
open,
close,
onClickHandler: nextHandler,
variant: 'link',
buttonStyle: 'next-btn',
}}
>
<NextButton
variant="link"
buttonStyle="next-btn"
onClick={nextHandler}
nextLink={nextLink}
disabled={disabled}
buttonLabel={shouldDisplayNotificationTriggerInSequence ? null : buttonText}
/>
</PluginSlot>
/>
);
};
@@ -132,21 +117,11 @@ SequenceNavigation.propTypes = {
onNavigate: PropTypes.func.isRequired,
nextHandler: PropTypes.func.isRequired,
previousHandler: PropTypes.func.isRequired,
close: PropTypes.func,
open: PropTypes.func,
isOpen: PropTypes.bool,
handleNavigate: PropTypes.func,
nextSequenceHandler: PropTypes.func,
};
SequenceNavigation.defaultProps = {
className: null,
unitId: null,
close: null,
open: null,
isOpen: false,
handleNavigate: null,
nextSequenceHandler: null,
};
export default SequenceNavigation;

View File

@@ -1,7 +1,6 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import { useIntl } from '@edx/frontend-platform/i18n';
import { useSelector } from 'react-redux';
import { GetCourseExitNavigation } from '../../course-exit';
@@ -9,6 +8,7 @@ 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,
@@ -16,12 +16,12 @@ const UnitNavigation = ({
onClickPrevious,
onClickNext,
isAtTop,
courseId,
}) => {
const intl = useIntl();
const {
isFirstUnit, isLastUnit, nextLink, previousLink,
} = useSequenceNavigationMetadata(sequenceId, unitId);
const { courseId } = useSelector(state => state.courseware);
const renderPreviousButton = () => (
<PreviousButton
@@ -38,13 +38,33 @@ const UnitNavigation = ({
const { exitActive, exitText } = GetCourseExitNavigation(courseId, intl);
const buttonText = (isLastUnit && exitText) ? exitText : intl.formatMessage(messages.nextButton);
const disabled = isLastUnit && !exitActive;
const variant = 'outline-primary';
const buttonStyle = 'next-button justify-content-center';
if (isAtTop) {
return (
<NextUnitTopNavTriggerSlot
{...{
courseId,
variant,
buttonStyle,
buttonText,
disabled,
sequenceId,
nextLink,
onClickHandler: onClickNext,
}}
/>
);
}
return (
<NextButton
variant="outline-primary"
buttonStyle="next-button justify-content-center"
onClick={onClickNext}
variant={variant}
buttonStyle={buttonStyle}
onClickHandler={onClickNext}
disabled={disabled}
buttonLabel={buttonText}
buttonText={buttonText}
nextLink={nextLink}
hasEffortEstimate
/>
@@ -60,6 +80,7 @@ const UnitNavigation = ({
};
UnitNavigation.propTypes = {
courseId: PropTypes.string.isRequired,
sequenceId: PropTypes.string.isRequired,
unitId: PropTypes.string,
onClickPrevious: PropTypes.func.isRequired,

View File

@@ -18,6 +18,7 @@ describe('Unit Navigation', () => {
const store = await initializeTestStore({ courseMetadata, unitBlocks });
const { courseware } = store.getState();
mockData = {
courseId: courseware.courseId,
unitId: unitBlocks[1].id,
sequenceId: courseware.sequenceId,
onClickPrevious: () => {},

View File

@@ -7,8 +7,8 @@ import { isRtl, getLocale } from '@edx/frontend-platform/i18n';
import UnitNavigationEffortEstimate from '../UnitNavigationEffortEstimate';
const NextButton = ({
onClick,
buttonLabel,
onClickHandler,
buttonText,
nextLink,
variant,
buttonStyle,
@@ -20,16 +20,16 @@ const NextButton = ({
const navLink = pathname.startsWith('/preview') ? `/preview${nextLink}` : nextLink;
const buttonContent = hasEffortEstimate ? (
<UnitNavigationEffortEstimate>
{buttonLabel}
{buttonText}
</UnitNavigationEffortEstimate>
) : buttonLabel;
) : buttonText;
return (
<Button
variant={variant}
className={buttonStyle}
disabled={disabled}
onClick={onClick}
onClick={onClickHandler}
as={disabled ? undefined : Link}
to={disabled ? undefined : navLink}
iconAfter={nextArrow}
@@ -44,8 +44,8 @@ NextButton.defaultProps = {
};
NextButton.propTypes = {
onClick: PropTypes.func.isRequired,
buttonLabel: PropTypes.string.isRequired,
onClickHandler: PropTypes.func.isRequired,
buttonText: PropTypes.string.isRequired,
nextLink: PropTypes.string.isRequired,
variant: PropTypes.string.isRequired,
buttonStyle: PropTypes.string.isRequired,