Home Reference Source

src/components/widgets/Form/FormContainer.jsx

import {
  compose,
  withHandlers,
  withProps,
  onlyUpdateForKeys,
  withState,
  lifecycle,
  withPropsOnChange,
} from 'recompose';
import { isEmpty, isEqual } from 'lodash';
import merge from 'deepmerge';
import { getFormValues } from 'redux-form';
import { createStructuredSelector } from 'reselect';
import { connect } from 'react-redux';

import ReduxForm from './ReduxForm';
import widgetContainer from '../WidgetContainer';
import { FORM } from '../widgetTypes';

const arrayMergeFunction = (destinationArray, sourceArray) => sourceArray;

export const withWidgetContainer = widgetContainer(
  {
    mapProps: props => {
      return {
        widgetId: props.widgetId,
        isEnabled: props.isEnabled,
        pageId: props.pageId,
        autoFocus: props.autoFocus,
        fieldsets: props.fieldsets,
        datasource: props.datasource && props.datasource[0],
        onSetModel: props.onSetModel,
        onResolve: props.onResolve,
        resolveModel: props.resolveModel,
        activeModel: props.activeModel,
        validation: props.validation,
        modelPrefix: props.modelPrefix,
        prompt: props.prompt,
        setActive: props.onFocus,
        placeholder: props.placeholder,
      };
    },
  },
  FORM
);

export const mapStateToProps = createStructuredSelector({
  reduxFormValues: (state, props) => getFormValues(props.form)(state) || {},
});

export const withLiveCycleMethods = lifecycle({
  componentDidUpdate(prevProps) {
    const {
      datasource,
      activeModel,
      defaultValues,
      reduxFormValues,
      setDefaultValues,
    } = this.props;
    if (
      !isEqual(prevProps.activeModel, activeModel) &&
      !isEqual(activeModel, defaultValues) &&
      !isEqual(activeModel, reduxFormValues)
    ) {
      setDefaultValues(activeModel);
    } else if (
      !isEmpty(defaultValues) &&
      !isEqual(prevProps.datasource, datasource)
    ) {
      setDefaultValues(null);
    }
  },
});

export const withPropsOnChangeWidget = withPropsOnChange(
  (props, nextProps) => {
    return (
      !isEqual(props.defaultValues, nextProps.defaultValues) ||
      !isEqual(props.datasource, nextProps.datasource)
    );
  },
  props => {
    return {
      initialValues: props.defaultValues
        ? props.defaultValues
        : merge(props.resolveModel || {}, props.datasource || {}, {
            arrayMerge: arrayMergeFunction,
          }),
    };
  }
);

export const withWidgetHandlers = withHandlers({
  onChange: props => (values, dispatch, options, prevValues) => {
    props.setActive && props.setActive();
    if (
      props.modelPrefix &&
      isEqual(props.initialValues, props.reduxFormValues) &&
      !isEqual(props.initialValues, props.resolveModel)
    ) {
      props.onResolve(props.initialValues);
    }

    if (isEmpty(values) || !props.modelPrefix) {
      props.onResolve(values);
    } else if (!isEqual(props.reduxFormValues, prevValues)) {
      props.onSetModel(values);
    }
  },
});

/**
 * Обертка в widgetContainer, мэппинг пропсов
 */

export default compose(
  withWidgetContainer,
  withProps(props => {
    return {
      form: props.widgetId,
      prompt: props.prompt,
    };
  }),
  connect(mapStateToProps),
  withState('defaultValues', 'setDefaultValues', null),
  withLiveCycleMethods,
  withPropsOnChangeWidget,
  withWidgetHandlers,
  onlyUpdateForKeys(['initialValues'])
)(ReduxForm);