Also allowing partially defined URLs - it will fill in the sub section or unit ID if it’s missing.
145 lines
3.8 KiB
JavaScript
145 lines
3.8 KiB
JavaScript
import React, { useCallback, useContext } from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import { history } from '@edx/frontend-platform';
|
|
import { Button } from '@edx/paragon';
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
import { faFilm, faBook, faPencilAlt, faTasks, faLock } from '@fortawesome/free-solid-svg-icons';
|
|
|
|
import { usePreviousUnit, useNextUnit, useCurrentSubSectionUnits, useCurrentUnit } from '../data/hooks';
|
|
import CourseStructureContext from '../CourseStructureContext';
|
|
import SubSectionMetadataContext from './SubSectionMetadataContext';
|
|
|
|
function UnitIcon({ type }) {
|
|
let icon = null;
|
|
switch (type) {
|
|
case 'video':
|
|
icon = faFilm;
|
|
break;
|
|
case 'other':
|
|
icon = faBook;
|
|
break;
|
|
case 'vertical':
|
|
icon = faTasks;
|
|
break;
|
|
case 'problem':
|
|
icon = faPencilAlt;
|
|
break;
|
|
case 'lock':
|
|
icon = faLock;
|
|
break;
|
|
default:
|
|
icon = faBook;
|
|
}
|
|
|
|
return (
|
|
<FontAwesomeIcon icon={icon} />
|
|
);
|
|
}
|
|
|
|
UnitIcon.propTypes = {
|
|
type: PropTypes.oneOf(['video', 'other', 'vertical', 'problem', 'lock']).isRequired,
|
|
};
|
|
|
|
export default function SubSectionNavigation() {
|
|
const { courseId, unitId } = useContext(CourseStructureContext);
|
|
const previousUnit = usePreviousUnit();
|
|
const nextUnit = useNextUnit();
|
|
|
|
const handlePreviousClick = useCallback(() => {
|
|
if (previousUnit) {
|
|
history.push(`/course/${courseId}/${previousUnit.parentId}/${previousUnit.id}`);
|
|
}
|
|
});
|
|
const handleNextClick = useCallback(() => {
|
|
if (nextUnit) {
|
|
history.push(`/course/${courseId}/${nextUnit.parentId}/${nextUnit.id}`);
|
|
}
|
|
});
|
|
|
|
const handleUnitClick = useCallback((unit) => {
|
|
history.push(`/course/${courseId}/${unit.parentId}/${unit.id}`);
|
|
});
|
|
|
|
if (!unitId) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<nav className="flex-grow-0 d-flex w-100 mb-3">
|
|
<Button
|
|
key="previous"
|
|
className="btn-outline-primary"
|
|
onClick={handlePreviousClick}
|
|
>
|
|
Previous
|
|
</Button>
|
|
<UnitNavigation clickHandler={handleUnitClick} />
|
|
<Button
|
|
key="next"
|
|
className="btn-outline-primary"
|
|
onClick={handleNextClick}
|
|
>
|
|
Next
|
|
</Button>
|
|
</nav>
|
|
);
|
|
}
|
|
|
|
function UnitNavigation({ clickHandler }) {
|
|
const currentUnit = useCurrentUnit();
|
|
const units = useCurrentSubSectionUnits();
|
|
const metadata = useContext(SubSectionMetadataContext);
|
|
|
|
const isGated = metadata.gatedContent.gated;
|
|
|
|
return (
|
|
<div className="btn-group ml-2 mr-2 flex-grow-1 d-flex" role="group">
|
|
{!isGated && units.map(unit => (
|
|
<UnitButton key={unit.id} unit={unit} disabled={unit.id === currentUnit.id} clickHandler={clickHandler} />
|
|
))}
|
|
{isGated && <UnitButton key={currentUnit.id} unit={currentUnit} disabled locked />}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
UnitNavigation.propTypes = {
|
|
clickHandler: PropTypes.func.isRequired,
|
|
};
|
|
|
|
function UnitButton({
|
|
unit, disabled, locked, clickHandler,
|
|
}) {
|
|
const { id, type } = unit;
|
|
const handleClick = useCallback(() => {
|
|
if (clickHandler !== null) {
|
|
clickHandler(unit);
|
|
}
|
|
}, [unit]);
|
|
|
|
return (
|
|
<Button
|
|
key={id}
|
|
className="btn-outline-secondary unit-button flex-grow-1"
|
|
onClick={handleClick}
|
|
disabled={disabled}
|
|
>
|
|
<UnitIcon type={locked ? 'lock' : type} />
|
|
</Button>
|
|
);
|
|
}
|
|
|
|
UnitButton.propTypes = {
|
|
unit: PropTypes.shape({
|
|
id: PropTypes.string.isRequired,
|
|
type: PropTypes.oneOf(['video', 'other', 'vertical', 'problem']).isRequired,
|
|
}).isRequired,
|
|
disabled: PropTypes.bool.isRequired, // Whether or not the button will function.
|
|
locked: PropTypes.bool, // Whether the unit is semantically "locked" and unnavigable.
|
|
clickHandler: PropTypes.func,
|
|
};
|
|
|
|
UnitButton.defaultProps = {
|
|
clickHandler: null,
|
|
locked: false,
|
|
};
|