Use release to indicate answer attempt
This commit is contained in:
@ -9,7 +9,7 @@ import {
|
||||
Row
|
||||
} from 'react-bootstrap';
|
||||
|
||||
const ANSWER_THRESHOLD = 200;
|
||||
const answerThreshold = 200;
|
||||
|
||||
export default contain(
|
||||
{
|
||||
@ -35,7 +35,7 @@ export default contain(
|
||||
isPressed,
|
||||
showInfo,
|
||||
shake,
|
||||
username
|
||||
isSignedIn: !!username
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -51,56 +51,46 @@ export default contain(
|
||||
isPressed: PropTypes.bool,
|
||||
showInfo: PropTypes.bool,
|
||||
shake: PropTypes.bool,
|
||||
username: PropTypes.string,
|
||||
isSignedIn: PropTypes.bool,
|
||||
hikesActions: PropTypes.object
|
||||
},
|
||||
|
||||
handleMouseDown({ pageX, pageY, touches }) {
|
||||
if (touches) {
|
||||
({ pageX, pageY } = touches[0]);
|
||||
}
|
||||
const { mouse: [pressX, pressY], hikesActions } = this.props;
|
||||
hikesActions.grabQuestion({ pressX, pressY, pageX, pageY });
|
||||
},
|
||||
|
||||
handleMouseUp() {
|
||||
handleMouseUp(e, answer) {
|
||||
e.stopPropagation();
|
||||
if (!this.props.isPressed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
hike,
|
||||
currentQuestion,
|
||||
isSignedIn,
|
||||
delta
|
||||
} = this.props;
|
||||
|
||||
this.props.hikesActions.releaseQuestion();
|
||||
this.props.hikesActions.answer({
|
||||
e,
|
||||
answer,
|
||||
hike,
|
||||
delta,
|
||||
currentQuestion,
|
||||
isSignedIn,
|
||||
threshold: answerThreshold
|
||||
});
|
||||
},
|
||||
|
||||
handleMouseMove(answer) {
|
||||
handleMouseMove(e) {
|
||||
if (!this.props.isPressed) {
|
||||
return () => {};
|
||||
return null;
|
||||
}
|
||||
const { delta, hikesActions } = this.props;
|
||||
|
||||
return (e) => {
|
||||
let { pageX, pageY, touches } = e;
|
||||
|
||||
if (touches) {
|
||||
e.preventDefault();
|
||||
// these re-assigns the values of pageX, pageY from touches
|
||||
({ pageX, pageY } = touches[0]);
|
||||
}
|
||||
|
||||
const { delta: [dx, dy], hikesActions } = this.props;
|
||||
const mouse = [pageX - dx, pageY - dy];
|
||||
|
||||
if (mouse[0] >= ANSWER_THRESHOLD) {
|
||||
return this.onAnswer(answer, true)();
|
||||
}
|
||||
|
||||
if (mouse[0] <= -ANSWER_THRESHOLD) {
|
||||
return this.onAnswer(answer, false)();
|
||||
}
|
||||
|
||||
return hikesActions.moveQuestion(mouse);
|
||||
};
|
||||
hikesActions.moveQuestion({ e, delta });
|
||||
},
|
||||
|
||||
onAnswer(answer, userAnswer) {
|
||||
const { hikesActions } = this.props;
|
||||
const { isSignedIn, hike, hikesActions } = this.props;
|
||||
return (e) => {
|
||||
if (e && e.preventDefault) {
|
||||
e.preventDefault();
|
||||
@ -109,20 +99,12 @@ export default contain(
|
||||
return hikesActions.answer({
|
||||
answer,
|
||||
userAnswer,
|
||||
props: this.props
|
||||
hike,
|
||||
isSignedIn
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
routerWillLeave(nextState, router, cb) {
|
||||
// TODO(berks): do animated transitions here stuff here
|
||||
this.setState({
|
||||
showInfo: false,
|
||||
isCorrect: false,
|
||||
mouse: [0, 0]
|
||||
}, cb);
|
||||
},
|
||||
|
||||
renderInfo(showInfo, info, hideInfo) {
|
||||
if (!info) {
|
||||
return null;
|
||||
@ -150,6 +132,8 @@ export default contain(
|
||||
},
|
||||
|
||||
renderQuestion(number, question, answer, shake) {
|
||||
const { hikesActions } = this.props;
|
||||
const mouseUp = e => this.handleMouseUp(e, answer);
|
||||
return ({ x }) => {
|
||||
const style = {
|
||||
WebkitTransform: `translate3d(${ x }px, 0, 0)`,
|
||||
@ -160,13 +144,13 @@ export default contain(
|
||||
<Panel
|
||||
className={ shake ? 'animated swing shake' : '' }
|
||||
header={ title }
|
||||
onMouseDown={ this.handleMouseDown }
|
||||
onMouseLeave={ this.handleMouseUp }
|
||||
onMouseMove={ this.handleMouseMove(answer) }
|
||||
onMouseUp={ this.handleMouseUp }
|
||||
onTouchEnd={ this.handleMouseUp }
|
||||
onTouchMove={ this.handleMouseMove(answer) }
|
||||
onTouchStart={ this.handleMouseDown }
|
||||
onMouseDown={ hikesActions.grabQuestion }
|
||||
onMouseLeave={ mouseUp }
|
||||
onMouseMove={ this.handleMouseMove }
|
||||
onMouseUp={ mouseUp }
|
||||
onTouchEnd={ mouseUp }
|
||||
onTouchMove={ this.handleMouseMove }
|
||||
onTouchStart={ hikesActions.grabQuestion }
|
||||
style={ style }>
|
||||
<p>{ question }</p>
|
||||
</Panel>
|
||||
@ -175,19 +159,20 @@ export default contain(
|
||||
},
|
||||
|
||||
render() {
|
||||
const { showInfo, shake } = this.props;
|
||||
const {
|
||||
hike: { tests = [] } = {},
|
||||
mouse: [x],
|
||||
currentQuestion,
|
||||
hikesActions
|
||||
hikesActions,
|
||||
showInfo,
|
||||
shake
|
||||
} = this.props;
|
||||
|
||||
const [ question, answer, info ] = tests[currentQuestion - 1] || [];
|
||||
|
||||
return (
|
||||
<Col
|
||||
onMouseUp={ this.handleMouseUp }
|
||||
onMouseUp={ e => this.handleMouseUp(e, answer) }
|
||||
xs={ 8 }
|
||||
xsOffset={ 2 }>
|
||||
<Row>
|
||||
|
@ -4,6 +4,7 @@ import { Actions } from 'thundercats';
|
||||
import debugFactory from 'debug';
|
||||
|
||||
const debug = debugFactory('freecc:hikes:actions');
|
||||
const noOp = { transform: () => {} };
|
||||
|
||||
function getCurrentHike(hikes = [{}], dashedName, currentHike) {
|
||||
if (!dashedName) {
|
||||
@ -35,18 +36,17 @@ function findNextHike(hikes, id) {
|
||||
return hikes[currentIndex + 1] || hikes[0];
|
||||
}
|
||||
|
||||
function releaseQuestion(state) {
|
||||
const oldHikesApp = state.hikesApp;
|
||||
const hikesApp = {
|
||||
...oldHikesApp,
|
||||
isPressed: false,
|
||||
delta: [0, 0],
|
||||
mouse: oldHikesApp.isCorrect ?
|
||||
oldHikesApp.mouse :
|
||||
[0, 0]
|
||||
};
|
||||
|
||||
return { ...state, hikesApp };
|
||||
function getMouse(e, [dx, dy]) {
|
||||
let { pageX, pageY, touches } = e;
|
||||
|
||||
if (touches) {
|
||||
e.preventDefault();
|
||||
// these re-assigns the values of pageX, pageY from touches
|
||||
({ pageX, pageY } = touches[0]);
|
||||
}
|
||||
|
||||
return [pageX - dx, pageY - dy];
|
||||
}
|
||||
|
||||
export default Actions({
|
||||
@ -107,64 +107,115 @@ export default Actions({
|
||||
};
|
||||
},
|
||||
|
||||
grabQuestion({ pressX, pressY, pageX, pageY }) {
|
||||
const dx = pageX - pressX;
|
||||
const dy = pageY - pressY;
|
||||
|
||||
const delta = [dx, dy];
|
||||
const mouse = [pageX - dx, pageY - dy];
|
||||
grabQuestion(e) {
|
||||
const { pageX, pageY } = e;
|
||||
const delta = [pageX, pageY];
|
||||
const mouse = getMouse(e, delta);
|
||||
|
||||
return {
|
||||
transform(state) {
|
||||
const hikesApp = { ...state.hikesApp, isPressed: true, delta, mouse };
|
||||
return { ...state, hikesApp };
|
||||
return {
|
||||
...state,
|
||||
hikesApp: {
|
||||
...state.hikesApp,
|
||||
isPressed: true,
|
||||
delta,
|
||||
mouse
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
releaseQuestion() {
|
||||
return { transform: releaseQuestion };
|
||||
},
|
||||
|
||||
moveQuestion(mouse) {
|
||||
return {
|
||||
transform(state) {
|
||||
const hikesApp = { ...state.hikesApp, mouse };
|
||||
return { ...state, hikesApp };
|
||||
return {
|
||||
...state,
|
||||
hikesApp: {
|
||||
...state.hikesApp,
|
||||
isPressed: false,
|
||||
mouse: [0, 0]
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
moveQuestion({ e, delta }) {
|
||||
const mouse = getMouse(e, delta);
|
||||
|
||||
return {
|
||||
transform(state) {
|
||||
return {
|
||||
...state,
|
||||
hikesApp: {
|
||||
...state.hikesApp,
|
||||
mouse
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
answer({
|
||||
e,
|
||||
answer,
|
||||
userAnswer,
|
||||
props: {
|
||||
hike: { id, name, tests, challengeType },
|
||||
currentQuestion,
|
||||
username
|
||||
}
|
||||
hike: { id, name, tests, challengeType },
|
||||
currentQuestion,
|
||||
isSignedIn,
|
||||
delta,
|
||||
threshold
|
||||
}) {
|
||||
if (typeof userAnswer === 'undefined') {
|
||||
const [positionX] = getMouse(e, delta);
|
||||
|
||||
// question released under threshold
|
||||
if (Math.abs(positionX) < threshold) {
|
||||
return noOp;
|
||||
}
|
||||
|
||||
if (positionX >= threshold) {
|
||||
userAnswer = true;
|
||||
}
|
||||
|
||||
if (positionX <= -threshold) {
|
||||
userAnswer = false;
|
||||
}
|
||||
}
|
||||
|
||||
// incorrect question
|
||||
if (answer !== userAnswer) {
|
||||
const startShake = {
|
||||
transform(state) {
|
||||
const hikesApp = { ...state.hikesApp, showInfo: true, shake: true };
|
||||
return { ...state, hikesApp };
|
||||
return {
|
||||
...state,
|
||||
hikesApp: {
|
||||
...state.hikesApp,
|
||||
showInfo: true,
|
||||
shake: true
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const removeShake = {
|
||||
transform(state) {
|
||||
const hikesApp = { ...state.hikesApp, shake: false };
|
||||
return { ...state, hikesApp };
|
||||
return {
|
||||
...state,
|
||||
hikesApp: {
|
||||
...state.hikesApp,
|
||||
shake: false
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
return Observable
|
||||
.just(removeShake)
|
||||
.delay(500)
|
||||
.startWith({ transform: releaseQuestion }, startShake);
|
||||
.startWith(startShake);
|
||||
}
|
||||
|
||||
// move to next question
|
||||
@ -198,22 +249,21 @@ export default Actions({
|
||||
}
|
||||
|
||||
// challenge completed
|
||||
const optimisticSave = username ?
|
||||
const optimisticSave = isSignedIn ?
|
||||
this.post$('/completed-challenge', { id, name, challengeType }) :
|
||||
Observable.just(true);
|
||||
|
||||
const correctAnswer = {
|
||||
transform(state) {
|
||||
const hikesApp = {
|
||||
...state.hikesApp,
|
||||
isCorrect: true,
|
||||
isPressed: false,
|
||||
delta: [0, 0],
|
||||
mouse: [ userAnswer ? 1000 : -1000, 0]
|
||||
};
|
||||
return {
|
||||
...state,
|
||||
hikesApp
|
||||
hikesApp: {
|
||||
...state.hikesApp,
|
||||
isCorrect: true,
|
||||
isPressed: false,
|
||||
delta: [0, 0],
|
||||
mouse: [ userAnswer ? 1000 : -1000, 0]
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -223,26 +273,16 @@ export default Actions({
|
||||
const { hikes, currentHike: { id } } = state.hikesApp;
|
||||
const currentHike = findNextHike(hikes, id);
|
||||
|
||||
// go to next route
|
||||
state.location = {
|
||||
action: 'PUSH',
|
||||
pathname: currentHike && currentHike.dashedName ?
|
||||
`/hikes/${ currentHike.dashedName }` :
|
||||
'/hikes'
|
||||
};
|
||||
|
||||
const hikesApp = {
|
||||
...state.hikesApp,
|
||||
currentHike,
|
||||
showQuestions: false,
|
||||
currentQuestion: 1,
|
||||
mouse: [0, 0]
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
points: username ? state.points + 1 : state.points,
|
||||
hikesApp,
|
||||
points: isSignedIn ? state.points + 1 : state.points,
|
||||
hikesApp: {
|
||||
...state.hikesApp,
|
||||
currentHike,
|
||||
showQuestions: false,
|
||||
currentQuestion: 1,
|
||||
mouse: [0, 0]
|
||||
},
|
||||
toast: {
|
||||
title: 'Congratulations!',
|
||||
message: 'Hike completed',
|
||||
@ -250,6 +290,12 @@ export default Actions({
|
||||
state.toast.id + 1 :
|
||||
0,
|
||||
type: 'success'
|
||||
},
|
||||
location: {
|
||||
action: 'PUSH',
|
||||
pathname: currentHike && currentHike.dashedName ?
|
||||
`/hikes/${ currentHike.dashedName }` :
|
||||
'/hikes'
|
||||
}
|
||||
};
|
||||
},
|
||||
|
Reference in New Issue
Block a user