diff --git a/common/app/routes/Hikes/components/Questions.jsx b/common/app/routes/Hikes/components/Questions.jsx
index 1a7b08c9e3..38dade4633 100644
--- a/common/app/routes/Hikes/components/Questions.jsx
+++ b/common/app/routes/Hikes/components/Questions.jsx
@@ -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(
{ question }
@@ -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 (
this.handleMouseUp(e, answer) }
xs={ 8 }
xsOffset={ 2 }>
diff --git a/common/app/routes/Hikes/flux/Actions.js b/common/app/routes/Hikes/flux/Actions.js
index 5220286759..25c879d302 100644
--- a/common/app/routes/Hikes/flux/Actions.js
+++ b/common/app/routes/Hikes/flux/Actions.js
@@ -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'
}
};
},