Skip to content

Instantly share code, notes, and snippets.

@jmreidy
Last active January 26, 2016 14:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jmreidy/63c64989d88bd3f6c620 to your computer and use it in GitHub Desktop.
Save jmreidy/63c64989d88bd3f6c620 to your computer and use it in GitHub Desktop.
import {Action} from '../actions/actionTypes';
import {isMatch} from 'lodash';
interface actionHandler {
(action:Action, state:any):Object;
}
export class ActionMatcher {
tests:Array<(action:Action) => boolean>;
handler:actionHandler;
constructor(type:string) {
this.tests = [(action:Action) => action.type === type];
}
withMeta(metaShape:Object):ActionMatcher {
this.tests.push((action:Action) => isMatch(action.meta, metaShape));
return this;
}
isError():ActionMatcher {
this.tests.push((action:Action) => action.error);
return this;
}
then(handler:actionHandler):ActionMatcher {
this.handler = handler;
return this;
}
exec(action:Action, state:any):any {
let nextState = state;
const match = this.tests.reduce((agg, t) => agg && (t(action)), true);
if (match) {
nextState = this.handler(action, state);
}
return nextState;
}
}
export function extend (extension:{}) {
Object.keys(extension).map((key) => {
ActionMatcher.prototype[key] = extension[key];
});
}
const matchAction = (type:string):ActionMatcher => {
return new ActionMatcher(type);
}
export default matchAction;
import {Dispatch} from 'redux';
export interface Action {
type: string;
error?:boolean;
payload?:any;
meta?:{};
}
interface ContainerActionMeta {
field?:string,
containerName: string;
}
export interface ContainerAction extends Action {
meta: ContainerActionMeta;
}
const createReducer = (matchers:[ActionMatcher], initialState:any) => (state = initialState, action:Action) => {
return matchers.reduce((s, matcher) => matcher.exec(action, s), state);
}
const updateField = (action:ContainerAction, state:any) => state.set(action.meta.field, action.payload);
export default createReducer([
matchAction(UPDATE_CONTAINER_STATE)
.withMeta({containerName: LOGIN_SCREEN, field: 'email'})
.then(updateField),
matchAction(UPDATE_CONTAINER_STATE)
.withMeta({containerName: LOGIN_SCREEN, field: 'password'})
.then(updateField),
matchAction(LOGIN)
.withMeta({phase: START})
.then((action, state) => state.set('loading', true)),
matchAction(LOGIN)
.withMeta({phase: SUCCESS})
.then((action, state) => state.set({'loggedIn': true, 'loading': false}),
matchAction(LOGIN)
.isError()
.then((action, state) => state.set('errorMessage', action.payload))
], new LoginScreenStateRecord());
@jmreidy
Copy link
Author

jmreidy commented Jan 26, 2016

key bit is the bottom:

export default createReducer([
  matchAction(UPDATE_CONTAINER_STATE)
    .withMeta({containerName: LOGIN_SCREEN, field: 'email'})
    .then(updateField),

  matchAction(UPDATE_CONTAINER_STATE)
    .withMeta({containerName: LOGIN_SCREEN, field: 'password'})
    .then(updateField),

  matchAction(LOGIN)
    .withMeta({phase: START})
    .then((action, state) => state.set('loading', true)),

  matchAction(LOGIN)
    .withMeta({phase: SUCCESS})
    .then((action, state) => state.set({'loggedIn': true, 'loading': false}),

  matchAction(LOGIN)
    .isError()
    .then((action, state) => state.set('errorMessage', action.payload))
], new LoginScreenStateRecord());

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment