Submit step challenge

This commit is contained in:
Berkeley Martinez
2016-06-08 18:48:30 -07:00
parent 8457db3319
commit c5aff0b16b
4 changed files with 78 additions and 51 deletions

View File

@ -5,29 +5,40 @@ import { createSelector } from 'reselect';
import PureComponent from 'react-pure-render/component'; import PureComponent from 'react-pure-render/component';
import ReactTransitionReplace from 'react-css-transition-replace'; import ReactTransitionReplace from 'react-css-transition-replace';
import { submitChallenge, goToStep } from '../../redux/actions'; import {
goToStep,
completeAction,
submitChallenge
} from '../../redux/actions';
import { challengeSelector } from '../../redux/selectors'; import { challengeSelector } from '../../redux/selectors';
import { Button, Col, Image, Row } from 'react-bootstrap'; import { Button, Col, Image, Row } from 'react-bootstrap';
const transitionTimeout = 1000; const transitionTimeout = 1000;
const mapStateToProps = createSelector( const mapStateToProps = createSelector(
challengeSelector, challengeSelector,
state => state.challengesApp.currentStep, state => state.challengesApp.currentIndex,
state => state.challengesApp.previousStep, state => state.challengesApp.previousIndex,
({ challenge }, currentStep, previousStep) => ({ state => state.challengesApp.isActionCompleted,
challenge, (
currentStep, {
previousStep, challenge: { description = [] }
numOfSteps: },
Array.isArray(challenge.description) ? currentIndex,
challenge.description.length : previousIndex,
0, isActionCompleted
isGoingForward: currentStep > previousStep ) => ({
currentIndex,
isActionCompleted,
step: description[currentIndex],
steps: description,
numOfSteps: description.length,
isGoingForward: currentIndex > previousIndex
}) })
); );
const dispatchActions = { const dispatchActions = {
goToStep, goToStep,
completeAction,
submitChallenge submitChallenge
}; };
@ -38,36 +49,37 @@ export class StepChallenge extends PureComponent {
this.handleBackClick = this.handleBackClick.bind(this); this.handleBackClick = this.handleBackClick.bind(this);
} }
static displayName = 'StepChallenge'; static displayName = 'StepChallenge';
static defaultProps = {
currentStep: 0,
previousStep: -1
};
static propTypes = { static propTypes = {
challenge: PropTypes.object, currentIndex: PropTypes.number,
currentStep: PropTypes.number, step: PropTypes.array,
previousStep: PropTypes.number, steps: PropTypes.array,
isActionCompleted: PropTypes.bool,
isGoingForward: PropTypes.bool, isGoingForward: PropTypes.bool,
numOfSteps: PropTypes.number,
goToStep: PropTypes.func, goToStep: PropTypes.func,
submitChallenge: PropTypes.func, completeAction: PropTypes.func,
numOfSteps: PropTypes.number submitChallenge: PropTypes.func
}; };
handleNextClick() { handleNextClick() {
const { numOfSteps, currentStep, submitChallenge, goToStep } = this.props; const { numOfSteps, currentIndex, submitChallenge, goToStep } = this.props;
const isLastStep = currentStep + 1 >= numOfSteps; const isLastStep = currentIndex + 1 >= numOfSteps;
if (isLastStep) { if (isLastStep) {
return submitChallenge(); return submitChallenge();
} }
return goToStep(currentStep + 1); return goToStep(currentIndex + 1);
} }
handleBackClick() { handleBackClick() {
const { currentStep, goToStep } = this.props; const { currentIndex, goToStep } = this.props;
goToStep(currentStep - 1); goToStep(currentIndex - 1);
} }
renderActionButton(action) { renderActionButton(action, completeAction) {
const isApiAction = action === '#';
const buttonCopy = isApiAction ?
'Confirm' :
'Open link in new tab ';
if (!action) { if (!action) {
return null; return null;
} }
@ -78,9 +90,10 @@ export class StepChallenge extends PureComponent {
bsSize='large' bsSize='large'
bsStyle='primary' bsStyle='primary'
href={ action } href={ action }
onClick={ completeAction }
target='_blank' target='_blank'
> >
Open link in new tab (this unlocks the next step) { buttonCopy } (this unlocks the next step)
</Button> </Button>
<div className='spacer' /> <div className='spacer' />
</div> </div>
@ -121,6 +134,7 @@ export class StepChallenge extends PureComponent {
bsSize='large' bsSize='large'
bsStyle='primary' bsStyle='primary'
className={ btnClass } className={ btnClass }
disabled={ hasAction && !isCompleted }
onClick={ this.handleNextClick } onClick={ this.handleNextClick }
> >
{ isLastStep ? 'Finish challenge' : 'Go to my next step'} { isLastStep ? 'Finish challenge' : 'Go to my next step'}
@ -128,7 +142,13 @@ export class StepChallenge extends PureComponent {
); );
} }
renderStep(step, currentStep, numOfSteps) { renderStep({
step,
currentIndex,
numOfSteps,
isActionCompleted,
completeAction
}) {
if (!Array.isArray(step)) { if (!Array.isArray(step)) {
return null; return null;
} }
@ -162,21 +182,21 @@ export class StepChallenge extends PureComponent {
</Row> </Row>
<div className='spacer' /> <div className='spacer' />
<div className='challenge-button-block'> <div className='challenge-button-block'>
{ this.renderActionButton(action) } { this.renderActionButton(action, completeAction) }
{ this.renderBackButton(currentStep) } { this.renderBackButton(currentIndex) }
<Col <Col
className='challenge-step-counter large-p text-center' className='challenge-step-counter large-p text-center'
sm={ 4 } sm={ 4 }
xs={ 12 } xs={ 12 }
> >
( { currentStep + 1 } / { numOfSteps }) ( { currentIndex + 1 } / { numOfSteps })
</Col> </Col>
{ {
this.renderNextButton( this.renderNextButton(
!!action, !!action,
currentStep, currentIndex,
numOfSteps, numOfSteps,
true isActionCompleted
) )
} }
</div> </div>
@ -202,16 +222,9 @@ export class StepChallenge extends PureComponent {
} }
render() { render() {
const { const { steps, isGoingForward } = this.props;
numOfSteps,
challenge,
currentStep,
isGoingForward
} = this.props;
const step = challenge.description[currentStep];
const transitionName = 'challenge-step-' + const transitionName = 'challenge-step-' +
(isGoingForward ? 'forward' : 'backward'); (isGoingForward ? 'forward' : 'backward');
return ( return (
<Col <Col
md={ 8 } md={ 8 }
@ -222,10 +235,10 @@ export class StepChallenge extends PureComponent {
transitionLeaveTimeout={ transitionTimeout } transitionLeaveTimeout={ transitionTimeout }
transitionName={ transitionName } transitionName={ transitionName }
> >
{ this.renderStep(step, currentStep, numOfSteps) } { this.renderStep(this.props) }
</ReactTransitionReplace> </ReactTransitionReplace>
<div className='hidden'> <div className='hidden'>
{ this.renderImages(challenge.description) } { this.renderImages(steps) }
</div> </div>
<div className='spacer' /> <div className='spacer' />
</Col> </Col>

View File

@ -6,7 +6,7 @@ import types from './types';
// step // step
export const goToStep = createAction(types.goToStep); export const goToStep = createAction(types.goToStep);
export const completeAction = createAction(types.completeAction);
// challenges // challenges
export const fetchChallenge = createAction(types.fetchChallenge); export const fetchChallenge = createAction(types.fetchChallenge);

View File

@ -15,11 +15,16 @@ const initialState = {
id: '', id: '',
challenge: '', challenge: '',
legacyKey: '', legacyKey: '',
currentStep: 0, // step
previousStep: -1, currentIndex: 0,
previousIndex: -1,
isActionCompleted: false,
// map
filter: '', filter: '',
files: {},
superBlocks: [], superBlocks: [],
// modern
files: {},
// misc
toast: 0 toast: 0
}; };
@ -73,9 +78,17 @@ const mainReducer = handleActions(
[types.resetStep]: () => initialState, [types.resetStep]: () => initialState,
[types.goToStep]: (state, { payload: step = 0 }) => ({ [types.goToStep]: (state, { payload: step = 0 }) => ({
...state, ...state,
currentStep: step, currentIndex: step,
previousStep: state.currentStep previousIndex: state.currentIndex,
isActionCompleted: false
}), }),
[types.completeAction]: state => ({
...state,
isActionCompleted: true
}),
// classic/modern
[types.initOutput]: (state, { payload: output }) => ({ [types.initOutput]: (state, { payload: output }) => ({
...state, ...state,
output output

View File

@ -3,6 +3,7 @@ import createTypes from '../../../utils/create-types';
export default createTypes([ export default createTypes([
// step // step
'goToStep', 'goToStep',
'completeAction',
// challenges // challenges
'fetchChallenge', 'fetchChallenge',