-
-
Save possibilities/fdd986f2d739d3aad82a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/package.json b/package.json | |
index d66584f..8b008b6 100644 | |
--- a/package.json | |
+++ b/package.json | |
@@ -69,6 +69,7 @@ | |
"karma-sinon": "1.0.4", | |
"karma-spec-reporter": "0.0.23", | |
"karma-webpack": "1.7.0", | |
+ "lodash.pick": "4.0.0", | |
"mocha": "2.3.4", | |
"phantomjs": "1.9.19", | |
"raf": "3.1.0", | |
diff --git a/src/components/AuthorLayout.js b/src/components/AuthorLayout.js | |
index 381ccdf..b33223a 100644 | |
--- a/src/components/AuthorLayout.js | |
+++ b/src/components/AuthorLayout.js | |
@@ -3,7 +3,7 @@ import { connect } from 'react-redux' | |
import Header from 'components/Header' | |
import EditableTableOfContents from './EditableTableOfContents' | |
import EditableLesson from './EditableLesson' | |
-import Footer from './Footer' | |
+import Footer from '../containers/Footer' | |
import GadgetTray from './GadgetTray' | |
import FinishCourse from './FinishCourse' | |
import GlassOverlay from './GlassOverlay' | |
@@ -13,7 +13,7 @@ import SelectionToolbar from 'components/SelectionToolbar' | |
import { activateGadget, editGadget } from '../actions/author' | |
import prefix from 'modules/prefixStyles' | |
-import { toolbarStyle, showToCToggleButton } from '../modules/calculateLayout' | |
+import { toolbarStyle } from '../modules/calculateLayout' | |
import { HEADER_HEIGHT, FOOTER_HEIGHT, TRAY_HEIGHT, SIDEBAR_WIDTH, DESKTOP_SCREEN_WIDTH, PHONE_SCREEN_WIDTH } from 'constants/layout' | |
import pureRender from 'pure-render-decorator' | |
@@ -47,8 +47,6 @@ export default class AuthoringLayout extends React.Component { | |
course: PropTypes.object, | |
isCourseEditable: PropTypes.bool, | |
isMobile: PropTypes.bool, | |
- nextLesson: PropTypes.object, | |
- prevLesson: PropTypes.object, | |
activeLesson: PropTypes.object, | |
routerState: PropTypes.object, | |
finishCourse: PropTypes.func.isRequired, | |
@@ -168,33 +166,11 @@ export default class AuthoringLayout extends React.Component { | |
} | |
renderFooter() { | |
- const { nextLesson, prevLesson, windowWidth, layoutOptions, isCourseEditable } = this.props | |
- const isLastLesson = nextLesson === null | |
- const shouldShowToggleSidebarButton = showToCToggleButton(windowWidth, layoutOptions) | |
- | |
- return <Footer | |
- isCourseEditable={isCourseEditable} | |
- | |
- nextLesson={nextLesson} | |
- prevLesson={prevLesson} | |
- | |
- // Learning buttons | |
- shouldShowPrevLessonButton={!!prevLesson && !shouldShowToggleSidebarButton} | |
- shouldShowNextLessonButton={!!nextLesson} | |
- shouldShowFinishCourseButton={isLastLesson} | |
- shouldShowToggleSidebarButton={shouldShowToggleSidebarButton} | |
- | |
- // Authoring buttons | |
- shouldShowToggleGadgetTrayButton={isCourseEditable} | |
- | |
- // Learning actions | |
- toggleSidebar={this.toggleSidebar} | |
- finishCourse={this.props.finishCourse} | |
- transitionToLesson={this.props.transitionToLesson} | |
- | |
- // Authoring actions | |
- toggleGadgetTray={this.toggleGadgetTray} | |
- /> | |
+ return ( | |
+ <Footer | |
+ toggleSidebar={this.toggleSidebar} | |
+ toggleGadgetTray={this.toggleGadgetTray} /> | |
+ ) | |
} | |
handleSidebarOverlayClick = (e) => { | |
diff --git a/src/components/CourseContainer.js b/src/components/CourseContainer.js | |
index 4dd701c..116bd36 100644 | |
--- a/src/components/CourseContainer.js | |
+++ b/src/components/CourseContainer.js | |
@@ -13,6 +13,7 @@ import WelcomePage from './WelcomePage' | |
import Placeholder from './Placeholder' | |
import pureRender from 'pure-render-decorator' | |
+import pick from 'lodash.pick' | |
function mapStateToProps(storeState) { | |
const { routerState, mode, windowWidth } = storeState | |
@@ -68,10 +69,23 @@ export default class CourseContainer extends React.Component { | |
const { course, courseId, isCourseEditable } = this.props | |
if(course && course.lessonIds) { | |
+ | |
+ const layoutProps = pick(this.props, [ | |
+ 'course', | |
+ 'isMobile', | |
+ 'layoutOptions', | |
+ 'isCourseEditable', | |
+ 'routerState', | |
+ 'activeLesson', | |
+ 'windowWidth', | |
+ 'finishCourse', | |
+ 'transitionToLesson' | |
+ ]) | |
+ | |
if(isCourseEditable) { | |
- return <AuthorLayout {...this.props} /> | |
+ return <AuthorLayout {...layoutProps} /> | |
} else { | |
- return <LearnerLayout {...this.props} /> | |
+ return <LearnerLayout {...layoutProps} /> | |
} | |
} | |
diff --git a/src/components/LearnerLayout.js b/src/components/LearnerLayout.js | |
index ab73002..3ec400d 100644 | |
--- a/src/components/LearnerLayout.js | |
+++ b/src/components/LearnerLayout.js | |
@@ -3,11 +3,11 @@ import StickyElement from 'components/StickyElement' | |
import Header from 'components/Header' | |
import TableOfContents from './TableOfContents' | |
import Lesson from './Lesson' | |
-import Footer from './Footer' | |
+import Footer from '../containers/Footer' | |
import FinishCourse from './FinishCourse' | |
import GlassOverlay from './GlassOverlay' | |
import Placeholder from './Placeholder' | |
-import { isHeaderSticky, isFooterSticky, lessonScrollOffsetY, showToCToggleButton } from '../modules/calculateLayout' | |
+import { isHeaderSticky, isFooterSticky, lessonScrollOffsetY } from '../modules/calculateLayout' | |
import { HEADER_HEIGHT, FOOTER_HEIGHT, SIDEBAR_WIDTH, DESKTOP_SCREEN_WIDTH, PHONE_SCREEN_WIDTH } from 'constants/layout' | |
import pureRender from 'pure-render-decorator' | |
@@ -34,8 +34,6 @@ export default class LearnerLayout extends React.Component { | |
course: PropTypes.object, | |
isMobile: PropTypes.bool, | |
- nextLesson: PropTypes.object, | |
- prevLesson: PropTypes.object, | |
activeLesson: PropTypes.object, | |
routerState: PropTypes.object, | |
finishCourse: PropTypes.func.isRequired, | |
@@ -154,34 +152,22 @@ export default class LearnerLayout extends React.Component { | |
} | |
renderFooter() { | |
- const { nextLesson, prevLesson, windowWidth, layoutOptions } = this.props | |
+ const { windowWidth, layoutOptions } = this.props | |
const { fixedSidebar } = layoutOptions | |
- const isLastLesson = nextLesson === null | |
const contentStyle = { | |
paddingLeft: fixedSidebar && (windowWidth > DESKTOP_SCREEN_WIDTH) ? SIDEBAR_WIDTH : 0 | |
} | |
- const shouldShowToggleSidebarButton = showToCToggleButton(windowWidth, layoutOptions) | |
- | |
- return <StickyElement | |
- height={FOOTER_HEIGHT} | |
- stickTo={{ bottom: 0, left: 0, right: 0, ...contentStyle }} | |
- isSticky={isFooterSticky(windowWidth, layoutOptions)} | |
- isPushedOffTheScreen={!this.state.isFooterExpanded}> | |
- | |
- <Footer | |
- nextLesson={nextLesson} | |
- prevLesson={prevLesson} | |
- | |
- shouldShowPrevLessonButton={!!prevLesson && !shouldShowToggleSidebarButton} | |
- shouldShowNextLessonButton={!!nextLesson} | |
- shouldShowFinishCourseButton={isLastLesson} | |
- shouldShowToggleSidebarButton={shouldShowToggleSidebarButton} | |
- | |
- toggleSidebar={this.toggleSidebar} | |
- finishCourse={this.props.finishCourse} | |
- transitionToLesson={this.props.transitionToLesson} | |
- /> | |
- </StickyElement> | |
+ | |
+ return ( | |
+ <StickyElement | |
+ height={FOOTER_HEIGHT} | |
+ stickTo={{ bottom: 0, left: 0, right: 0, ...contentStyle }} | |
+ isSticky={isFooterSticky(windowWidth, layoutOptions)} | |
+ isPushedOffTheScreen={!this.state.isFooterExpanded}> | |
+ | |
+ <Footer toggleSidebar={this.toggleSidebar} /> | |
+ </StickyElement> | |
+ ) | |
} | |
handleSidebarOverlayClick = (e) => { | |
diff --git a/src/components/ReduxApp.js b/src/components/ReduxApp.js | |
index 7d30879..8580b68 100644 | |
--- a/src/components/ReduxApp.js | |
+++ b/src/components/ReduxApp.js | |
@@ -43,9 +43,12 @@ export default class ReduxApp extends React.Component { | |
isMobile: false | |
} | |
- this.store = configureStore(props, { | |
- mode: props.initialMode | |
- }) | |
+ // Prepare initial store state | |
+ const { initialMode: mode, layoutOptions } = props | |
+ const config = { layoutOptions } | |
+ | |
+ // Create the store | |
+ this.store = configureStore(props, { mode, config }) | |
} | |
render() { | |
diff --git a/src/containers/Footer.js b/src/containers/Footer.js | |
new file mode 100644 | |
index 0000000..2ed7a6f | |
--- /dev/null | |
+++ b/src/containers/Footer.js | |
@@ -0,0 +1,48 @@ | |
+import React, { PropTypes } from 'react' | |
+import { bindActionCreators } from 'redux' | |
+import { connect } from 'react-redux' | |
+import Footer from '../components/Footer' | |
+import activeNextAndPrevLessons from '../modules/activeNextAndPrevLessons' | |
+import { finishCourse, transitionToLesson } from '../actions/index' | |
+import { showToCToggleButton } from '../modules/calculateLayout' | |
+import playerModes from '../constants/playerModes' | |
+ | |
+function mapStateToProps(storeState, ownProps) { | |
+ const { mode, windowWidth, config, routerState } = storeState | |
+ const { courseId } = routerState | |
+ const course = storeState.coursesById[courseId] | |
+ const isCourseEditable = mode === playerModes.AUTHORING && course && course.isEditable | |
+ | |
+ const { activeLesson, nextLesson, prevLesson } = activeNextAndPrevLessons(storeState) | |
+ const isLastLesson = nextLesson === null | |
+ const { layoutOptions } = config | |
+ const shouldShowToggleSidebarButton = showToCToggleButton(windowWidth, layoutOptions) | |
+ | |
+ const shouldShowPrevLessonButton = !!prevLesson && !shouldShowToggleSidebarButton | |
+ const shouldShowNextLessonButton = !!nextLesson | |
+ const shouldShowFinishCourseButton = isLastLesson | |
+ const shouldShowToggleGadgetTrayButton = isCourseEditable | |
+ | |
+ return { | |
+ ...ownProps, | |
+ isCourseEditable, | |
+ activeLesson, | |
+ nextLesson, | |
+ prevLesson, | |
+ windowWidth, | |
+ shouldShowPrevLessonButton, | |
+ shouldShowNextLessonButton, | |
+ shouldShowFinishCourseButton, | |
+ shouldShowToggleSidebarButton, | |
+ shouldShowToggleGadgetTrayButton | |
+ } | |
+} | |
+ | |
+function mapDispatchToProps(dispatch) { | |
+ return bindActionCreators({ | |
+ finishCourse, | |
+ transitionToLesson | |
+ }, dispatch) | |
+} | |
+ | |
+export default connect(mapStateToProps, mapDispatchToProps)(Footer) | |
diff --git a/src/reducers/__tests__/ReducersTest.js b/src/reducers/__tests__/ReducersTest.js | |
index 596f987..ac09e82 100644 | |
--- a/src/reducers/__tests__/ReducersTest.js | |
+++ b/src/reducers/__tests__/ReducersTest.js | |
@@ -1,6 +1,7 @@ | |
/* global describe, it */ | |
import { | |
+ config, | |
windowWidth, | |
routerState, | |
lessonScrollState, | |
@@ -549,3 +550,12 @@ describe('windowWidth', () => { | |
expect(windowWidth(null, action)).toEqual(100) | |
}) | |
}) | |
+ | |
+describe('config', () => { | |
+ | |
+ // Note: this test is pointless but highlights that the config | |
+ // is frozen after the store is initially created | |
+ it('returns its initial state forever', () => { | |
+ expect(config({}, {})).toEqual({}) | |
+ }) | |
+}) | |
diff --git a/src/reducers/index.js b/src/reducers/index.js | |
index 4f6fc5f..684b21a 100644 | |
--- a/src/reducers/index.js | |
+++ b/src/reducers/index.js | |
@@ -327,7 +327,15 @@ export function windowWidth(state = 0, action) { | |
return state | |
} | |
+// We only allow populating this at creation time | |
+export function config(state = {}) { | |
+ // NOTE: please don't alter this reducer to respond to any actions | |
+ return state | |
+} | |
+ | |
export default combineReducers({ | |
+ config, | |
+ windowWidth, | |
restApiConfig, | |
coursesById, | |
lessonsById, | |
@@ -346,6 +354,5 @@ export default combineReducers({ | |
globalConfirmation, | |
currentTray, | |
gadgetBundlesByTray, | |
- currentUser, | |
- windowWidth | |
+ currentUser | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment