Home Reference Source

src/reducers/formPlugin.js

import _ from 'lodash';
import merge from 'deepmerge';
import {
  DISABLE_FIELD,
  ENABLE_FIELD,
  SHOW_FIELD,
  HIDE_FIELD,
  REGISTER_FIELD_EXTRA,
  ADD_FIELD_MESSAGE,
  REMOVE_FIELD_MESSAGE,
  REGISTER_DEPENDENCY,
  SET_FIELD_FILTER,
  SHOW_FIELDS,
  HIDE_FIELDS,
  ENABLE_FIELDS,
  DISABLE_FIELDS,
  SET_REQUIRED,
  UNSET_REQUIRED,
} from '../constants/formPlugin';
import { actionTypes } from 'redux-form';

const defaultState = {
  isInit: true,
  visible: true,
  disabled: false,
  message: null,
  filter: [],
  dependency: null,
  required: false,
};

const setValueByNames = (state, names, props) =>
  Object.assign(
    {},
    state,
    _.reduce(
      names,
      (result, name) => {
        return {
          ...result,
          [name]: { ...state[name], ...props },
        };
      },
      {}
    )
  );

function resolve(state = defaultState, action) {
  switch (action.type) {
    case REGISTER_FIELD_EXTRA:
      return Object.assign(
        {},
        state,
        merge(defaultState, action.payload.initialState || {})
      );
    case DISABLE_FIELD:
      return Object.assign({}, state, { disabled: true });
    case ENABLE_FIELD:
      return Object.assign({}, state, { disabled: false });
    case SHOW_FIELD:
      return Object.assign({}, state, { visible: true });
    case HIDE_FIELD:
      return Object.assign({}, state, { visible: false });
    case ADD_FIELD_MESSAGE:
      return Object.assign({}, state, {
        message: { ...action.payload.message },
      });
    case REMOVE_FIELD_MESSAGE:
      return Object.assign({}, state, { message: null });
    case REGISTER_DEPENDENCY:
      return Object.assign({}, state, {
        dependency: action.payload.dependency,
      });
    case SET_FIELD_FILTER:
      return Object.assign({}, state, {
        filter: state.filter
          .filter(f => f.filterId !== action.payload.filter.filterId)
          .concat(action.payload.filter),
      });
    case SHOW_FIELDS:
      return setValueByNames(state, action.payload.names, { visible: true });
    case DISABLE_FIELDS:
      return setValueByNames(state, action.payload.names, { disabled: true });
    case ENABLE_FIELDS:
      return setValueByNames(state, action.payload.names, { disabled: false });
    case HIDE_FIELDS:
      return setValueByNames(state, action.payload.names, { visible: false });
    case SET_REQUIRED:
      return Object.assign({}, state, { required: true });
    case UNSET_REQUIRED:
      return Object.assign({}, state, { required: false });
    default:
      return state;
  }
}

/**
 * Резолв изменения поля в redux form с учетом keepDirty
 * @param state
 * @param payload
 * @param meta
 * @returns {any}
 */
export function resolveChange(state, { payload, meta }) {
  const { field } = meta;
  let newState = Object.assign({}, state);

  if (_.has(payload, 'keepDirty')) {
    _.set(newState, `values[${field}]`, payload.value);
    if (!payload.keepDirty) {
      _.set(newState, `initial[${field}]`, payload.value);
    }
  } else {
    _.set(newState, `values[${field}]`, payload);
  }

  return newState;
}

/**
 * Редюсер удаления/добваления алертов
 * @ignore
 */
export default function formPlugin(state = {}, action) {
  switch (action.type) {
    case REGISTER_FIELD_EXTRA:
    case DISABLE_FIELD:
    case ENABLE_FIELD:
    case SHOW_FIELD:
    case HIDE_FIELD:
    case ADD_FIELD_MESSAGE:
    case REMOVE_FIELD_MESSAGE:
    case REGISTER_DEPENDENCY:
    case SET_FIELD_FILTER:
    case SET_REQUIRED:
    case UNSET_REQUIRED:
      return _.set(
        state,
        ['registeredFields', action.payload.name],
        resolve(_.get(state, ['registeredFields', action.payload.name]), action)
      );
    case SHOW_FIELDS:
    case DISABLE_FIELDS:
    case ENABLE_FIELDS:
    case HIDE_FIELDS:
      return _.set(
        state,
        'registeredFields',
        resolve(_.get(state, 'registeredFields'), action)
      );
    case actionTypes.CHANGE:
      return resolveChange(state, action);
    default:
      return state;
  }
}