src/decorators/bindActions.js
import {bind} from 'alt-utils/lib/decorators';
import flatten from '../utils/flatten';
import {getLevel as getLogLevel, logLevel} from '../utils/logging';
/**
* Decorates a store with any number of viewAction definitions.
*/
export default function bindActions(...args) {
return function decorate(storeClass) {
const calls = flatten(args);
calls.forEach(call => bindViewActionHandler(storeClass, call));
return storeClass;
};
}
function bindViewActionHandler(storeClass, definition) {
const {name, action, reducer, sideEffect, logger, logging} = definition;
const handlerName = `${name}`;
if (storeClass.prototype[handlerName]) throw new Error(`Duplicate handler "${handlerName}"`);
storeClass.prototype[handlerName] = function handleViewAction(payload) {
if (logging || getLogLevel() === logLevel.FORCE) {
logger[payload instanceof Error ? 'error' : 'log'](payload && payload.toJS ? payload.toJS() : payload);
}
const currentState = this.state;
let nextState = currentState;
try {
nextState = reducer && reducer(currentState, payload);
}
catch (error) {
console.error(`${handlerName}: error executing reducer`, error);
}
if (nextState && nextState !== currentState) {
this.setState(nextState);
}
if (sideEffect) {
setTimeout(() => {
try {
sideEffect({state: nextState, prevState: currentState, payload});
}
catch (error) {
console.error(`${handlerName}: error executing sideEffect`, error);
}
});
}
};
const bindActionHandler = bind(action);
bindActionHandler(
storeClass,
handlerName,
Object.getOwnPropertyDescriptor(storeClass.prototype, handlerName)
);
};