Question now semi functional
This commit is contained in:
		@@ -26,7 +26,7 @@ const appLocation = createLocation(
 | 
			
		||||
function location$(history) {
 | 
			
		||||
  return Rx.Observable.create(function(observer) {
 | 
			
		||||
    const dispose = history.listen(function(location) {
 | 
			
		||||
      observer.onNext(location.pathname);
 | 
			
		||||
      observer.onNext(location);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return Rx.Disposable.create(() => {
 | 
			
		||||
@@ -40,10 +40,9 @@ app$({ history, location: appLocation })
 | 
			
		||||
  .flatMap(
 | 
			
		||||
    ({ AppCat }) => {
 | 
			
		||||
      // instantiate the cat with service
 | 
			
		||||
      const appCat = AppCat(null, services);
 | 
			
		||||
      const appCat = AppCat(null, services, history);
 | 
			
		||||
      // hydrate the stores
 | 
			
		||||
      return hydrate(appCat, catState)
 | 
			
		||||
        .map(() => appCat);
 | 
			
		||||
      return hydrate(appCat, catState).map(() => appCat);
 | 
			
		||||
    },
 | 
			
		||||
    // not using nextLocation at the moment but will be used for
 | 
			
		||||
    // redirects in the future
 | 
			
		||||
@@ -51,12 +50,26 @@ app$({ history, location: appLocation })
 | 
			
		||||
  )
 | 
			
		||||
  .doOnNext(({ appCat }) => {
 | 
			
		||||
    const appActions = appCat.getActions('appActions');
 | 
			
		||||
    const appStore = appCat.getStore('appStore');
 | 
			
		||||
 | 
			
		||||
    location$(history)
 | 
			
		||||
    const route$ = location$(history)
 | 
			
		||||
      .pluck('pathname')
 | 
			
		||||
      .distinctUntilChanged()
 | 
			
		||||
      .doOnNext(route => debug('route change', route))
 | 
			
		||||
      .subscribe(route => appActions.updateRoute(route));
 | 
			
		||||
      .distinctUntilChanged();
 | 
			
		||||
 | 
			
		||||
    appStore
 | 
			
		||||
      .pluck('route')
 | 
			
		||||
      .filter(route => !!route)
 | 
			
		||||
      .withLatestFrom(
 | 
			
		||||
        route$,
 | 
			
		||||
        (nextRoute, currentRoute) => ({ currentRoute, nextRoute })
 | 
			
		||||
      )
 | 
			
		||||
      // only continue when route change requested
 | 
			
		||||
      .filter(({ currentRoute, nextRoute }) => currentRoute !== nextRoute)
 | 
			
		||||
      .doOnNext(({ nextRoute }) => {
 | 
			
		||||
        debug('route change', nextRoute);
 | 
			
		||||
        history.pushState(history.state, nextRoute);
 | 
			
		||||
      })
 | 
			
		||||
      .subscribeOnError(err => console.error(err));
 | 
			
		||||
 | 
			
		||||
    appActions.goBack.subscribe(function() {
 | 
			
		||||
      history.goBack();
 | 
			
		||||
@@ -65,10 +78,11 @@ app$({ history, location: appLocation })
 | 
			
		||||
    appActions
 | 
			
		||||
      .updateRoute
 | 
			
		||||
      .pluck('route')
 | 
			
		||||
      .doOnNext(route => debug('update route', route))
 | 
			
		||||
      .subscribe(function(route) {
 | 
			
		||||
        history.pushState(null, route);
 | 
			
		||||
      });
 | 
			
		||||
      .doOnNext(route => {
 | 
			
		||||
        debug('update route', route);
 | 
			
		||||
        history.pushState(history.state, route);
 | 
			
		||||
      })
 | 
			
		||||
      .subscribeOnError(err => console.error(err));
 | 
			
		||||
  })
 | 
			
		||||
  .flatMap(({ props, appCat }) => {
 | 
			
		||||
    props.history = history;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,14 +2,15 @@ import { Cat } from 'thundercats';
 | 
			
		||||
import stamp from 'stampit';
 | 
			
		||||
import { Disposable, Observable } from 'rx';
 | 
			
		||||
 | 
			
		||||
import { postJSON$ } from '../utils/ajax-stream.js';
 | 
			
		||||
import { post$, postJSON$ } from '../utils/ajax-stream.js';
 | 
			
		||||
import { AppActions, AppStore } from './flux';
 | 
			
		||||
import { HikesActions } from './routes/Hikes/flux';
 | 
			
		||||
import { JobActions, JobsStore} from './routes/Jobs/flux';
 | 
			
		||||
 | 
			
		||||
const ajaxStamp = stamp({
 | 
			
		||||
  methods: {
 | 
			
		||||
    postJSON$: postJSON$
 | 
			
		||||
    postJSON$,
 | 
			
		||||
    post$
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,8 @@ const initValue = {
 | 
			
		||||
  points: 0,
 | 
			
		||||
  hikesApp: {
 | 
			
		||||
    hikes: [],
 | 
			
		||||
    currentHikes: {},
 | 
			
		||||
    currentQuestion: 1,
 | 
			
		||||
    // lecture state
 | 
			
		||||
    currentHike: {},
 | 
			
		||||
    showQuestion: false
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
@@ -22,13 +22,31 @@ export default Store({
 | 
			
		||||
  init({ instance: appStore, args: [cat] }) {
 | 
			
		||||
    const { updateRoute, getUser, setTitle } = cat.getActions('appActions');
 | 
			
		||||
    const register = createRegistrar(appStore);
 | 
			
		||||
    const { toggleQuestions, fetchHikes } = cat.getActions('hikesActions');
 | 
			
		||||
    const {
 | 
			
		||||
      toggleQuestions,
 | 
			
		||||
      fetchHikes,
 | 
			
		||||
      hideInfo,
 | 
			
		||||
      grabQuestion,
 | 
			
		||||
      releaseQuestion,
 | 
			
		||||
      moveQuestion,
 | 
			
		||||
      answer
 | 
			
		||||
    } = cat.getActions('hikesActions');
 | 
			
		||||
 | 
			
		||||
    // app
 | 
			
		||||
    register(setter(fromMany(getUser, setTitle, updateRoute)));
 | 
			
		||||
 | 
			
		||||
    // hikes
 | 
			
		||||
    register(fromMany(fetchHikes, toggleQuestions));
 | 
			
		||||
    register(
 | 
			
		||||
      fromMany(
 | 
			
		||||
        toggleQuestions,
 | 
			
		||||
        fetchHikes,
 | 
			
		||||
        hideInfo,
 | 
			
		||||
        grabQuestion,
 | 
			
		||||
        releaseQuestion,
 | 
			
		||||
        moveQuestion,
 | 
			
		||||
        answer
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return appStore;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
import React, { PropTypes } from 'react';
 | 
			
		||||
import { Motion } from 'react-motion';
 | 
			
		||||
import { spring, Motion } from 'react-motion';
 | 
			
		||||
import { contain } from 'thundercats-react';
 | 
			
		||||
import debugFactory from 'debug';
 | 
			
		||||
import {
 | 
			
		||||
  Button,
 | 
			
		||||
  Col,
 | 
			
		||||
@@ -10,19 +9,32 @@ import {
 | 
			
		||||
  Row
 | 
			
		||||
} from 'react-bootstrap';
 | 
			
		||||
 | 
			
		||||
const debug = debugFactory('freecc:hikes');
 | 
			
		||||
const ANSWER_THRESHOLD = 200;
 | 
			
		||||
 | 
			
		||||
export default contain(
 | 
			
		||||
  {
 | 
			
		||||
    store: 'appStore',
 | 
			
		||||
    actions: ['hikesAction'],
 | 
			
		||||
    map(state) {
 | 
			
		||||
      const { currentQuestion, currentHike } = state.hikesApp;
 | 
			
		||||
 | 
			
		||||
    actions: ['hikesActions'],
 | 
			
		||||
    map({ hikesApp }) {
 | 
			
		||||
      const {
 | 
			
		||||
        currentHike,
 | 
			
		||||
        currentQuestion = 1,
 | 
			
		||||
        mouse = [0, 0],
 | 
			
		||||
        isCorrect = false,
 | 
			
		||||
        delta = [0, 0],
 | 
			
		||||
        isPressed = false,
 | 
			
		||||
        showInfo = false,
 | 
			
		||||
        shake = false
 | 
			
		||||
      } = hikesApp;
 | 
			
		||||
      return {
 | 
			
		||||
        hike: currentHike,
 | 
			
		||||
        currentQuestion
 | 
			
		||||
        currentQuestion,
 | 
			
		||||
        mouse,
 | 
			
		||||
        isCorrect,
 | 
			
		||||
        delta,
 | 
			
		||||
        isPressed,
 | 
			
		||||
        showInfo,
 | 
			
		||||
        shake
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
@@ -30,150 +42,89 @@ export default contain(
 | 
			
		||||
    displayName: 'Questions',
 | 
			
		||||
 | 
			
		||||
    propTypes: {
 | 
			
		||||
      dashedName: PropTypes.string,
 | 
			
		||||
      currentQuestion: PropTypes.number,
 | 
			
		||||
      hike: PropTypes.object,
 | 
			
		||||
      currentQuestion: PropTypes.number,
 | 
			
		||||
      mouse: PropTypes.array,
 | 
			
		||||
      isCorrect: PropTypes.bool,
 | 
			
		||||
      delta: PropTypes.array,
 | 
			
		||||
      isPressed: PropTypes.bool,
 | 
			
		||||
      showInfo: PropTypes.bool,
 | 
			
		||||
      shake: PropTypes.bool,
 | 
			
		||||
      hikesActions: PropTypes.object
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInitialState: () => ({
 | 
			
		||||
      mouse: [0, 0],
 | 
			
		||||
      correct: false,
 | 
			
		||||
      delta: [0, 0],
 | 
			
		||||
      isPressed: false,
 | 
			
		||||
      showInfo: false,
 | 
			
		||||
      shake: false
 | 
			
		||||
    }),
 | 
			
		||||
 | 
			
		||||
    getTweenValues() {
 | 
			
		||||
      const { mouse: [x, y] } = this.state;
 | 
			
		||||
      return {
 | 
			
		||||
        val: { x, y },
 | 
			
		||||
        config: [120, 10]
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleMouseDown({ pageX, pageY, touches }) {
 | 
			
		||||
      if (touches) {
 | 
			
		||||
        ({ pageX, pageY } = touches[0]);
 | 
			
		||||
      }
 | 
			
		||||
      const { mouse: [pressX, pressY] } = this.state;
 | 
			
		||||
      const dx = pageX - pressX;
 | 
			
		||||
      const dy = pageY - pressY;
 | 
			
		||||
      this.setState({
 | 
			
		||||
        isPressed: true,
 | 
			
		||||
        delta: [dx, dy],
 | 
			
		||||
        mouse: [pageX - dx, pageY - dy]
 | 
			
		||||
      });
 | 
			
		||||
      const { mouse: [pressX, pressY], hikesActions } = this.props;
 | 
			
		||||
      hikesActions.grabQuestion({ pressX, pressY, pageX, pageY });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleMouseUp() {
 | 
			
		||||
      const { correct } = this.state;
 | 
			
		||||
      if (correct) {
 | 
			
		||||
        return this.setState({
 | 
			
		||||
          isPressed: false,
 | 
			
		||||
          delta: [0, 0]
 | 
			
		||||
        });
 | 
			
		||||
      if (!this.props.isPressed) {
 | 
			
		||||
        return null;
 | 
			
		||||
      }
 | 
			
		||||
      this.setState({
 | 
			
		||||
        isPressed: false,
 | 
			
		||||
        mouse: [0, 0],
 | 
			
		||||
        delta: [0, 0]
 | 
			
		||||
      });
 | 
			
		||||
      this.props.hikesActions.releaseQuestion();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleMouseMove(answer) {
 | 
			
		||||
      if (!this.props.isPressed) {
 | 
			
		||||
        return () => {};
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return (e) => {
 | 
			
		||||
        let { pageX, pageY, touches } = e;
 | 
			
		||||
 | 
			
		||||
        if (touches) {
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          // these reassins the values of pageX, pageY from touches
 | 
			
		||||
          // these re-assigns the values of pageX, pageY from touches
 | 
			
		||||
          ({ pageX, pageY } = touches[0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const { isPressed, delta: [dx, dy] } = this.state;
 | 
			
		||||
        if (isPressed) {
 | 
			
		||||
        const { delta: [dx, dy], hikesActions } = this.props;
 | 
			
		||||
        const mouse = [pageX - dx, pageY - dy];
 | 
			
		||||
 | 
			
		||||
        if (mouse[0] >= ANSWER_THRESHOLD) {
 | 
			
		||||
            this.handleMouseUp();
 | 
			
		||||
          return this.onAnswer(answer, true)();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (mouse[0] <= -ANSWER_THRESHOLD) {
 | 
			
		||||
            this.handleMouseUp();
 | 
			
		||||
          return this.onAnswer(answer, false)();
 | 
			
		||||
        }
 | 
			
		||||
          this.setState({ mouse });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return hikesActions.moveQuestion(mouse);
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hideInfo() {
 | 
			
		||||
      this.setState({ showInfo: false });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onAnswer(answer, userAnswer) {
 | 
			
		||||
      const { hikesActions } = this.props;
 | 
			
		||||
      return (e) => {
 | 
			
		||||
        if (e && e.preventDefault) {
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.disposeTimeout) {
 | 
			
		||||
          clearTimeout(this.disposeTimeout);
 | 
			
		||||
          this.disposeTimeout = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (answer === userAnswer) {
 | 
			
		||||
          debug('correct answer!');
 | 
			
		||||
          this.setState({
 | 
			
		||||
            correct: true,
 | 
			
		||||
            mouse: [ userAnswer ? 1000 : -1000, 0]
 | 
			
		||||
          });
 | 
			
		||||
          this.disposeTimeout = setTimeout(() => {
 | 
			
		||||
            this.onCorrectAnswer();
 | 
			
		||||
          }, 1000);
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        debug('incorrect');
 | 
			
		||||
        this.setState({
 | 
			
		||||
          showInfo: true,
 | 
			
		||||
          shake: true
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.disposeTimeout = setTimeout(
 | 
			
		||||
          () => this.setState({ shake: false }),
 | 
			
		||||
          500
 | 
			
		||||
        );
 | 
			
		||||
        return hikesActions.answer({ answer, userAnswer, props: this.props });
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onCorrectAnswer() {
 | 
			
		||||
      const {
 | 
			
		||||
        hikesActions,
 | 
			
		||||
        hike: { id, name }
 | 
			
		||||
      } = this.props;
 | 
			
		||||
 | 
			
		||||
      hikesActions.completedHike({ id, name });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    routerWillLeave(nextState, router, cb) {
 | 
			
		||||
      // TODO(berks): do animated transitions here stuff here
 | 
			
		||||
      this.setState({
 | 
			
		||||
        showInfo: false,
 | 
			
		||||
        correct: false,
 | 
			
		||||
        isCorrect: false,
 | 
			
		||||
        mouse: [0, 0]
 | 
			
		||||
      }, cb);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    renderInfo(showInfo, info) {
 | 
			
		||||
    renderInfo(showInfo, info, hideInfo) {
 | 
			
		||||
      if (!info) {
 | 
			
		||||
        return null;
 | 
			
		||||
      }
 | 
			
		||||
      return (
 | 
			
		||||
        <Modal
 | 
			
		||||
          backdrop={ true }
 | 
			
		||||
          onHide={ this.hideInfo }
 | 
			
		||||
          onHide={ hideInfo }
 | 
			
		||||
          show={ showInfo }>
 | 
			
		||||
          <Modal.Body>
 | 
			
		||||
            <h3>
 | 
			
		||||
@@ -184,7 +135,7 @@ export default contain(
 | 
			
		||||
            <Button
 | 
			
		||||
              block={ true }
 | 
			
		||||
              bsSize='large'
 | 
			
		||||
              onClick={ this.hideInfo }>
 | 
			
		||||
              onClick={ hideInfo }>
 | 
			
		||||
              hide
 | 
			
		||||
            </Button>
 | 
			
		||||
          </Modal.Footer>
 | 
			
		||||
@@ -193,8 +144,7 @@ export default contain(
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    renderQuestion(number, question, answer, shake) {
 | 
			
		||||
      return ({ x: xFunc }) => {
 | 
			
		||||
        const x = xFunc().val.x;
 | 
			
		||||
      return ({ x }) => {
 | 
			
		||||
        const style = {
 | 
			
		||||
          WebkitTransform: `translate3d(${ x }px, 0, 0)`,
 | 
			
		||||
          transform: `translate3d(${ x }px, 0, 0)`
 | 
			
		||||
@@ -219,10 +169,12 @@ export default contain(
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
      const { showInfo, shake } = this.state;
 | 
			
		||||
      const { showInfo, shake } = this.props;
 | 
			
		||||
      const {
 | 
			
		||||
        hike: { tests = [] } = {},
 | 
			
		||||
        currentQuestion
 | 
			
		||||
        mouse: [x],
 | 
			
		||||
        currentQuestion,
 | 
			
		||||
        hikesActions
 | 
			
		||||
      } = this.props;
 | 
			
		||||
 | 
			
		||||
      const [ question, answer, info ] = tests[currentQuestion - 1] || [];
 | 
			
		||||
@@ -233,21 +185,21 @@ export default contain(
 | 
			
		||||
          xs={ 8 }
 | 
			
		||||
          xsOffset={ 2 }>
 | 
			
		||||
          <Row>
 | 
			
		||||
            <Motion style={{ x: this.getTweenValues }}>
 | 
			
		||||
            <Motion style={{ x: spring(x, [120, 10]) }}>
 | 
			
		||||
              { this.renderQuestion(currentQuestion, question, answer, shake) }
 | 
			
		||||
            </Motion>
 | 
			
		||||
            { this.renderInfo(showInfo, info) }
 | 
			
		||||
            { this.renderInfo(showInfo, info, hikesActions.hideInfo) }
 | 
			
		||||
            <Panel>
 | 
			
		||||
              <Button
 | 
			
		||||
                bsSize='large'
 | 
			
		||||
                className='pull-left'
 | 
			
		||||
                onClick={ this.onAnswer(answer, false, info) }>
 | 
			
		||||
                onClick={ this.onAnswer(answer, false) }>
 | 
			
		||||
                false
 | 
			
		||||
              </Button>
 | 
			
		||||
              <Button
 | 
			
		||||
                bsSize='large'
 | 
			
		||||
                className='pull-right'
 | 
			
		||||
                onClick={ this.onAnswer(answer, true, info) }>
 | 
			
		||||
                onClick={ this.onAnswer(answer, true) }>
 | 
			
		||||
                true
 | 
			
		||||
              </Button>
 | 
			
		||||
            </Panel>
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,20 @@ 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 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default Actions({
 | 
			
		||||
  refs: { displayName: 'HikesActions' },
 | 
			
		||||
  shouldBindMethods: true,
 | 
			
		||||
@@ -74,14 +88,111 @@ export default Actions({
 | 
			
		||||
  toggleQuestions() {
 | 
			
		||||
    return {
 | 
			
		||||
      transform(state) {
 | 
			
		||||
        state.hikesApp.showQuestions = !state.hikesApp.showQuestions;
 | 
			
		||||
        return Object.assign({}, state);
 | 
			
		||||
        const hikesApp = { ...state.hikesApp, showQuestions: true };
 | 
			
		||||
        return { ...state, hikesApp };
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  completedHike(data = {}) {
 | 
			
		||||
    return this.postJSON$('/completed-challenge', data)
 | 
			
		||||
  hideInfo() {
 | 
			
		||||
    return {
 | 
			
		||||
      transform(state) {
 | 
			
		||||
        const hikesApp = { ...state.hikesApp, showInfo: false };
 | 
			
		||||
        return { ...state, hikesApp };
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  grabQuestion({ pressX, pressY, pageX, pageY }) {
 | 
			
		||||
    const dx = pageX - pressX;
 | 
			
		||||
    const dy = pageY - pressY;
 | 
			
		||||
 | 
			
		||||
    const delta = [dx, dy];
 | 
			
		||||
    const mouse = [pageX - dx, pageY - dy];
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      transform(state) {
 | 
			
		||||
        const hikesApp = { ...state.hikesApp, isPressed: true, delta, mouse };
 | 
			
		||||
        return { ...state, hikesApp };
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  releaseQuestion() {
 | 
			
		||||
    return { transform: releaseQuestion };
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  moveQuestion(mouse) {
 | 
			
		||||
    return {
 | 
			
		||||
      transform(state) {
 | 
			
		||||
        const hikesApp = { ...state.hikesApp, mouse };
 | 
			
		||||
        return { ...state, hikesApp };
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  answer({
 | 
			
		||||
    answer,
 | 
			
		||||
    userAnswer,
 | 
			
		||||
    props: {
 | 
			
		||||
      hike: { id, name, tests, challengeType },
 | 
			
		||||
      currentQuestion
 | 
			
		||||
    }
 | 
			
		||||
  }) {
 | 
			
		||||
 | 
			
		||||
    // incorrect question
 | 
			
		||||
    if (answer !== userAnswer) {
 | 
			
		||||
      const startShake = {
 | 
			
		||||
        transform(state) {
 | 
			
		||||
          const hikesApp = { ...state.hikesApp, showInfo: true, shake: true };
 | 
			
		||||
          return { ...state, hikesApp };
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      const removeShake = {
 | 
			
		||||
        transform(state) {
 | 
			
		||||
          const hikesApp = { ...state.hikesApp, shake: false };
 | 
			
		||||
          return { ...state, hikesApp };
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      return Observable
 | 
			
		||||
        .just(removeShake)
 | 
			
		||||
        .delay(500)
 | 
			
		||||
        .startWith({ transform: releaseQuestion }, startShake);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // move to next question
 | 
			
		||||
    if (tests[currentQuestion + 1]) {
 | 
			
		||||
 | 
			
		||||
      return {
 | 
			
		||||
        transform(state) {
 | 
			
		||||
 | 
			
		||||
          const hikesApp = {
 | 
			
		||||
            ...state.hikesApp,
 | 
			
		||||
            currentQuestion: currentQuestion + 1
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          return { ...state, hikesApp };
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // challenge completed
 | 
			
		||||
    const correctAnswer = {
 | 
			
		||||
      transform(state) {
 | 
			
		||||
        const hikesApp = {
 | 
			
		||||
          ...state.hikesApp,
 | 
			
		||||
          isCorrect: true,
 | 
			
		||||
          isPressed: false,
 | 
			
		||||
          delta: [0, 0],
 | 
			
		||||
          mouse: [ userAnswer ? 1000 : -1000, 0]
 | 
			
		||||
        };
 | 
			
		||||
        return { ...state, hikesApp };
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return this.post$('/completed-challenge', { id, name, challengeType })
 | 
			
		||||
      .map(() => {
 | 
			
		||||
        return {
 | 
			
		||||
          transform(state) {
 | 
			
		||||
@@ -98,6 +209,7 @@ export default Actions({
 | 
			
		||||
          }
 | 
			
		||||
        };
 | 
			
		||||
      })
 | 
			
		||||
      .startWith(correctAnswer)
 | 
			
		||||
      .catch(err => {
 | 
			
		||||
        console.error(err);
 | 
			
		||||
        return Observable.just({
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import debugFactory from 'debug';
 | 
			
		||||
import { AnonymousObservable, helpers } from 'rx';
 | 
			
		||||
import { Observable, AnonymousObservable, helpers } from 'rx';
 | 
			
		||||
 | 
			
		||||
const debug = debugFactory('freecc:ajax$');
 | 
			
		||||
const root = typeof window !== 'undefined' ? window : {};
 | 
			
		||||
@@ -147,8 +147,12 @@ export function ajax$(options) {
 | 
			
		||||
    var processResponse = function(xhr, e) {
 | 
			
		||||
      var status = xhr.status === 1223 ? 204 : xhr.status;
 | 
			
		||||
      if ((status >= 200 && status <= 300) || status === 0 || status === '') {
 | 
			
		||||
        try {
 | 
			
		||||
          observer.onNext(normalizeSuccess(e, xhr, settings));
 | 
			
		||||
          observer.onCompleted();
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
          observer.onError(err);
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        observer.onError(normalizeError(e, xhr, 'error'));
 | 
			
		||||
      }
 | 
			
		||||
@@ -228,8 +232,8 @@ export function ajax$(options) {
 | 
			
		||||
        settings.hasContent && settings.body
 | 
			
		||||
      );
 | 
			
		||||
      xhr.send(settings.hasContent && settings.body || null);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      observer.onError(e);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      observer.onError(err);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return function() {
 | 
			
		||||
@@ -247,13 +251,25 @@ export function ajax$(options) {
 | 
			
		||||
  * from the Ajax POST.
 | 
			
		||||
  */
 | 
			
		||||
export function post$(url, body) {
 | 
			
		||||
  try {
 | 
			
		||||
    body = JSON.stringify(body);
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    return Observable.throw(e);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return ajax$({ url, body, method: 'POST' });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function postJSON$(url, body) {
 | 
			
		||||
  try {
 | 
			
		||||
    body = JSON.stringify(body);
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    return Observable.throw(e);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return ajax$({
 | 
			
		||||
    url,
 | 
			
		||||
    body: JSON.stringify(body),
 | 
			
		||||
    body,
 | 
			
		||||
    method: 'POST',
 | 
			
		||||
    responseType: 'json',
 | 
			
		||||
    headers: { 'Content-Type': 'application/json' }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user