Submit step challenge
This commit is contained in:
@ -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>
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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',
|
||||||
|
Reference in New Issue
Block a user