add user stores/actions

construct fetchr on every request
pull/1382/head
Berkeley Martinez 2015-07-24 17:52:07 -07:00
parent 77a0a82118
commit a1a4ac883d
10 changed files with 131 additions and 34 deletions

View File

@ -1,8 +1,9 @@
import Rx from 'rx';
import React from 'react';
import Fetchr from 'fetchr';
import debugFactory from 'debug';
import { Router } from 'react-router';
import { history } from 'react-router/lib/BrowserHistory';
import debugFactory from 'debug';
import { hydrate } from 'thundercats';
import { Render } from 'thundercats-react';
@ -11,6 +12,9 @@ import { app$ } from '../common/app';
const debug = debugFactory('fcc:client');
const DOMContianer = document.getElementById('fcc');
const catState = window.__fcc__.data || {};
const services = new Fetchr({
xhrPath: '/services'
});
Rx.longStackSupport = !!debug.enabled;
@ -18,7 +22,7 @@ Rx.longStackSupport = !!debug.enabled;
app$(history)
.flatMap(
({ AppCat }) => {
const appCat = AppCat();
const appCat = AppCat(null, services);
return hydrate(appCat, catState)
.map(() => appCat);
},

View File

@ -1,28 +1,37 @@
import React, { PropTypes } from 'react';
import { contain } from 'thundercats-react';
import { Row } from 'react-bootstrap';
import { Nav } from './components/Nav';
import { Footer } from './components/Footer';
export default class extends React.Component {
constructor(props) {
super(props);
}
export default contain(
{
store: 'appStore',
fetchAction: 'appActions.getUser',
getPayload(props) {
return {
isPrimed: !!props.username
};
}
},
React.createClass({
displayName: 'FreeCodeCamp',
static displayName = 'FreeCodeCamp'
static propTypes = {
children: PropTypes.node
}
propTypes: {
children: PropTypes.node
},
render() {
return (
<div>
<Nav />
<Row>
{ this.props.children }
</Row>
<Footer />
</div>
);
}
}
render() {
return (
<div>
<Nav />
<Row>
{ this.props.children }
</Row>
<Footer />
</div>
);
}
})
);

View File

@ -1,9 +1,11 @@
import { Cat } from 'thundercats';
import { HikesActions, HikesStore } from './routes/Hikes/flux';
import { AppActions, AppStore } from './flux';
export default Cat()
.init(({ instance }) => {
instance.register(HikesActions);
instance.register(HikesStore, null, instance);
.init(({ instance: cat, args: [services] }) => {
cat.register(AppActions, null, services);
cat.register(AppStore, null, cat);
cat.register(HikesActions, null, services);
cat.register(HikesStore, null, cat);
});

View File

@ -0,0 +1,31 @@
import { Actions } from 'thundercats';
import debugFactory from 'debug';
const debug = debugFactory('freecc:app:actions');
export default Actions({
setUser({ username, picture, progressTimestamps = [] }) {
return {
username,
picture,
points: progressTimestamps.length
};
},
getUser: 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);
});
});
});

18
common/app/flux/Store.js Normal file
View File

@ -0,0 +1,18 @@
import { Store } from 'thundercats';
const { createRegistrar, setter } = Store;
const initValue = {
username: null,
picture: null,
points: 0
};
export default Store(initValue)
.refs({ displayName: 'AppStore' })
.init(({ instance: appStore, args: [cat] }) => {
const { setUser } = cat.getActions('appActions');
const register = createRegistrar(appStore);
register(setter(setUser));
return appStore;
});

2
common/app/flux/index.js Normal file
View File

@ -0,0 +1,2 @@
export AppActions from './Actions';
export AppStore from './Store';

View File

@ -1,12 +1,8 @@
import { Actions } from 'thundercats';
import assign from 'object.assign';
import debugFactory from 'debug';
import Fetchr from 'fetchr';
const debug = debugFactory('freecc:hikes:actions');
const service = new Fetchr({
xhrPath: '/services'
});
function getCurrentHike(hikes =[{}], dashedName, currentHike) {
if (!dashedName) {
@ -36,7 +32,7 @@ export default Actions({
setHikes: null
})
.refs({ displayName: 'HikesActions' })
.init(({ instance }) => {
.init(({ instance, args: [services] }) => {
// set up hikes fetching
instance.fetchHikes.subscribe(
({ isPrimed, dashedName }) => {
@ -53,7 +49,7 @@ export default Actions({
}
});
}
service.read('hikes', null, null, (err, hikes) => {
services.read('hikes', null, null, (err, hikes) => {
if (err) {
debug('an error occurred fetching hikes', err);
}

View File

@ -1,11 +1,12 @@
import React from 'react';
import Router from 'react-router';
import Fetchr from 'fetchr';
import Location from 'react-router/lib/Location';
import debugFactory from 'debug';
import { app$ } from '../../common/app';
import { RenderToString } from 'thundercats-react';
const debug = debugFactory('freecc:servereact');
const debug = debugFactory('freecc:react-server');
// add routes here as they slowly get reactified
// remove their individual controllers
@ -25,6 +26,7 @@ export default function reactSubRouter(app) {
app.use(router);
function serveReactApp(req, res, next) {
const services = new Fetchr({ req });
const location = new Location(req.path, req.query);
// returns a router wrapped app
@ -42,7 +44,7 @@ export default function reactSubRouter(app) {
// prefetches data and sets up it up for current state
debug('rendering to string');
return RenderToString(
AppCat(),
AppCat(null, services),
React.createElement(Router, initialState)
);
})

View File

@ -1,8 +1,11 @@
import Fetchr from 'fetchr';
import getHikesService from '../services/hikes';
import getUserServices from '../services/user';
export default function bootServices(app) {
const hikesService = getHikesService(app);
const userServices = getUserServices(app);
Fetchr.registerFetcher(hikesService);
Fetchr.registerFetcher(userServices);
app.use('/services', Fetchr.middleware());
}

30
server/services/user.js Normal file
View File

@ -0,0 +1,30 @@
import debugFactory from 'debug';
import assign from 'object.assign';
const censor = '**********************:P********';
const debug = debugFactory('freecc:services:user');
const protectedUserFields = {
id: censor,
password: censor,
profiles: censor
};
export default function userServices(/* app */) {
return {
name: 'user',
read: (req, resource, params, config, cb) => {
let { user } = req;
if (user) {
debug('user is signed in');
// Zalgo!!!
return process.nextTick(() => {
cb(null, assign({}, user.toJSON(), protectedUserFields));
});
}
debug('user is not signed in');
return process.nextTick(() => {
cb(null, {});
});
}
};
}