UNPKG

redux-tiles

Version:

Library to create and easily compose redux pieces together in less verbose manner

163 lines (147 loc) 4.26 kB
import { Reducer } from "redux"; import { createType } from "../helpers"; import { asyncAction, createResetAction, syncAction } from "./actions"; import { createReducer } from "./reducer"; import { createSelectors } from "./selectors"; import { IAsyncActionTypes, ICreateSelectorsTypes, IData, IOverloadedAction, ISelectors, ISyncActionTypes, ISyncTileParams, ITile, ITileParams, ReducerObject, SyncData } from "./types"; const prefix: string = "Redux_Tiles_"; export interface ITypes { [key: string]: string; } export interface IReducerAction { payload: { data: any } | undefined; error: string | Object | undefined | null; } export function createTile(params: ITileParams): ITile { const { type, fn, caching, nesting, selectorFallback = null } = params; // initial state is equal to empty object, because of possible nesting // basically every object should contain default properties, so we handle // this situation using selectors const initialState: any = nesting ? {} : null; const identificator: string = createType({ type }); const types: ITypes = { START: `${prefix}${identificator}_START`, SUCCESS: `${prefix}${identificator}_SUCCESS`, FAILURE: `${prefix}${identificator}_FAILURE`, RESET: `${prefix}${identificator}_RESET` }; const selectorParams: ICreateSelectorsTypes = { selectorFallback: { isPending: false, error: null, data: selectorFallback, fetched: false }, tileName: type, nesting }; const selectors: ISelectors = createSelectors(selectorParams); const actionParams: IAsyncActionTypes = { START: types.START, SUCCESS: types.SUCCESS, FAILURE: types.FAILURE, fn, type, caching, nesting, selectors }; const action: IOverloadedAction = asyncAction(actionParams); action.reset = createResetAction({ type: types.RESET }); const reducerObject: ReducerObject = { [types.START]: { data: null, isPending: true, error: null, fetched: false }, [types.FAILURE]: (_storeState: {}, storeAction: IReducerAction): IData => ({ data: null, isPending: false, error: storeAction.error, fetched: true }), [types.SUCCESS]: (_storeState: {}, storeAction: IReducerAction): IData => ({ error: null, isPending: false, data: storeAction.payload && storeAction.payload.data, fetched: true }), [types.RESET]: initialState }; const reducer: Reducer<any> = createReducer(initialState, reducerObject); return { action, reducer, selectors, tileName: type, constants: types, reflect: params }; } export function createSyncTile(params: ISyncTileParams): ITile { const { type, nesting, fn = (fnParams: any): any => fnParams.params, fns, // we have default state as an object because of the possible nesting initialState = nesting ? {} : null, selectorFallback } = params; const identificator: string = createType({ type }); const types: ITypes = { SET: `${prefix}${identificator}_SET`, RESET: `${prefix}${identificator}_RESET` }; const selectorParams: ICreateSelectorsTypes = { selectorFallback, tileName: type, nesting }; const selectors: ISelectors = createSelectors(selectorParams); const actionParams: ISyncActionTypes = { SET: types.SET, nesting, fn, selector: selectors.get }; const action: IOverloadedAction = syncAction(actionParams); action.reset = createResetAction({ type: types.RESET }); if (fns) { Object.keys(fns).forEach((methodName: string) => { const method: any = fns[methodName]; const customActionParams: ISyncActionTypes = { ...actionParams, fn: method }; action[methodName] = syncAction(customActionParams); }); } const reducerObject: ReducerObject = { [types.SET]: (_storeState: {}, storeAction: IReducerAction): SyncData => storeAction.payload && storeAction.payload.data, [types.RESET]: initialState }; const reducer: Reducer<any> = createReducer(initialState, reducerObject); return { action, selectors, reducer, tileName: type, constants: types, reflect: params }; }