diff --git a/client/index.js b/client/index.js
index e775b6ceca..862b31cdf0 100644
--- a/client/index.js
+++ b/client/index.js
@@ -3,20 +3,23 @@ import React from 'react';
import { Router } from 'react-router';
import { history } from 'react-router/lib/BrowserHistory';
import debugFactory from 'debug';
-import { Cat } from 'thundercats';
+import { Render } from 'thundercats-react';
import { app$ } from '../common/app';
const debug = debugFactory('fcc:client');
const DOMContianer = document.getElementById('fcc');
-const fcc = new Cat();
Rx.longStackSupport = !!debug.enabled;
// returns an observable
app$(history)
- .flatMap(([ initialState ]) => {
- return fcc.render(React.createElement(Router, initialState), DOMContianer);
+ .flatMap(({ initialState, AppCat }) => {
+ return Render(
+ AppCat(),
+ React.createElement(Router, initialState),
+ DOMContianer
+ );
})
.subscribe(
() => {
diff --git a/common/app/Cat.js b/common/app/Cat.js
new file mode 100644
index 0000000000..d1686b78fc
--- /dev/null
+++ b/common/app/Cat.js
@@ -0,0 +1,9 @@
+import { Cat } from 'thundercats';
+import { HikesActions, HikesStore } from './routes/Hikes/flux';
+
+
+export default Cat()
+ .init(({ instance }) => {
+ instance.register(HikesActions);
+ instance.register(HikesStore, null, instance);
+ });
diff --git a/common/app/app-stream.jsx b/common/app/app-stream.jsx
index 2942a38371..dcba9b7ca0 100644
--- a/common/app/app-stream.jsx
+++ b/common/app/app-stream.jsx
@@ -2,6 +2,7 @@ import Rx from 'rx';
import assign from 'object.assign';
import { Router } from 'react-router';
import App from './App.jsx';
+import AppCat from './Cat';
import childRoutes from './routes';
@@ -10,5 +11,8 @@ const router$ = Rx.Observable.fromNodeCallback(Router.run, Router);
const routes = assign({ components: App }, childRoutes);
export default function app$(location) {
- return router$(routes, location);
+ return router$(routes, location)
+ .map(([initialState, transistion]) => {
+ return { initialState, transistion, AppCat };
+ });
}
diff --git a/common/app/routes/Hikes/components/Map.jsx b/common/app/routes/Hikes/components/Map.jsx
index c859638552..4c3ec01e8d 100644
--- a/common/app/routes/Hikes/components/Map.jsx
+++ b/common/app/routes/Hikes/components/Map.jsx
@@ -1,33 +1,46 @@
-import React from 'react';
+import React, { PropTypes } from 'react';
import stampit from 'react-stampit';
import { Link } from 'react-router';
+import { contain } from 'thundercats-react';
import { ListGroup, ListGroupItem, Panel } from 'react-bootstrap';
-import videos from '../videos.json';
-export default stampit(React, {
- displayName: 'HikesMap',
+export default contain(
+ {
+ store: 'hikesStore',
+ fetchAction: 'hikesActions.fetchHikes'
+ },
+ stampit(React, {
+ displayName: 'HikesMap',
- render() {
+ propTypes: {
+ hikes: PropTypes.array
+ },
+
+ render() {
+ const {
+ hikes
+ } = this.props;
+
+ const vidElements = hikes.map(({ name, id }) => {
+ return (
+
+
+ { name }
+
+
+ );
+ });
- const vidElements = videos.map(({ title, id }) => {
return (
-
-
- { title }
-
-
+
+
+ Welcome To Hikes!
+
+
+ { vidElements }
+
+
);
- });
-
- return (
-
-
- Welcome To Hikes!
-
-
- { vidElements }
-
-
- );
- }
-});
+ }
+ })
+);
diff --git a/common/app/routes/Hikes/flux/Actions.js b/common/app/routes/Hikes/flux/Actions.js
new file mode 100644
index 0000000000..970c9706fe
--- /dev/null
+++ b/common/app/routes/Hikes/flux/Actions.js
@@ -0,0 +1,34 @@
+import { Actions } from 'thundercats';
+import debugFactory from 'debug';
+import Fetchr from 'fetchr';
+
+const debug = debugFactory('freecc:hikes:actions');
+const service = new Fetchr({
+ xhrPath: '/services'
+});
+
+export default Actions({
+ // start fetching hikes
+ fetchHikes: null,
+ // set hikes on store
+ setHikes: null,
+
+ getHike(id) {
+ return { id };
+ }
+})
+ .refs({ displayName: 'HikesActions' })
+ .init(({ instance }) => {
+ // set up hikes fetching
+ // TODO(berks): check if store is already primed
+ instance.fetchHikes.subscribe(
+ () => {
+ service.read('hikes', null, null, (err, hikes) => {
+ if (err) {
+ debug('an error occured fetching hikes', err);
+ }
+ instance.setHikes({ hikes });
+ });
+ }
+ );
+ });
diff --git a/common/app/routes/Hikes/flux/Store.js b/common/app/routes/Hikes/flux/Store.js
index e69de29bb2..be3e675c84 100644
--- a/common/app/routes/Hikes/flux/Store.js
+++ b/common/app/routes/Hikes/flux/Store.js
@@ -0,0 +1,19 @@
+import { Store } from 'thundercats';
+
+const initialValue = {
+ hikes: [],
+ isPrimed: false
+};
+
+export default Store(initialValue)
+ .refs({ displayName: 'HikesStore'})
+ .init(({ instance, args }) => {
+ const [cat] = args;
+ let {
+ setHikes
+ // getHike
+ } = cat.getActions('hikesActions');
+ instance.register(Store.setter(setHikes));
+
+ return instance;
+ });
diff --git a/common/app/routes/Hikes/flux/index.js b/common/app/routes/Hikes/flux/index.js
new file mode 100644
index 0000000000..05980cb3ff
--- /dev/null
+++ b/common/app/routes/Hikes/flux/index.js
@@ -0,0 +1,2 @@
+export { default as HikesActions } from './Actions';
+export { default as HikesStore } from './Store';
diff --git a/package.json b/package.json
index 48f258bcbb..5e383ce192 100644
--- a/package.json
+++ b/package.json
@@ -51,7 +51,7 @@
"express-session": "~1.9.2",
"express-state": "^1.2.0",
"express-validator": "~2.8.0",
- "fetchr": "^0.4.16",
+ "fetchr": "^0.5.12",
"font-awesome": "~4.3.0",
"forever": "~0.14.1",
"frameguard": "^0.2.2",
@@ -97,7 +97,8 @@
"rx": "^2.5.3",
"sanitize-html": "~1.6.1",
"source-map-support": "^0.3.2",
- "thundercats": "^2.0.0-rc6",
+ "thundercats": "^2.0.0-rc8",
+ "thundercats-react": "0.0.3",
"twit": "~1.1.20",
"uglify-js": "~2.4.15",
"validator": "~3.22.1",
diff --git a/server/boot/a-react.js b/server/boot/a-react.js
index be7e2b5858..9d13bf60b8 100644
--- a/server/boot/a-react.js
+++ b/server/boot/a-react.js
@@ -3,7 +3,7 @@ import Router from 'react-router';
import Location from 'react-router/lib/Location';
import debugFactory from 'debug';
import { app$ } from '../../common/app';
-import { Cat } from 'thundercats';
+import { RenderToString } from 'thundercats-react';
const debug = debugFactory('freecc:servereact');
@@ -25,23 +25,23 @@ export default function reactSubRouter(app) {
app.use(router);
function serveReactApp(req, res, next) {
- const fcc = new Cat();
const location = new Location(req.path, req.query);
// returns a router wrapped app
app$(location)
// if react-router does not find a route send down the chain
- .filter(function([ initialState ]) {
+ .filter(function({ initialState }) {
if (!initialState) {
debug('tried to find %s but got 404', location.pathname);
return next();
}
return !!initialState;
})
- .flatMap(function([ initialState ]) {
+ .flatMap(function({ initialState, AppCat }) {
// call thundercats renderToString
// prefetches data and sets up it up for current state
- return fcc.renderToString(
+ return RenderToString(
+ AppCat(),
React.createElement(Router, initialState)
);
})
diff --git a/server/boot/a-services.js b/server/boot/a-services.js
new file mode 100644
index 0000000000..3cb288a99d
--- /dev/null
+++ b/server/boot/a-services.js
@@ -0,0 +1,8 @@
+import Fetchr from 'fetchr';
+import getHikesService from '../services/hikes';
+
+export default function bootServices(app) {
+ const hikesService = getHikesService(app);
+ Fetchr.registerFetcher(hikesService);
+ app.use('/services', Fetchr.middleware());
+}
diff --git a/server/boot/challenge.js b/server/boot/challenge.js
index 9562829a0f..0d700ff620 100644
--- a/server/boot/challenge.js
+++ b/server/boot/challenge.js
@@ -108,7 +108,7 @@ module.exports = function(app) {
app.use(router);
function returnNextChallenge(req, res, next) {
- var completed = req.user.completedChallenges.map(function (elem) {
+ var completed = req.user.completedChallenges.map(function(elem) {
return elem.id;
});
@@ -157,12 +157,12 @@ module.exports = function(app) {
}
function returnCurrentChallenge(req, res, next) {
- var completed = req.user.completedChallenges.map(function (elem) {
+ var completed = req.user.completedChallenges.map(function(elem) {
return elem.id;
});
req.user.uncompletedChallenges = utils.allChallengeIds()
- .filter(function (elem) {
+ .filter(function(elem) {
if (completed.indexOf(elem) === -1) {
return elem;
}
@@ -227,12 +227,12 @@ module.exports = function(app) {
challengeName: challenge.name,
dashedName: challenge.dashedName,
challengeBlock: R.head(R.flatten(Object.keys(challengeMapWithIds)
- .map(function (key) {
+ .map(function(key) {
return challengeMapWithIds[key]
- .filter(function (elem) {
+ .filter(function(elem) {
return elem === ('' + challenge.id);
})
- .map(function () {
+ .map(function() {
return key;
});
})
@@ -263,15 +263,14 @@ module.exports = function(app) {
environment: utils.whichEnvironment()
};
- //TODO Berkeley
+ // TODO Berkeley
var challengeView = {
0: 'coursewares/showHTML',
1: 'coursewares/showJS',
2: 'coursewares/showVideo',
3: 'coursewares/showZiplineOrBasejump',
4: 'coursewares/showZiplineOrBasejump',
- 5: 'coursewares/showBonfire',
- 6: 'coursewares/showHike'
+ 5: 'coursewares/showBonfire'
};
saveUser(req.user)
diff --git a/server/boot/fieldGuide.js b/server/boot/fieldGuide.js
index 62a5a61fbd..ef723a6b39 100644
--- a/server/boot/fieldGuide.js
+++ b/server/boot/fieldGuide.js
@@ -6,6 +6,14 @@ var utils = require('../utils');
var allFieldGuideNamesAndIds = utils.allFieldGuideNamesAndIds();
+// order here determine order on all-articles page
+const categories = [
+ 'orientation',
+ 'FYI',
+ 'outreach',
+ 'contact'
+];
+
module.exports = function(app) {
var router = app.loopback.Router();
var FieldGuide = app.models.FieldGuide;
@@ -88,14 +96,6 @@ module.exports = function(app) {
completedFieldGuides = req.user.completedFieldGuides;
}
- // order here determine order on page
- const categories = [
- 'orientation',
- 'FYI',
- 'outreach',
- 'contact'
- ];
-
// produces an array of arrays of field guides ordered by the above
// i.e. [[...orientFieldGuides][...FYIfieldGuides]...]
const orderFieldGuides = categories
diff --git a/server/services/hikes.js b/server/services/hikes.js
new file mode 100644
index 0000000000..f019fe0d8d
--- /dev/null
+++ b/server/services/hikes.js
@@ -0,0 +1,15 @@
+export default function hikesService(app) {
+ const Challenge = app.models.Challenge;
+
+ return {
+ name: 'hikes',
+ read: (req, resource, params, config, cb) => {
+ Challenge.find({ where: { challengeType: '6' } }, (err, hikes) => {
+ if (err) {
+ return cb(err);
+ }
+ cb(null, hikes);
+ });
+ }
+ };
+}