Skip to content

Commit

Permalink
improved storeConfig
Browse files Browse the repository at this point in the history
  • Loading branch information
yankeeinlondon committed Mar 16, 2017
1 parent 912235a commit 30e79da
Show file tree
Hide file tree
Showing 13 changed files with 243 additions and 5 deletions.
File renamed without changes.
11 changes: 11 additions & 0 deletions addon/redux/actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* ACTION CREATORS
*
* There no action creators to start. Add them using ember-cli with the following
* syntax:
*
* ember generate action [name]
*/


export default {};
30 changes: 30 additions & 0 deletions addon/redux/middleware/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* MIDDLEWARE INDEX
*
* Middleware is an important concept in Redux and follows conventions that won't be
* completely foreign to you if you used popular NodeJS servers like Express or Koa.
*
* In Redux a middleware must provide the signature:
*
* (store) => (next) => (action) => { ... }
*
* This file, is meant as a manager of middleware's that you'll use in this application
* and typically you will not have to touch this file directly. Instead, if you want to
* add a middleware to your application just use ember-cli:
*
* ember generate middleware [name]
* ember destroy middleware [name]
*
* This will create a file '[name].js' who's job it is to export a function which when called
* will produce a middleware function.
*
* It's good to note that in many cases you'll not need to be overly creative as there are
* many pre-existing middleware's you can take off the shelf and use. In fact, by default
* we've added two that are VERY common in Redux apps by default both because we think you'll
* want to use them but also because they serve as a small example (of pulling off the self
* more than rolling your own).
*/

import thunk from './thunk';

export default [thunk];
17 changes: 17 additions & 0 deletions addon/redux/middleware/thunk.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* thunk Middleware
*/
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}

return next(action);
};
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;
37 changes: 37 additions & 0 deletions addon/redux/state-initializers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* For many Ember apps you may choose to ignore the state-initializer but
* with a growing tendency for offline applications it is becoming increasingly
* likely that you'll want some strategy for initializing your state.
*
* Initialization acts structurally in a similar way to reducers. In both instances
* the overall state machine is broken down into discrete parts. Then each part of the
* state tree is delegated to a separate file for processing.
*
* You can of course, address intialisation across all state here as a singular
* file but typically you'll actually want to initialize state by sections in which case you'll
* want to use the following ember-cli commands:
*
* ember generate state-initializer [name]
* ember destroy state-initializer [name]
*
* Using these two commands will ensure that this file is managed for you.
*/

const modules = [];

export function loadState(config) {
const state = {};
modules.map(m => {
state[m] = this[m].loadState(config);
});

return state;
}

export function saveState(pre, post) {
modules.map(m => {
if(get(pre, m) !== get(post, m)) {
get(this, m).saveState(pre, post);
}
});
}
14 changes: 14 additions & 0 deletions addon/redux/storeConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import redux from 'npm:redux';
import reducers from './reducers/index';
import enhancers from './enhancers/index';
import middleware from './middleware/index';
import initialState from './state-initializers/index';
import config from 'ember-get-config';

const { createStore, applyMiddleware, compose } = redux;
const devTools = window.devToolsExtension ? window.devToolsExtension() : f => f;
const createStoreWithMiddleware = compose(applyMiddleware(...middleware), devTools, enhancers)(createStore);

