From de1d931b8200ca8a92daf051726786d24d62b713 Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Mon, 13 Jul 2015 00:25:01 -0700 Subject: [PATCH] add hikes/map pulls hikes out of db and renders --- client/index.js | 11 ++-- common/app/Cat.js | 9 ++++ common/app/app-stream.jsx | 6 ++- common/app/routes/Hikes/components/Map.jsx | 63 +++++++++++++--------- common/app/routes/Hikes/flux/Actions.js | 34 ++++++++++++ common/app/routes/Hikes/flux/Store.js | 19 +++++++ common/app/routes/Hikes/flux/index.js | 2 + package.json | 5 +- server/boot/a-react.js | 10 ++-- server/boot/a-services.js | 8 +++ server/boot/challenge.js | 17 +++--- server/boot/fieldGuide.js | 16 +++--- server/services/hikes.js | 15 ++++++ 13 files changed, 161 insertions(+), 54 deletions(-) create mode 100644 common/app/Cat.js create mode 100644 common/app/routes/Hikes/flux/Actions.js create mode 100644 common/app/routes/Hikes/flux/index.js create mode 100644 server/boot/a-services.js create mode 100644 server/services/hikes.js 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); + }); + } + }; +}