Video's and video challenge renders
This commit is contained in:
@ -63,6 +63,7 @@ export class FreeCodeCamp extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
const { username, points, picture } = this.props;
|
const { username, points, picture } = this.props;
|
||||||
const navProps = { username, points, picture };
|
const navProps = { username, points, picture };
|
||||||
|
console.log('app', this.props.children);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -17,6 +17,7 @@ const mapStateToProps = createSelector(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// export plain component for testing
|
// export plain component for testing
|
||||||
export class Hike extends React.Component {
|
export class Hike extends React.Component {
|
||||||
static displayName = 'Hike';
|
static displayName = 'Hike';
|
||||||
@ -71,4 +72,4 @@ export class Hike extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// export redux aware component
|
// export redux aware component
|
||||||
export default connect(mapStateToProps, { resetHike });
|
export default connect(mapStateToProps, { resetHike })(Hike);
|
||||||
|
@ -21,10 +21,11 @@ const mapStateToProps = createSelector(
|
|||||||
return { hikes: [] };
|
return { hikes: [] };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
hikes: hikes.results.map(dashedName => hikes.enitites[dashedName])
|
hikes: hikes.results.map(dashedName => hikes.entities[dashedName])
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const fetchOptions = {
|
const fetchOptions = {
|
||||||
fetchAction: 'fetchHikes',
|
fetchAction: 'fetchHikes',
|
||||||
|
|
||||||
@ -50,8 +51,6 @@ export class Hikes extends React.Component {
|
|||||||
updateTitle('Hikes');
|
updateTitle('Hikes');
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate = shouldComponentUpdate;
|
|
||||||
|
|
||||||
renderMap(hikes) {
|
renderMap(hikes) {
|
||||||
return (
|
return (
|
||||||
<HikesMap hikes={ hikes }/>
|
<HikesMap hikes={ hikes }/>
|
||||||
|
@ -90,4 +90,4 @@ export class Lecture extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, { })(Lecture);
|
export default connect(mapStateToProps)(Lecture);
|
||||||
|
@ -17,7 +17,7 @@ export default React.createClass({
|
|||||||
const vidElements = hikes.map(({ title, dashedName}) => {
|
const vidElements = hikes.map(({ title, dashedName}) => {
|
||||||
return (
|
return (
|
||||||
<ListGroupItem key={ dashedName }>
|
<ListGroupItem key={ dashedName }>
|
||||||
<Link to={ `/hikes/${dashedName}` }>
|
<Link to={ `/videos/${dashedName}` }>
|
||||||
<h3>{ title }</h3>
|
<h3>{ title }</h3>
|
||||||
</Link>
|
</Link>
|
||||||
</ListGroupItem>
|
</ListGroupItem>
|
||||||
|
@ -1,50 +1,70 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { spring, Motion } from 'react-motion';
|
import { spring, Motion } from 'react-motion';
|
||||||
import { contain } from 'thundercats-react';
|
import { connect } from 'react-redux';
|
||||||
import { Button, Col, Row } from 'react-bootstrap';
|
import { Button, Col, Row } from 'react-bootstrap';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
|
import {
|
||||||
|
answerQuestion,
|
||||||
|
moveQuestion,
|
||||||
|
releaseQuestion,
|
||||||
|
grabQuestion
|
||||||
|
} from '../redux/actions';
|
||||||
|
|
||||||
const answerThreshold = 100;
|
const answerThreshold = 100;
|
||||||
|
const actionsToBind = {
|
||||||
|
answerQuestion,
|
||||||
|
moveQuestion,
|
||||||
|
releaseQuestion,
|
||||||
|
grabQuestion
|
||||||
|
};
|
||||||
|
|
||||||
export default contain(
|
const mapStateToProps = createSelector(
|
||||||
{
|
state => state.hikesApp.hikes.entities,
|
||||||
store: 'appStore',
|
state => state.hikesApp.hikes.results,
|
||||||
actions: ['hikesActions'],
|
state => state.hikesApp.ui,
|
||||||
map({ hikesApp, username }) {
|
state => state.app.isSignedIn,
|
||||||
|
(hikesMap, hikesByDashname, ui, isSignedIn) => {
|
||||||
const {
|
const {
|
||||||
currentHike,
|
|
||||||
currentQuestion = 1,
|
currentQuestion = 1,
|
||||||
mouse = [ 0, 0 ],
|
mouse = [ 0, 0 ],
|
||||||
isCorrect = false,
|
|
||||||
delta = [ 0, 0 ],
|
delta = [ 0, 0 ],
|
||||||
|
isCorrect = false,
|
||||||
isPressed = false,
|
isPressed = false,
|
||||||
shake = false
|
shouldShakeQuestion = false
|
||||||
} = hikesApp;
|
} = ui;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hike: currentHike,
|
|
||||||
currentQuestion,
|
currentQuestion,
|
||||||
mouse,
|
|
||||||
isCorrect,
|
isCorrect,
|
||||||
|
mouse,
|
||||||
delta,
|
delta,
|
||||||
isPressed,
|
isPressed,
|
||||||
shake,
|
shouldShakeQuestion,
|
||||||
isSignedIn: !!username
|
isSignedIn
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
);
|
||||||
React.createClass({
|
|
||||||
displayName: 'Questions',
|
|
||||||
|
|
||||||
propTypes: {
|
class Question extends React.Component {
|
||||||
hike: PropTypes.object,
|
static displayName = 'Questions';
|
||||||
currentQuestion: PropTypes.number,
|
|
||||||
|
static propTypes = {
|
||||||
|
// actions
|
||||||
|
answerQuestion: PropTypes.func,
|
||||||
|
releaseQuestion: PropTypes.func,
|
||||||
|
moveQuestion: PropTypes.func,
|
||||||
|
grabQuestion: PropTypes.func,
|
||||||
|
// ui state
|
||||||
|
tests: PropTypes.array,
|
||||||
mouse: PropTypes.array,
|
mouse: PropTypes.array,
|
||||||
isCorrect: PropTypes.bool,
|
|
||||||
delta: PropTypes.array,
|
delta: PropTypes.array,
|
||||||
|
isCorrect: PropTypes.bool,
|
||||||
isPressed: PropTypes.bool,
|
isPressed: PropTypes.bool,
|
||||||
shake: PropTypes.bool,
|
|
||||||
isSignedIn: PropTypes.bool,
|
isSignedIn: PropTypes.bool,
|
||||||
hikesActions: PropTypes.object
|
currentQuestion: PropTypes.number,
|
||||||
},
|
shouldShakeQuestion: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
handleMouseUp(e, answer, info) {
|
handleMouseUp(e, answer, info) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@ -53,54 +73,44 @@ export default contain(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
hike,
|
releaseQuestion,
|
||||||
currentQuestion,
|
answerQuestion
|
||||||
isSignedIn,
|
|
||||||
delta
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
this.props.hikesActions.releaseQuestion();
|
releaseQuestion();
|
||||||
this.props.hikesActions.answer({
|
answerQuestion({
|
||||||
e,
|
e,
|
||||||
answer,
|
answer,
|
||||||
hike,
|
|
||||||
delta,
|
|
||||||
currentQuestion,
|
|
||||||
isSignedIn,
|
|
||||||
info,
|
info,
|
||||||
threshold: answerThreshold
|
threshold: answerThreshold
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
handleMouseMove(e) {
|
handleMouseMove(isPressed, { delta, moveQuestion }) {
|
||||||
if (!this.props.isPressed) {
|
if (!isPressed) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const { delta, hikesActions } = this.props;
|
return e => moveQuestion({ e, delta });
|
||||||
|
}
|
||||||
hikesActions.moveQuestion({ e, delta });
|
|
||||||
},
|
|
||||||
|
|
||||||
onAnswer(answer, userAnswer, info) {
|
onAnswer(answer, userAnswer, info) {
|
||||||
const { isSignedIn, hike, currentQuestion, hikesActions } = this.props;
|
const { isSignedIn, answerQuestion } = this.props;
|
||||||
return (e) => {
|
return e => {
|
||||||
if (e && e.preventDefault) {
|
if (e && e.preventDefault) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
return hikesActions.answer({
|
return answerQuestion({
|
||||||
answer,
|
answer,
|
||||||
userAnswer,
|
userAnswer,
|
||||||
currentQuestion,
|
|
||||||
hike,
|
|
||||||
info,
|
info,
|
||||||
isSignedIn
|
isSignedIn
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
renderQuestion(number, question, answer, shake, info) {
|
renderQuestion(number, question, answer, shouldShakeQuestion, info) {
|
||||||
const { hikesActions } = this.props;
|
const { grabQuestion, isPressed } = this.props;
|
||||||
const mouseUp = e => this.handleMouseUp(e, answer, info);
|
const mouseUp = e => this.handleMouseUp(e, answer, info);
|
||||||
return ({ x }) => {
|
return ({ x }) => {
|
||||||
const style = {
|
const style = {
|
||||||
@ -109,28 +119,28 @@ export default contain(
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<article
|
<article
|
||||||
className={ shake ? 'animated swing shake' : '' }
|
className={ shouldShakeQuestion ? 'animated swing shake' : '' }
|
||||||
onMouseDown={ hikesActions.grabQuestion }
|
onMouseDown={ grabQuestion }
|
||||||
onMouseLeave={ mouseUp }
|
onMouseLeave={ mouseUp }
|
||||||
onMouseMove={ this.handleMouseMove }
|
onMouseMove={ this.handleMouseMove(isPressed, this.props) }
|
||||||
onMouseUp={ mouseUp }
|
onMouseUp={ mouseUp }
|
||||||
onTouchEnd={ mouseUp }
|
onTouchEnd={ mouseUp }
|
||||||
onTouchMove={ this.handleMouseMove }
|
onTouchMove={ this.handleMouseMove(isPressed, this.props) }
|
||||||
onTouchStart={ hikesActions.grabQuestion }
|
onTouchStart={ grabQuestion }
|
||||||
style={ style }>
|
style={ style }>
|
||||||
<h4>Question { number }</h4>
|
<h4>Question { number }</h4>
|
||||||
<p>{ question }</p>
|
<p>{ question }</p>
|
||||||
</article>
|
</article>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
hike: { tests = [] } = {},
|
tests = [],
|
||||||
mouse: [x],
|
mouse: [x],
|
||||||
currentQuestion,
|
currentQuestion,
|
||||||
shake
|
shouldShakeQuestion
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const [ question, answer, info ] = tests[currentQuestion - 1] || [];
|
const [ question, answer, info ] = tests[currentQuestion - 1] || [];
|
||||||
@ -138,7 +148,7 @@ export default contain(
|
|||||||
currentQuestion,
|
currentQuestion,
|
||||||
question,
|
question,
|
||||||
answer,
|
answer,
|
||||||
shake,
|
shouldShakeQuestion,
|
||||||
info
|
info
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -173,5 +183,6 @@ export default contain(
|
|||||||
</Col>
|
</Col>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
);
|
|
||||||
|
export default connect(mapStateToProps, actionsToBind)(Question);
|
||||||
|
@ -43,7 +43,7 @@ export const moveQuestion = createAction(
|
|||||||
// info: String,
|
// info: String,
|
||||||
// threshold: Number
|
// threshold: Number
|
||||||
// }) => Action
|
// }) => Action
|
||||||
export const answer = createAction(types.answer);
|
export const answerQuestion = createAction(types.answerQuestion);
|
||||||
|
|
||||||
export const startShake = createAction(types.startShake);
|
export const startShake = createAction(types.startShake);
|
||||||
export const endShake = createAction(types.primeNextQuestion);
|
export const endShake = createAction(types.primeNextQuestion);
|
||||||
|
@ -10,7 +10,7 @@ import { postJSON$ } from '../../../../utils/ajax-stream';
|
|||||||
|
|
||||||
export default () => ({ getState, dispatch }) => next => {
|
export default () => ({ getState, dispatch }) => next => {
|
||||||
return function answerSaga(action) {
|
return function answerSaga(action) {
|
||||||
if (types.answer !== action.type) {
|
if (types.answerQuestion !== action.type) {
|
||||||
return next(action);
|
return next(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,14 +56,11 @@ export default () => ({ getState, dispatch }) => next => {
|
|||||||
// incorrect question
|
// incorrect question
|
||||||
if (answer !== finalAnswer) {
|
if (answer !== finalAnswer) {
|
||||||
if (info) {
|
if (info) {
|
||||||
dispatch({
|
dispatch(makeToast({
|
||||||
type: 'makeToast',
|
|
||||||
payload: {
|
|
||||||
title: 'Hint',
|
title: 'Hint',
|
||||||
message: info,
|
message: info,
|
||||||
type: 'info'
|
type: 'info'
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Observable
|
return Observable
|
||||||
@ -100,7 +97,7 @@ export default () => ({ getState, dispatch }) => next => {
|
|||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
return Observable.just({
|
return Observable.just({
|
||||||
type: 'error',
|
type: 'app.error',
|
||||||
error
|
error
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -32,7 +32,6 @@ export default ({ services }) => ({ dispatch }) => next => {
|
|||||||
|
|
||||||
const currentHike = getCurrentHike(hikes, dashedName);
|
const currentHike = getCurrentHike(hikes, dashedName);
|
||||||
|
|
||||||
console.log('foo', currentHike);
|
|
||||||
return fetchHikesCompleted(hikes, currentHike);
|
return fetchHikesCompleted(hikes, currentHike);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
@ -7,16 +7,27 @@ const initialState = {
|
|||||||
results: [],
|
results: [],
|
||||||
entities: {}
|
entities: {}
|
||||||
},
|
},
|
||||||
// lecture state
|
// ui
|
||||||
|
// hike dashedName
|
||||||
currentHike: '',
|
currentHike: '',
|
||||||
showQuestions: false
|
// 1 indexed
|
||||||
|
currentQuestion: 1,
|
||||||
|
// [ xPosition, yPosition ]
|
||||||
|
mouse: [ 0, 0 ],
|
||||||
|
// change in mouse position since pressed
|
||||||
|
// [ xDelta, yDelta ]
|
||||||
|
delta: [ 0, 0 ],
|
||||||
|
isPressed: false,
|
||||||
|
isCorrect: false,
|
||||||
|
shouldShakeQuestion: false,
|
||||||
|
shouldShowQuestions: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export default handleActions(
|
export default handleActions(
|
||||||
{
|
{
|
||||||
[types.toggleQuestion]: state => ({
|
[types.toggleQuestion]: state => ({
|
||||||
...state,
|
...state,
|
||||||
showQuestions: !state.showQuestions,
|
shouldShowQuestions: !state.shouldShowQuestions,
|
||||||
currentQuestion: 1
|
currentQuestion: 1
|
||||||
}),
|
}),
|
||||||
|
|
||||||
@ -38,13 +49,13 @@ export default handleActions(
|
|||||||
[types.resetHike]: state => ({
|
[types.resetHike]: state => ({
|
||||||
...state,
|
...state,
|
||||||
currentQuestion: 1,
|
currentQuestion: 1,
|
||||||
showQuestions: false,
|
shouldShowQuestions: false,
|
||||||
mouse: [0, 0],
|
mouse: [0, 0],
|
||||||
delta: [0, 0]
|
delta: [0, 0]
|
||||||
}),
|
}),
|
||||||
|
|
||||||
[types.startShake]: state => ({ ...state, shake: true }),
|
[types.startShake]: state => ({ ...state, shouldShakeQuestion: true }),
|
||||||
[types.endShake]: state => ({ ...state, shake: false }),
|
[types.endShake]: state => ({ ...state, shouldShakeQuestion: false }),
|
||||||
|
|
||||||
[types.primeNextQuestion]: (state, { payload: userAnswer }) => ({
|
[types.primeNextQuestion]: (state, { payload: userAnswer }) => ({
|
||||||
...state,
|
...state,
|
||||||
@ -68,7 +79,7 @@ export default handleActions(
|
|||||||
|
|
||||||
[types.goToNextHike]: state => ({
|
[types.goToNextHike]: state => ({
|
||||||
...state,
|
...state,
|
||||||
currentHike: findNextHike(state.hikes, state.currentHike.id),
|
currentHike: findNextHike(state.hikes, state.currentHike),
|
||||||
showQuestions: false,
|
showQuestions: false,
|
||||||
currentQuestion: 1,
|
currentQuestion: 1,
|
||||||
mouse: [ 0, 0 ]
|
mouse: [ 0, 0 ]
|
||||||
|
@ -7,7 +7,7 @@ const types = [
|
|||||||
'releaseQuestion',
|
'releaseQuestion',
|
||||||
'moveQuestion',
|
'moveQuestion',
|
||||||
|
|
||||||
'answer',
|
'answerQuestion',
|
||||||
|
|
||||||
'startShake',
|
'startShake',
|
||||||
'endShake',
|
'endShake',
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React, { PropTypes, createElement } from 'react';
|
import React, { PropTypes, createElement } from 'react';
|
||||||
import { Observable, CompositeDisposable } from 'rx';
|
import { Observable, CompositeDisposable } from 'rx';
|
||||||
|
import shouldComponentUpdate from 'react-pure-render/function';
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
|
|
||||||
// interface contain {
|
// interface contain {
|
||||||
@ -179,10 +180,7 @@ export default function contain(options = {}, Component) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate() {
|
shouldComponentUpdate = shouldComponentUpdate;
|
||||||
// props should be immutable
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { props } = this;
|
const { props } = this;
|
||||||
|
@ -25,7 +25,7 @@ export default function hikesService(app) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
cb(null, hikes);
|
cb(null, hikes.map(hike => hike.toJSON()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user