Allow loading with no unit, and of sequences with no unitIds. (#34)
This requires some defensive programming here and there to let things load in a minimal state.
This commit is contained in:
@@ -55,7 +55,7 @@ function Sequence({
|
||||
const logEvent = (eventName, widgetPlacement, targetUnitId) => {
|
||||
// Note: tabs are tracked with a 1-indexed position
|
||||
// as opposed to a 0-index used throughout this MFE
|
||||
const currentIndex = sequence.unitIds.indexOf(unitId);
|
||||
const currentIndex = sequence.unitIds.length > 0 ? sequence.unitIds.indexOf(unitId) : 0;
|
||||
const payload = {
|
||||
current_tab: currentIndex + 1,
|
||||
id: unitId,
|
||||
@@ -110,7 +110,7 @@ function Sequence({
|
||||
|
||||
const gated = sequence.gatedContent !== undefined && sequence.gatedContent.gated;
|
||||
|
||||
if (sequenceStatus === 'loaded' && unit) {
|
||||
if (sequenceStatus === 'loaded') {
|
||||
return (
|
||||
<div className="sequence">
|
||||
<SequenceNavigation
|
||||
@@ -147,7 +147,7 @@ function Sequence({
|
||||
/>
|
||||
</Suspense>
|
||||
)}
|
||||
{!gated && (
|
||||
{!gated && unitId !== null && (
|
||||
<Unit
|
||||
key={unitId}
|
||||
id={unitId}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { useSelector } from 'react-redux';
|
||||
import UnitButton from './UnitButton';
|
||||
import SequenceNavigationTabs from './SequenceNavigationTabs';
|
||||
import { useSequenceNavigationMetadata } from './hooks';
|
||||
@@ -22,8 +23,30 @@ export default function SequenceNavigation({
|
||||
const sequence = useModel('sequences', sequenceId);
|
||||
const { isFirstUnit, isLastUnit } = useSequenceNavigationMetadata(sequenceId, unitId);
|
||||
const isLocked = sequence.gatedContent !== undefined && sequence.gatedContent.gated;
|
||||
const sequenceStatus = useSelector(state => state.courseware.sequenceStatus);
|
||||
|
||||
return (
|
||||
const renderUnitButtons = () => {
|
||||
if (isLocked) {
|
||||
return (
|
||||
<UnitButton unitId={unitId} title="" contentType="lock" isActive onClick={() => {}} />
|
||||
);
|
||||
}
|
||||
if (sequence.unitIds.length === 0 || unitId === null) {
|
||||
return (
|
||||
<div style={{ flexBasis: '100%', minWidth: 0, borderBottom: 'solid 1px #EAEAEA' }} />
|
||||
);
|
||||
}
|
||||
return (
|
||||
<SequenceNavigationTabs
|
||||
unitIds={sequence.unitIds}
|
||||
unitId={unitId}
|
||||
showCompletion={sequence.showCompletion}
|
||||
onNavigate={onNavigate}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return sequenceStatus === 'loaded' && (
|
||||
<nav className={classNames('sequence-navigation', className)}>
|
||||
<Button className="previous-btn" onClick={previousSequenceHandler} disabled={isFirstUnit}>
|
||||
<FontAwesomeIcon icon={faChevronLeft} className="mr-2" size="sm" />
|
||||
@@ -33,16 +56,7 @@ export default function SequenceNavigation({
|
||||
description="The Previous button in the sequence nav"
|
||||
/>
|
||||
</Button>
|
||||
|
||||
{isLocked ? <UnitButton unitId={unitId} title="" contentType="lock" isActive onClick={() => {}} /> : (
|
||||
<SequenceNavigationTabs
|
||||
unitIds={sequence.unitIds}
|
||||
unitId={unitId}
|
||||
showCompletion={sequence.showCompletion}
|
||||
onNavigate={onNavigate}
|
||||
/>
|
||||
)}
|
||||
|
||||
{renderUnitButtons()}
|
||||
<Button className="next-btn" onClick={nextSequenceHandler} disabled={isLastUnit}>
|
||||
<FormattedMessage
|
||||
defaultMessage="Next"
|
||||
@@ -56,8 +70,8 @@ export default function SequenceNavigation({
|
||||
}
|
||||
|
||||
SequenceNavigation.propTypes = {
|
||||
unitId: PropTypes.string.isRequired,
|
||||
sequenceId: PropTypes.string.isRequired,
|
||||
unitId: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
onNavigate: PropTypes.func.isRequired,
|
||||
nextSequenceHandler: PropTypes.func.isRequired,
|
||||
@@ -66,4 +80,5 @@ SequenceNavigation.propTypes = {
|
||||
|
||||
SequenceNavigation.defaultProps = {
|
||||
className: null,
|
||||
unitId: null,
|
||||
};
|
||||
|
||||
@@ -41,14 +41,14 @@ function normalizeBlocks(courseUsageKey, blocks) {
|
||||
models.courses[block.id] = {
|
||||
id: courseUsageKey,
|
||||
title: block.display_name,
|
||||
sectionIds: block.children,
|
||||
sectionIds: block.children || [],
|
||||
};
|
||||
break;
|
||||
case 'chapter':
|
||||
models.sections[block.id] = {
|
||||
id: block.id,
|
||||
title: block.display_name,
|
||||
sequenceIds: block.children,
|
||||
sequenceIds: block.children || [],
|
||||
};
|
||||
break;
|
||||
|
||||
@@ -57,7 +57,7 @@ function normalizeBlocks(courseUsageKey, blocks) {
|
||||
id: block.id,
|
||||
title: block.display_name,
|
||||
lmsWebUrl: block.lms_web_url,
|
||||
unitIds: block.children,
|
||||
unitIds: block.children || [],
|
||||
};
|
||||
break;
|
||||
case 'vertical':
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
getSequenceMetadata,
|
||||
} from './api';
|
||||
import {
|
||||
addModelsMap, updateModel, updateModels,
|
||||
addModelsMap, updateModel, updateModels, updateModelsMap,
|
||||
} from '../model-store';
|
||||
import {
|
||||
fetchCourseRequest,
|
||||
@@ -40,11 +40,12 @@ export function fetchCourse(courseUsageKey) {
|
||||
modelType: 'sections',
|
||||
modelsMap: sections,
|
||||
}));
|
||||
dispatch(addModelsMap({
|
||||
// We update for sequences and units because the sequence metadata may have come back first.
|
||||
dispatch(updateModelsMap({
|
||||
modelType: 'sequences',
|
||||
modelsMap: sequences,
|
||||
}));
|
||||
dispatch(addModelsMap({
|
||||
dispatch(updateModelsMap({
|
||||
modelType: 'units',
|
||||
modelsMap: units,
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user