Refactor containers to share more code (#61)

Specifically, make sure that the header, footer, and tabs are all
shared code so that they look the same and don't need to be
redefined as we add more tab pages.
This commit is contained in:
Michael Terry
2020-05-21 11:56:49 -04:00
committed by GitHub
parent 589db9356e
commit 2f01e8a646
19 changed files with 290 additions and 241 deletions

View File

@@ -4,6 +4,7 @@ import { useSelector, useDispatch } from 'react-redux';
import { history } from '@edx/frontend-platform';
import { getLocale } from '@edx/frontend-platform/i18n';
import { useRouteMatch, Redirect } from 'react-router';
import {
fetchCourse,
fetchSequence,
@@ -14,9 +15,9 @@ import {
saveSequencePosition,
} from './data/thunks';
import { useModel } from '../model-store';
import { TabPage } from '../tab-page';
import Course from './course';
import { sequenceIdsSelector, firstSequenceIdSelector } from './data/selectors';
function useUnitNavigationHandler(courseId, sequenceId, unitId) {
@@ -200,7 +201,10 @@ export default function CoursewareContainer() {
}
return (
<main className="flex-grow-1 d-flex flex-column">
<TabPage
activeTabSlug="courseware"
courseId={courseId}
>
<Course
courseId={courseId}
sequenceId={sequenceId}
@@ -209,7 +213,7 @@ export default function CoursewareContainer() {
previousSequenceHandler={previousSequenceHandler}
unitNavigationHandler={unitNavigationHandler}
/>
</main>
</TabPage>
);
}

View File

@@ -1,23 +1,15 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { useSelector } from 'react-redux';
import { AlertList } from '../../user-messages';
import { useAccessExpirationAlert } from '../../access-expiration-alert';
import { useLogistrationAlert } from '../../logistration-alert';
import { useEnrollmentAlert } from '../../enrollment-alert';
import { useOfferAlert } from '../../offer-alert';
import PageLoading from '../../PageLoading';
import InstructorToolbar from './InstructorToolbar';
import Sequence from './sequence';
import CourseBreadcrumbs from './CourseBreadcrumbs';
import { Header, CourseTabsNavigation } from '../../course-header';
import CourseSock from './course-sock';
import ContentTools from './tools/ContentTools';
import messages from './messages';
import { useModel } from '../../model-store';
// Note that we import from the component files themselves in the enrollment-alert package.
@@ -37,90 +29,53 @@ function Course({
nextSequenceHandler,
previousSequenceHandler,
unitNavigationHandler,
intl,
}) {
const course = useModel('courses', courseId);
const sequence = useModel('sequences', sequenceId);
const section = useModel('sections', sequence ? sequence.sectionId : null);
useOfferAlert(courseId);
useLogistrationAlert();
useEnrollmentAlert(courseId);
useAccessExpirationAlert(courseId);
const courseStatus = useSelector(state => state.courseware.courseStatus);
const {
canShowUpgradeSock,
verifiedMode,
} = course;
if (courseStatus === 'loading') {
return (
<PageLoading
srMessage={intl.formatMessage(messages['learn.loading.learning.sequence'])}
/>
);
}
if (courseStatus === 'loaded') {
const {
canShowUpgradeSock,
org, number, title, isStaff, tabs, verifiedMode,
} = course;
return (
<>
<Header
courseOrg={org}
courseNumber={number}
courseTitle={title}
/>
{isStaff && (
<InstructorToolbar
courseId={courseId}
unitId={unitId}
/>
)}
<CourseTabsNavigation tabs={tabs} activeTabSlug="courseware" />
<div className="container-fluid">
<AlertList
className="my-3"
topic="course"
customAlerts={{
clientEnrollmentAlert: EnrollmentAlert,
clientStaffEnrollmentAlert: StaffEnrollmentAlert,
clientLogistrationAlert: LogistrationAlert,
clientAccessExpirationAlert: AccessExpirationAlert,
clientOfferAlert: OfferAlert,
}}
// courseId is provided because EnrollmentAlert and StaffEnrollmentAlert require it.
customProps={{
courseId,
}}
/>
<CourseBreadcrumbs
courseId={courseId}
sectionId={section ? section.id : null}
sequenceId={sequenceId}
/>
<AlertList topic="sequence" />
</div>
<div className="flex-grow-1 d-flex flex-column">
<Sequence
unitId={unitId}
sequenceId={sequenceId}
courseId={courseId}
unitNavigationHandler={unitNavigationHandler}
nextSequenceHandler={nextSequenceHandler}
previousSequenceHandler={previousSequenceHandler}
/>
{canShowUpgradeSock && verifiedMode && <CourseSock verifiedMode={verifiedMode} />}
<ContentTools course={course} />
</div>
</>
);
}
// courseStatus 'failed' and any other unexpected course status.
return (
<p className="text-center py-5 mx-auto" style={{ maxWidth: '30em' }}>
{intl.formatMessage(messages['learn.course.load.failure'])}
</p>
<>
<AlertList
className="my-3"
topic="course"
customAlerts={{
clientEnrollmentAlert: EnrollmentAlert,
clientStaffEnrollmentAlert: StaffEnrollmentAlert,
clientLogistrationAlert: LogistrationAlert,
clientAccessExpirationAlert: AccessExpirationAlert,
clientOfferAlert: OfferAlert,
}}
// courseId is provided because EnrollmentAlert and StaffEnrollmentAlert require it.
customProps={{
courseId,
}}
/>
<CourseBreadcrumbs
courseId={courseId}
sectionId={section ? section.id : null}
sequenceId={sequenceId}
/>
<AlertList topic="sequence" />
<Sequence
unitId={unitId}
sequenceId={sequenceId}
courseId={courseId}
unitNavigationHandler={unitNavigationHandler}
nextSequenceHandler={nextSequenceHandler}
previousSequenceHandler={previousSequenceHandler}
/>
{canShowUpgradeSock && verifiedMode && <CourseSock verifiedMode={verifiedMode} />}
<ContentTools course={course} />
</>
);
}
@@ -131,7 +86,6 @@ Course.propTypes = {
nextSequenceHandler: PropTypes.func.isRequired,
previousSequenceHandler: PropTypes.func.isRequired,
unitNavigationHandler: PropTypes.func.isRequired,
intl: intlShape.isRequired,
};
Course.defaultProps = {
@@ -140,4 +94,4 @@ Course.defaultProps = {
unitId: null,
};
export default injectIntl(Course);
export default Course;

View File

@@ -1,16 +0,0 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'learn.loading.learning.sequence': {
id: 'learn.loading.learning.sequence',
defaultMessage: 'Loading learning sequence...',
description: 'Message when learning sequence is being loaded',
},
'learn.course.load.failure': {
id: 'learn.course.load.failure',
defaultMessage: 'There was an error loading this course.',
description: 'Message when a course fails to load',
},
});
export default messages;