export default function() {
return createStoreWithMiddleware(reducers, initialState.loadState(config));
}
2 changes: 2 additions & 0 deletions addon/services/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ const fb = Ember.Service.extend({
},

set(path, value, name) {
console.log(`setting: ${path}, dispatch of: ${name}`);
return this._writeToDB('set', path, value, name);
},
push(path, value, name) {
Expand All @@ -126,6 +127,7 @@ const fb = Ember.Service.extend({
return new Promise((resolve, reject) => {
app.database().ref(path)[operation](value)
.then((result) => {
console.log('success:', `${name}/${opName}_SUCCESS`);
dispatch({type: `${name}/${opName}_SUCCESS`, path, value });
resolve(result);
})
Expand Down
24 changes: 24 additions & 0 deletions app/redux/reducers/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Immutable from 'npm:immutable';
/**
* app Reducer
*/
const defaultState = Immutable.OrderedMap();
const reducer = (state, action) => {

switch(action.type) {

case '@firebase/app/INITIALIZED':
return state.merge({
initialized: true,
appName: action.appName,
url: action.url
});


default:
return state || defaultState;
} // end switch

};

export default reducer;
36 changes: 36 additions & 0 deletions app/redux/reducers/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Immutable from 'npm:immutable';
/**
* counterparties Reducer
*/
const defaultState = Immutable.OrderedMap();
const reducer = (state, action) => {

switch(action.type) {
case '@firebase/auth/CURRENT_USER_CHANGED':
return state.merge({currentUser: action.user});

case '@firebase/auth/SUCCESS':
return state
.merge({
isAuthenticated: true,
currentUser: action.user,
})
.delete('code')
.delete('message');

case '@firebase/auth/SIGN_OUT':
case '@firebase/auth/FAILURE':
return state.merge({
isAuthenticated: false,
currentUser: null,
code: action.code,
message: action.message,
});

default:
return state || defaultState;
} // end switch

};

export default reducer;
26 changes: 26 additions & 0 deletions app/redux/reducers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import ReduxImmutable from 'npm:redux-immutable';
const { combineReducers } = ReduxImmutable;
/**
* This is the master reducer, it partitions the jobs amounts
* one or more other reducers which take on responsibility for
* a discrete part of the state tree.
*
* Use the "ember generate reducer [name]" command to create additional
* reducers (and "ember destroy" to remove).
*
* Alternatively, if you have a very simple state model, you can just use
* this file as the single reducer used by the store.
*
* Note: only VERY small applications should be managed by a single
* reducer file.
*/

import app from './app';
import auth from './auth';
import watchers from './watchers';

export default combineReducers({
app,
auth,
watchers,
});
26 changes: 26 additions & 0 deletions app/redux/reducers/watchers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Immutable from 'npm:immutable';
/**
* counterparties Reducer
*/
const defaultState = Immutable.List();
const reducer = (state, action) => {

switch(action.type) {

case '@firebase/WATCHER_ADD':
return state.push(action.watcher);

case '@firebase/WATCHER_REMOVE':
return defaultState;

case '@firebase/auth/SIGN_OUT':
return defaultState;


default:
return state || defaultState;
} // end switch

};

export default reducer;
4 changes: 2 additions & 2 deletions tests/dummy/app/redux/reducers/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import redux from 'npm:redux';
const { combineReducers } = redux;
import ReduxImmutable from 'npm:redux-immutable';
const { combineReducers } = ReduxImmutable;
/**
* This is the master reducer, it partitions the jobs amounts
* one or more other reducers which take on responsibility for
Expand Down
21 changes: 18 additions & 3 deletions tests/dummy/app/redux/storeConfig.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
import redux from 'npm:redux';
import { combineReducers } from 'npm:redux-immutable';
import Immutable from 'npm:immutable';

import reducers from './reducers/index';
import enhancers from './enhancers/index';
import middleware from './middleware/index';
import initialState from './state-initializers/index';
import config from 'ember-get-config';

const { createStore, applyMiddleware, compose } = redux;
const devTools = window.devToolsExtension ? window.devToolsExtension() : f => f;
const devTools = window.devToolsExtension ? window.devToolsExtension({serialize: true}) : f => f;
const createStoreWithMiddleware = compose(applyMiddleware(...middleware), devTools, enhancers)(createStore);
const initialize = (c) => {
const raw = Object.keys(initialState)
.map(i => {
return { [i]: initialState[i].loadState(c) };
})
.reduce( (prev, current) => Object.assign({}, prev, {[current.key]: current.value}) );
return Immutable.Map(raw);
};

export default function(addonReducers) {
const combinedReducers = typeof reducers === 'function'
? reducers
: combineReducers(Object.assign({}, reducers, addonReducers));

export default function() {
return createStoreWithMiddleware(reducers, initialState.loadState(config));
return createStoreWithMiddleware(combinedReducers, initialize(config));
}

0 comments on commit 30e79da

Please sign in to comment.