Make structure changes to hikes

This commit is contained in:
Berkeley Martinez
2015-12-22 19:33:25 -08:00
parent fe16a74faa
commit af950779a4
11 changed files with 154 additions and 116 deletions

View File

@ -4,11 +4,21 @@ import debugFactory from 'debug';
const debug = debugFactory('freecc:app:actions'); const debug = debugFactory('freecc:app:actions');
export default Actions({ export default Actions({
shouldBindMethods: true,
refs: { displayName: 'AppActions' },
setTitle(title = 'Learn To Code') { setTitle(title = 'Learn To Code') {
return { title: title + ' | Free Code Camp' }; return { title: title + ' | Free Code Camp' };
}, },
setUser({ getUser({ isPrimed }) {
if (isPrimed) {
return null;
}
debug('fetching user data');
return this.readService$('user', null, null)
.map(function({
username, username,
picture, picture,
progressTimestamps = [], progressTimestamps = [],
@ -22,28 +32,14 @@ export default Actions({
isFrontEndCert, isFrontEndCert,
isFullStackCert isFullStackCert
}; };
})
.catch(err => {
console.error(err);
});
}, },
getUser: null,
updateRoute(route) { updateRoute(route) {
return { route }; return { route };
}, },
goBack: null goBack: null
})
.refs({ displayName: 'AppActions' })
.init(({ instance: appActions, args: [services] }) => {
appActions.getUser.subscribe(({ isPrimed }) => {
if (isPrimed) {
debug('isPrimed');
return;
}
services.read('user', null, null, (err, user) => {
if (err) {
return debug('user service error');
}
debug('user service returned successful');
return appActions.setUser(user);
});
});
return appActions;
}); });

View File

@ -18,15 +18,15 @@ export default Store({
value: initValue value: initValue
}, },
init({ instance: appStore, args: [cat] }) { init({ instance: appStore, args: [cat] }) {
const { updateRoute, setUser, setTitle } = cat.getActions('appActions'); const { updateRoute, getUser, setTitle } = cat.getActions('appActions');
const register = createRegistrar(appStore); const register = createRegistrar(appStore);
let { setHikes } = cat.getActions('hikesActions'); const { fetchHikes } = cat.getActions('hikesActions');
// app // app
register(setter(fromMany(setUser, setTitle, updateRoute))); register(setter(fromMany(getUser, setTitle, updateRoute)));
// hikes // hikes
register(setHikes); register(fetchHikes);
return appStore; return appStore;
} }

View File

@ -0,0 +1,56 @@
import React, { PropTypes } from 'react';
import {
Col,
Panel,
Row
} from 'react-bootstrap';
import Lecture from './Lecture.jsx';
import Questions from './Questions.jsx';
export default React.createClass({
displayName: 'Hike',
propTypes: {
showQuestions: PropTypes.bool,
currentHike: PropTypes.object
},
renderBody(showQuestions, currentHike) {
if (showQuestions) {
return (
<Questions hike={ currentHike }/>
);
}
const {
challengeSeed: [ id ] = ['1'],
description = []
} = currentHike;
return (
<Lecture
description={ description }
id={ id } />
);
},
render() {
const { currentHike, showQuestions } = this.props;
const { title } = currentHike;
const videoTitle = <h2>{ title }</h2>;
return (
<Col xs={ 12 }>
<Row>
<Panel
className={ 'text-center' }
title={ videoTitle }>
{ this.renderBody(showQuestions, currentHike) }
</Panel>
</Row>
</Col>
);
}
});

View File

@ -9,7 +9,10 @@ import HikesMap from './Map.jsx';
export default contain( export default contain(
{ {
store: 'hikesStore', store: 'appStore',
map(state) {
return state.hikesApp;
},
actions: ['appActions'], actions: ['appActions'],
fetchAction: 'hikesActions.fetchHikes', fetchAction: 'hikesActions.fetchHikes',
getPayload: ({ hikes, params }) => ({ getPayload: ({ hikes, params }) => ({
@ -54,8 +57,12 @@ export default contain(
return ( return (
<div> <div>
<Row style={ preventOverflow }> <Row style={ preventOverflow }>
{ this.renderChild(children, hikes, currentHike) || {
this.renderMap(hikes) } // render sub-route
this.renderChild(children, hikes, currentHike) ||
// if no sub-route render hikes map
this.renderMap(hikes)
}
</Row> </Row>
</div> </div>
); );

View File

@ -1,5 +1,5 @@
import React, { PropTypes } from 'react'; import React, { PropTypes } from 'react';
import { Button, Col, Row, Panel } from 'react-bootstrap'; import { Button, Col, Row } from 'react-bootstrap';
import { History } from 'react-router'; import { History } from 'react-router';
import Vimeo from 'react-vimeo'; import Vimeo from 'react-vimeo';
import debugFactory from 'debug'; import debugFactory from 'debug';
@ -19,8 +19,6 @@ export default React.createClass({
handleFinish() { handleFinish() {
debug('loading questions'); debug('loading questions');
const { dashedName } = this.props.params;
this.history.pushState(null, `/hikes/${dashedName}/questions/1`);
}, },
renderTranscript(transcript, dashedName) { renderTranscript(transcript, dashedName) {
@ -31,7 +29,6 @@ export default React.createClass({
render() { render() {
const { const {
title,
challengeSeed = ['1'], challengeSeed = ['1'],
description = [] description = []
} = this.props.currentHike; } = this.props.currentHike;
@ -39,31 +36,22 @@ export default React.createClass({
const [ id ] = challengeSeed; const [ id ] = challengeSeed;
const videoTitle = <h2>{ title }</h2>;
return ( return (
<Col xs={ 12 }> <Col xs={ 12 }>
<Row> <Row>
<Panel className={ 'text-center' } title={ videoTitle }>
<Vimeo <Vimeo
onError={ this.handleError } onError={ this.handleError }
onFinish= { this.handleFinish } onFinish= { this.handleFinish }
videoId={ id } /> videoId={ id } />
</Panel>
</Row> </Row>
<Row> <Row>
<Col xs={ 12 }>
<Panel>
{ this.renderTranscript(description, dashedName) } { this.renderTranscript(description, dashedName) }
</Panel>
<Panel>
<Button <Button
block={ true } block={ true }
bsSize='large' bsSize='large'
onClick={ this.handleFinish }> onClick={ this.handleFinish }>
Take me to the Questions Take me to the Questions
</Button> </Button>
</Panel>
</Col>
</Row> </Row>
</Col> </Col>
); );

View File

@ -11,7 +11,7 @@ export default React.createClass({
render() { render() {
const { const {
hikes hikes = [{}]
} = this.props; } = this.props;
const vidElements = hikes.map(({ title, dashedName}) => { const vidElements = hikes.map(({ title, dashedName}) => {

View File

@ -16,7 +16,7 @@ const debug = debugFactory('freecc:hikes');
const ANSWER_THRESHOLD = 200; const ANSWER_THRESHOLD = 200;
export default React.createClass({ export default React.createClass({
displayName: 'Question', displayName: 'Questions',
mixins: [ mixins: [
History, History,

View File

@ -25,18 +25,11 @@ function getCurrentHike(hikes = [{}], dashedName, currentHike) {
} }
export default Actions({ export default Actions({
// start fetching hikes refs: { displayName: 'HikesActions' },
fetchHikes: null, shouldBindMethods: true,
// set hikes on store fetchHikes({ isPrimed, dashedName }) {
setHikes: null
})
.refs({ displayName: 'HikesActions' })
.init(({ instance: hikeActions, args: [services] }) => {
// set up hikes fetching
hikeActions.fetchHikes.subscribe(
({ isPrimed, dashedName }) => {
if (isPrimed) { if (isPrimed) {
return hikeActions.setHikes({ return {
transform: (state) => { transform: (state) => {
const { hikesApp: oldState } = state; const { hikesApp: oldState } = state;
@ -49,25 +42,24 @@ export default Actions({
const hikesApp = { ...oldState, currentHike }; const hikesApp = { ...oldState, currentHike };
return Object.assign({}, state, { hikesApp }); return Object.assign({}, state, { hikesApp });
} }
}); };
}
services.read('hikes', null, null, (err, hikes) => {
if (err) {
return console.error(err);
} }
return this.readService$('hikes', null, null)
.map(hikes => {
const hikesApp = { const hikesApp = {
hikes, hikes,
currentHike: getCurrentHike(hikes, dashedName) currentHike: getCurrentHike(hikes, dashedName)
}; };
hikeActions.setHikes({ return {
transform(oldState) { transform(oldState) {
return Object.assign({}, oldState, { hikesApp }); return Object.assign({}, oldState, { hikesApp });
} }
}); };
})
.catch(err => {
console.error(err);
}); });
} }
);
}); });

View File

@ -1,2 +1 @@
export { default as HikesActions } from './Actions'; export { default as HikesActions } from './Actions';
export { default as HikesStore } from './Store';

View File

@ -1,6 +1,5 @@
import Hikes from './components/Hikes.jsx'; import Hikes from './components/Hikes.jsx';
import Lecture from './components/Lecture.jsx'; import Hike from './components/Hike.jsx';
import Question from './components/Question.jsx';
/* /*
* show video /hikes/someVideo * show video /hikes/someVideo
@ -12,9 +11,6 @@ export default {
component: Hikes, component: Hikes,
childRoutes: [{ childRoutes: [{
path: ':dashedName', path: ':dashedName',
component: Lecture component: Hike
}, {
path: ':dashedName/questions/:number',
component: Question
}] }]
}; };

View File

@ -1,9 +1,13 @@
import helmet from 'helmet'; import helmet from 'helmet';
const trusted = [ let trusted = [
"'self'" "'self'"
]; ];
if (process.env.NODE_ENV !== 'production') {
trusted.push('ws://localhost:3001');
}
export default function csp() { export default function csp() {
return helmet.csp({ return helmet.csp({
defaultSrc: trusted, defaultSrc: trusted,