Skip to content

Instantly share code, notes, and snippets.

@possibilities
Created January 15, 2016 19:55
Embed
What would you like to do?
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