openreplay/frontend/app/duck/requestStateCreator.js
2021-05-01 15:12:01 +05:30

80 lines
2.2 KiB
JavaScript

import { List, Map } from 'immutable';
export class RequestTypes {
constructor(type) {
this.REQUEST = `${ type }_REQUEST`;
this.SUCCESS = `${ type }_SUCCESS`;
this.FAILURE = `${ type }_FAILURE`;
}
toArray() {
return [ this.REQUEST, this.SUCCESS, this.FAILURE ];
}
}
const defaultReducer = (state = Map()) => state;
const initialState = Map({
loading: false,
errors: null,
});
const addRequestState = (
types,
reducer = defaultReducer,
) => {
const typesArray = Array.isArray(types) ? types : [ types ];
const requestEvents = typesArray.map(a => a.REQUEST);
const successEvents = typesArray.map(a => a.SUCCESS);
const failureEvents = typesArray.map(a => a.FAILURE);
let loadingCounter = 0;
return (inputState, action = {}) => {
let state = reducer(inputState, action);
// initialization
state = inputState ? state : state.merge(initialState);
if (requestEvents.includes(action.type)) {
loadingCounter += 1;
return state.set('loading', loadingCounter > 0).set('errors', null);
}
if (successEvents.includes(action.type)) {
loadingCounter -= 1;
return state.set('loading', loadingCounter > 0).set('errors', null);
}
if (failureEvents.includes(action.type)) {
loadingCounter -= 1;
return state.set('loading', loadingCounter > 0).set('errors', List(action.errors));
}
return state;
};
};
// TODO: Errors
/**
* @types: RequestTypes - array or single
* or object like {'state1': RequestTypes, 'state2': [RequestTypes] ... }
* @reducer: wrapped reducer
* */
export default (
types,
reducer = defaultReducer,
) => {
if (types instanceof RequestTypes || types instanceof Array) {
return addRequestState(types, reducer);
}
const keys = Object.keys(types).filter(key => key !== '_');
const reducers = {};
keys.map((key) => { reducers[ key ] = addRequestState(types[ key ]); });
const actualReducer = types._ ? addRequestState(types._, reducer) : reducer;
return (inputState, action = {}) => {
let state = actualReducer(inputState, action);
keys.map((key) => {
state = state.update(key, subState => reducers[ key ](subState, action));
});
return state;
};
};