diff --git a/common/app/routes/challenges/components/Challenge.jsx b/common/app/routes/challenges/components/Challenge.jsx index d4421ef7c2..331d7b426e 100644 --- a/common/app/routes/challenges/components/Challenge.jsx +++ b/common/app/routes/challenges/components/Challenge.jsx @@ -1,13 +1,26 @@ import React, { PropTypes } from 'react'; - -import PureComponent from 'react-pure-render/component'; +import { connect } from 'react-redux'; import { Col } from 'react-bootstrap'; +import { createSelector } from 'reselect'; +import PureComponent from 'react-pure-render/component'; import Editor from './Editor.jsx'; import SidePanel from './Side-Panel.jsx'; import Preview from './Preview.jsx'; +import { challengeSelector } from '../redux/selectors'; -export default class extends PureComponent { +const mapStateToProps = createSelector( + challengeSelector, + state => state.challengesApp.content, + ({ challenge, showPreview, mode }, content) => ({ + content, + challenge, + showPreview, + mode + }) +); + +export class Challenge extends PureComponent { static displayName = 'Challenge'; static propTypes = { @@ -54,3 +67,5 @@ export default class extends PureComponent { ); } } + +export default connect(mapStateToProps)(Challenge); diff --git a/common/app/routes/challenges/components/Challenges.jsx b/common/app/routes/challenges/components/Challenges.jsx index 5f2fc05d7e..d4aaa384e1 100644 --- a/common/app/routes/challenges/components/Challenges.jsx +++ b/common/app/routes/challenges/components/Challenges.jsx @@ -8,35 +8,16 @@ import PureComponent from 'react-pure-render/component'; import Challenge from './Challenge.jsx'; import Step from './step/Step.jsx'; import { fetchChallenge } from '../../../redux/actions'; -import { STEP, HTML } from '../../../utils/challengeTypes'; +import { challengeSelector } from '../redux/selectors'; const bindableActions = { fetchChallenge }; -const challengeSelector = createSelector( - state => state.challengesApp.challenge, - state => state.entities.challenge, - (challengeName, challengeMap) => { - const challenge = challengeMap[challengeName]; - return { - challenge: challenge, - showPreview: !!challenge && challenge.challengeType === HTML, - isStep: !!challenge && challenge.challengeType === STEP, - mode: !!challenge && challenge.challengeType === HTML ? - 'text/html' : - 'javascript' - }; - } -); - const mapStateToProps = createSelector( challengeSelector, - state => state.challengesApp.content, - (challengeProps, content) => ({ - ...challengeProps, - content - }) + state => state.challengesApp.challenge, + ({ isStep }, challenge) => ({ challenge, isStep }) ); const fetchOptions = { @@ -45,24 +26,19 @@ const fetchOptions = { return [ dashedName ]; }, isPrimed({ challenge }) { - return challenge; + return !!challenge; } }; export class Challenges extends PureComponent { static displayName = 'Challenges'; - static propTypes = { - challenge: PropTypes.object, - showPreview: PropTypes.bool, - mode: PropTypes.string, - isStep: PropTypes.bool - }; + static propTypes = { isStep: PropTypes.bool }; render() { if (this.props.isStep) { - return ; + return ; } - return ; + return ; } } diff --git a/common/app/routes/challenges/components/step/Step.jsx b/common/app/routes/challenges/components/step/Step.jsx index 9941d486db..6d95f413cc 100644 --- a/common/app/routes/challenges/components/step/Step.jsx +++ b/common/app/routes/challenges/components/step/Step.jsx @@ -2,17 +2,20 @@ import React, { PropTypes } from 'react'; import classnames from 'classnames'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import { goToStep } from '../../redux/actions'; import PureComponent from 'react-pure-render/component'; import ReactTransitionReplace from 'react-css-transition-replace'; +import { goToStep } from '../../redux/actions'; +import { challengeSelector } from '../../redux/selectors'; import { Button, Col, Image, Row } from 'react-bootstrap'; const transitionTimeout = 1000; const mapStateToProps = createSelector( + challengeSelector, state => state.challengesApp.currentStep, state => state.challengesApp.previousStep, - (currentStep, previousStep) => ({ + ({ challenge }, currentStep, previousStep) => ({ + challenge, currentStep, previousStep, isGoingForward: currentStep > previousStep diff --git a/common/app/routes/challenges/redux/selectors.js b/common/app/routes/challenges/redux/selectors.js new file mode 100644 index 0000000000..b248c64e5b --- /dev/null +++ b/common/app/routes/challenges/redux/selectors.js @@ -0,0 +1,21 @@ +import { STEP, HTML } from '../../../utils/challengeTypes'; +import { createSelector } from 'reselect'; + +export const challengeSelector = createSelector( + state => state.challengesApp.challenge, + state => state.entities.challenge, + (challengeName, challengeMap) => { + if (!challengeName || !challengeMap) { + return {}; + } + const challenge = challengeMap[challengeName]; + return { + challenge: challenge, + showPreview: !!challenge && challenge.challengeType === HTML, + isStep: !!challenge && challenge.challengeType === STEP, + mode: !!challenge && challenge.challengeType === HTML ? + 'text/html' : + 'javascript' + }; + } +);