Make structure changes to hikes
This commit is contained in:
@ -4,46 +4,42 @@ import debugFactory from 'debug';
|
||||
const debug = debugFactory('freecc:app:actions');
|
||||
|
||||
export default Actions({
|
||||
shouldBindMethods: true,
|
||||
refs: { displayName: 'AppActions' },
|
||||
|
||||
setTitle(title = 'Learn To Code') {
|
||||
return { title: title + '| Free Code Camp' };
|
||||
return { title: title + ' | Free Code Camp' };
|
||||
},
|
||||
|
||||
setUser({
|
||||
username,
|
||||
picture,
|
||||
progressTimestamps = [],
|
||||
isFrontEndCert,
|
||||
isFullStackCert
|
||||
}) {
|
||||
return {
|
||||
username,
|
||||
picture,
|
||||
points: progressTimestamps.length,
|
||||
isFrontEndCert,
|
||||
isFullStackCert
|
||||
};
|
||||
getUser({ isPrimed }) {
|
||||
if (isPrimed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
debug('fetching user data');
|
||||
return this.readService$('user', null, null)
|
||||
.map(function({
|
||||
username,
|
||||
picture,
|
||||
progressTimestamps = [],
|
||||
isFrontEndCert,
|
||||
isFullStackCert
|
||||
}) {
|
||||
return {
|
||||
username,
|
||||
picture,
|
||||
points: progressTimestamps.length,
|
||||
isFrontEndCert,
|
||||
isFullStackCert
|
||||
};
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
},
|
||||
|
||||
getUser: null,
|
||||
updateRoute(route) {
|
||||
return { route };
|
||||
},
|
||||
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;
|
||||
});
|
||||
});
|
||||
|
@ -18,15 +18,15 @@ export default Store({
|
||||
value: initValue
|
||||
},
|
||||
init({ instance: appStore, args: [cat] }) {
|
||||
const { updateRoute, setUser, setTitle } = cat.getActions('appActions');
|
||||
const { updateRoute, getUser, setTitle } = cat.getActions('appActions');
|
||||
const register = createRegistrar(appStore);
|
||||
let { setHikes } = cat.getActions('hikesActions');
|
||||
const { fetchHikes } = cat.getActions('hikesActions');
|
||||
|
||||
// app
|
||||
register(setter(fromMany(setUser, setTitle, updateRoute)));
|
||||
register(setter(fromMany(getUser, setTitle, updateRoute)));
|
||||
|
||||
// hikes
|
||||
register(setHikes);
|
||||
register(fetchHikes);
|
||||
|
||||
return appStore;
|
||||
}
|
||||
|
56
common/app/routes/Hikes/components/Hike.jsx
Normal file
56
common/app/routes/Hikes/components/Hike.jsx
Normal 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>
|
||||
);
|
||||
}
|
||||
});
|
@ -9,7 +9,10 @@ import HikesMap from './Map.jsx';
|
||||
|
||||
export default contain(
|
||||
{
|
||||
store: 'hikesStore',
|
||||
store: 'appStore',
|
||||
map(state) {
|
||||
return state.hikesApp;
|
||||
},
|
||||
actions: ['appActions'],
|
||||
fetchAction: 'hikesActions.fetchHikes',
|
||||
getPayload: ({ hikes, params }) => ({
|
||||
@ -54,8 +57,12 @@ export default contain(
|
||||
return (
|
||||
<div>
|
||||
<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>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,5 +1,5 @@
|
||||
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 Vimeo from 'react-vimeo';
|
||||
import debugFactory from 'debug';
|
||||
@ -19,8 +19,6 @@ export default React.createClass({
|
||||
|
||||
handleFinish() {
|
||||
debug('loading questions');
|
||||
const { dashedName } = this.props.params;
|
||||
this.history.pushState(null, `/hikes/${dashedName}/questions/1`);
|
||||
},
|
||||
|
||||
renderTranscript(transcript, dashedName) {
|
||||
@ -31,7 +29,6 @@ export default React.createClass({
|
||||
|
||||
render() {
|
||||
const {
|
||||
title,
|
||||
challengeSeed = ['1'],
|
||||
description = []
|
||||
} = this.props.currentHike;
|
||||
@ -39,31 +36,22 @@ export default React.createClass({
|
||||
|
||||
const [ id ] = challengeSeed;
|
||||
|
||||
const videoTitle = <h2>{ title }</h2>;
|
||||
return (
|
||||
<Col xs={ 12 }>
|
||||
<Row>
|
||||
<Panel className={ 'text-center' } title={ videoTitle }>
|
||||
<Vimeo
|
||||
onError={ this.handleError }
|
||||
onFinish= { this.handleFinish }
|
||||
videoId={ id } />
|
||||
</Panel>
|
||||
<Vimeo
|
||||
onError={ this.handleError }
|
||||
onFinish= { this.handleFinish }
|
||||
videoId={ id } />
|
||||
</Row>
|
||||
<Row>
|
||||
<Col xs={ 12 }>
|
||||
<Panel>
|
||||
{ this.renderTranscript(description, dashedName) }
|
||||
</Panel>
|
||||
<Panel>
|
||||
<Button
|
||||
block={ true }
|
||||
bsSize='large'
|
||||
onClick={ this.handleFinish }>
|
||||
Take me to the Questions
|
||||
</Button>
|
||||
</Panel>
|
||||
</Col>
|
||||
{ this.renderTranscript(description, dashedName) }
|
||||
<Button
|
||||
block={ true }
|
||||
bsSize='large'
|
||||
onClick={ this.handleFinish }>
|
||||
Take me to the Questions
|
||||
</Button>
|
||||
</Row>
|
||||
</Col>
|
||||
);
|
||||
|
@ -11,7 +11,7 @@ export default React.createClass({
|
||||
|
||||
render() {
|
||||
const {
|
||||
hikes
|
||||
hikes = [{}]
|
||||
} = this.props;
|
||||
|
||||
const vidElements = hikes.map(({ title, dashedName}) => {
|
||||
|
@ -16,7 +16,7 @@ const debug = debugFactory('freecc:hikes');
|
||||
const ANSWER_THRESHOLD = 200;
|
||||
|
||||
export default React.createClass({
|
||||
displayName: 'Question',
|
||||
displayName: 'Questions',
|
||||
|
||||
mixins: [
|
||||
History,
|
@ -25,49 +25,41 @@ function getCurrentHike(hikes = [{}], dashedName, currentHike) {
|
||||
}
|
||||
|
||||
export default Actions({
|
||||
// start fetching hikes
|
||||
fetchHikes: null,
|
||||
// set hikes on store
|
||||
setHikes: null
|
||||
})
|
||||
.refs({ displayName: 'HikesActions' })
|
||||
.init(({ instance: hikeActions, args: [services] }) => {
|
||||
// set up hikes fetching
|
||||
hikeActions.fetchHikes.subscribe(
|
||||
({ isPrimed, dashedName }) => {
|
||||
if (isPrimed) {
|
||||
return hikeActions.setHikes({
|
||||
transform: (state) => {
|
||||
refs: { displayName: 'HikesActions' },
|
||||
shouldBindMethods: true,
|
||||
fetchHikes({ isPrimed, dashedName }) {
|
||||
if (isPrimed) {
|
||||
return {
|
||||
transform: (state) => {
|
||||
|
||||
const { hikesApp: oldState } = state;
|
||||
const currentHike = getCurrentHike(
|
||||
oldState.hikes,
|
||||
dashedName,
|
||||
oldState.currentHike
|
||||
);
|
||||
const { hikesApp: oldState } = state;
|
||||
const currentHike = getCurrentHike(
|
||||
oldState.hikes,
|
||||
dashedName,
|
||||
oldState.currentHike
|
||||
);
|
||||
|
||||
const hikesApp = { ...oldState, currentHike };
|
||||
return Object.assign({}, state, { hikesApp });
|
||||
}
|
||||
});
|
||||
const hikesApp = { ...oldState, currentHike };
|
||||
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 = {
|
||||
hikes,
|
||||
currentHike: getCurrentHike(hikes, dashedName)
|
||||
};
|
||||
|
||||
return {
|
||||
transform(oldState) {
|
||||
return Object.assign({}, oldState, { hikesApp });
|
||||
}
|
||||
|
||||
const hikesApp = {
|
||||
hikes,
|
||||
currentHike: getCurrentHike(hikes, dashedName)
|
||||
};
|
||||
|
||||
hikeActions.setHikes({
|
||||
transform(oldState) {
|
||||
return Object.assign({}, oldState, { hikesApp });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -1,2 +1 @@
|
||||
export { default as HikesActions } from './Actions';
|
||||
export { default as HikesStore } from './Store';
|
||||
|
@ -1,6 +1,5 @@
|
||||
import Hikes from './components/Hikes.jsx';
|
||||
import Lecture from './components/Lecture.jsx';
|
||||
import Question from './components/Question.jsx';
|
||||
import Hike from './components/Hike.jsx';
|
||||
|
||||
/*
|
||||
* show video /hikes/someVideo
|
||||
@ -12,9 +11,6 @@ export default {
|
||||
component: Hikes,
|
||||
childRoutes: [{
|
||||
path: ':dashedName',
|
||||
component: Lecture
|
||||
}, {
|
||||
path: ':dashedName/questions/:number',
|
||||
component: Question
|
||||
component: Hike
|
||||
}]
|
||||
};
|
||||
|
@ -1,9 +1,13 @@
|
||||
import helmet from 'helmet';
|
||||
|
||||
const trusted = [
|
||||
let trusted = [
|
||||
"'self'"
|
||||
];
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
trusted.push('ws://localhost:3001');
|
||||
}
|
||||
|
||||
export default function csp() {
|
||||
return helmet.csp({
|
||||
defaultSrc: trusted,
|
||||
|
Reference in New Issue
Block a user