Files
socialhose-php/frontend/app/redux/modules/abstract/reduxModule.js
T
2022-12-09 08:36:26 -06:00

179 lines
4.2 KiB
JavaScript

import { createAction, handleActions } from 'redux-actions'
import { fromJS } from 'immutable'
import {thunkAction} from '../../utils/common'
export class ReduxModule {
constructor () {
this._namespace = this.getNamespace()
this._actions = {}
this._reducers = {}
}
init () {
this._initialState = fromJS(this.getInitialState())
const actions = this.defineActions()
const reducers = this._addNamespaceToReducers(this.defineReducers())
Object.assign(this._actions, actions)
Object.assign(this._reducers, reducers)
this.reducers = handleActions(this._reducers, this._initialState)
this.actions = this._actions
}
getNamespace () {
//implement in subclasses
}
getInitialState () {
//implement in subclasses
}
defineActions () {
//implement in subclasses
//it should return hash of function
/**
* return {
* action1,
* action2
* }
*/
}
defineReducers () {
//implement in subclasses
/*
return {
[actionName]: this.****Reducer()
}
or use this.addReducer()
*/
}
_addNamespaceToReducers (obj) {
const result = {}
for (let actionName in obj) {
result[this.ns(actionName)] = obj[actionName]
}
return result
}
/** utils **/
ns (actionName) {
return `${this._namespace} ${actionName}`
}
evalPath (path) {
return path
//TODO: something better
/*return path.map(
(item) => (typeof item === 'function') ? item(state) : item
);*/
}
/** action creators **/
createAction (actionName, actionFn) {
return createAction(this.ns(actionName), actionFn)
}
thunkAction (actionName, actionMethod, emitPending) {
return thunkAction(this.ns(actionName), actionMethod, emitPending)
}
thunkPendingReducer (field) {
return (state, {payload: {isPending}}) => state.set(field, isPending)
}
/** reducer creators **/
setReducer (field) {
return (state, {payload: value}) => state.set(field, value)
}
setInReducer (path) {
return (state, {payload: value}) => state.setIn(this.evalPath(path), value)
}
setFieldReducer () {
return (state, {payload: {field, value}}) => state.set(field, value)
}
resetReducer (field, defaultValue) {
return (state) => state.set(field, defaultValue)
}
mergeReducer () {
return (state, {payload: values}) => state.merge(values)
}
mergeInReducer (path) {
return (state, {payload: values}) => state.mergeIn(this.evalPath(path), values)
}
toggleReducer (field) {
return (state) => state.set(field, !state.get(field))
}
toggleInReducer (path) {
return (state) => {
const realPath = this.evalPath(path)
return state.setIn(realPath, !state.getIn(realPath))
}
}
addReducer (actionName, reducerFn) {
this._reducers[this.ns(actionName)] = reducerFn
}
//do not prefix with namespace
addExternalReducer (actionName, reducerFn) {
this._reducers[actionName] = reducerFn
}
/** handler creators
* handler = action + reducer
**/
createHandler (actionName, actionFn, reducerFn) {
const action = this.createAction(actionName, actionFn)
this.addReducer(actionName, reducerFn)
return action
}
set (actionName, field) {
return this.createHandler(actionName, {}, this.setReducer(field))
}
setIn (actionName, path) {
return this.createHandler(actionName, {}, this.setInReducer(path))
}
setField (actionName) {
return this.createHandler(actionName, (field, value) => ({field, value}), this.setFieldReducer())
}
reset (actionName, field, defaultValue) {
return this.createHandler(actionName, {}, this.resetReducer(field, defaultValue))
}
merge (actionName) {
return this.createHandler(actionName, {}, this.mergeReducer())
}
mergeIn (actionName, path) {
return this.createHandler(actionName, {}, this.mergeInReducer(path))
}
toggle (actionName, field) {
return this.createHandler(actionName, {}, this.toggleReducer(field))
}
toggleIn (actionName, path) {
return this.createHandler(actionName, {}, this.toggleInReducer(path))
}
resetToInitialState (actionName) {
return this.createHandler(actionName, {}, () => this._initialState)
}
}
export default ReduxModule