Initial version of Course Home page (#20)

* refactor: Moving PageLoading up to the top

This way it can be used on both the courseware and outline pages.

* Adding index.js files to data directories, and PropTypes data shapes

- The course-blocks and course-meta data directories now have index files so their exports can be imported from that, rather than reaching into specific files in the directories.
- Also added “shapes” for use in React Components that use PropTypes for the course blocks data structure, and the course metadata data structure.

* Simplifying/refactoring CourseContainer rendering a bit.

* Adding course outline page.

This page is not complete.

- It contains the ‘outline’ itself with links to the Sequences in the course.
- It contains a very basic stab at displaying dates - they’re not even formatted.
- It shows logistration and enrollment alerts for anonymous and unenrolled users.

It does not include any other content in the right-hand sidebar.  It also doesn’t include a welcome message, or perhaps any number of other features on the page.  This is effectively an initial implementation for discovering how much data we’re missing from our APIs.  It should not be used as-is by any means.
This commit is contained in:
David Joy
2020-03-06 13:21:18 -05:00
committed by GitHub
parent 5a3597ac4b
commit 6ba8929c97
16 changed files with 415 additions and 37 deletions

View File

@@ -0,0 +1,20 @@
export {
getCourseBlocks,
getSequenceMetadata,
updateSequencePosition,
getBlockCompletion,
createBookmark,
deleteBookmark,
} from './api';
export {
reducer,
courseBlocksShape,
} from './slice';
export {
fetchCourseBlocks,
fetchSequenceMetadata,
checkBlockCompletion,
saveSequencePosition,
addBookmark,
removeBookmark,
} from './thunks';

View File

@@ -1,5 +1,6 @@
/* eslint-disable no-param-reassign */
import { createSlice } from '@reduxjs/toolkit';
import PropTypes from 'prop-types';
const blocksSlice = createSlice({
name: 'blocks',
@@ -132,3 +133,10 @@ export const {
} = blocksSlice.actions;
export const { reducer } = blocksSlice;
export const courseBlocksShape = PropTypes.objectOf(PropTypes.shape({
id: PropTypes.string.isRequired,
displayName: PropTypes.string.isRequired,
children: PropTypes.arrayOf(PropTypes.string),
parentId: PropTypes.string,
}));

View File

@@ -0,0 +1,6 @@
export { getCourseMetadata } from './api';
export {
reducer,
courseMetadataShape,
} from './slice';
export { fetchCourseMetadata } from './thunks';

View File

@@ -1,5 +1,6 @@
/* eslint-disable no-param-reassign */
import { createSlice } from '@reduxjs/toolkit';
import PropTypes from 'prop-types';
const courseMetaSlice = createSlice({
name: 'course-meta',
@@ -12,13 +13,33 @@ const courseMetaSlice = createSlice({
},
fetchCourseMetadataSuccess: (draftState, { payload }) => ({
fetchState: 'loaded',
/*
* NOTE: If you change the data saved here,
* update the courseMetadataShape below!
*/
// Course identifiers
name: payload.name,
number: payload.number,
org: payload.org,
tabs: payload.tabs,
userHasAccess: payload.userHasAccess,
// Enrollment dates
enrollmentStart: payload.enrollmentStart,
enrollmentEnd: payload.enrollmentEnd,
// Course dates
end: payload.end,
start: payload.start,
// User access/enrollment status
enrollmentMode: payload.enrollment.mode,
isEnrolled: payload.enrollment.isActive,
userHasAccess: payload.userHasAccess,
verifiedMode: payload.verifiedMode,
// Misc
tabs: payload.tabs,
}),
fetchCourseMetadataFailure: (draftState) => {
draftState.fetchState = 'failed';
@@ -33,3 +54,40 @@ export const {
} = courseMetaSlice.actions;
export const { reducer } = courseMetaSlice;
export const courseMetadataShape = PropTypes.shape({
fetchState: PropTypes.string,
// Course identifiers
name: PropTypes.string,
number: PropTypes.string,
org: PropTypes.string,
// Enrollment dates
enrollmentStart: PropTypes.string,
enrollmentEnd: PropTypes.string,
// User access/enrollment status
enrollmentMode: PropTypes.string,
isEnrolled: PropTypes.bool,
userHasAccess: PropTypes.bool,
verifiedMode: PropTypes.shape({
price: PropTypes.number.isRequired,
currency: PropTypes.string.isRequired,
currencySymbol: PropTypes.string.isRequired,
sku: PropTypes.string.isRequired,
upgradeUrl: PropTypes.string.isRequired,
}),
// Course dates
start: PropTypes.string,
end: PropTypes.string,
// Misc
tabs: PropTypes.arrayOf(PropTypes.shape({
priority: PropTypes.number,
slug: PropTypes.string,
title: PropTypes.string,
type: PropTypes.string,
url: PropTypes.string,
})),
});