<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import compose from 'recompact/compose';
import withState from 'recompact/withState';
import withProps from 'recompact/withProps';
import withHandlers from 'recompact/withHandlers';
import withContext from 'recompact/withContext';
import getContext from 'recompact/getContext';
import omitProps from 'recompact/omitProps';
import omit from 'recompact/utils/omit';

const isValidForm = (validationFields) => {
  return Object
    .keys(validationFields)
    .every((name) => validationFields[name].status);
};

export default (Target) => {
  const validators = {};

  const FormValidation = (props) => (
    <Target {...props}/>
  );

  return compose(
    withState('validationFields', 'setValidationFields', {}),
    getContext({
      neoform: PropTypes.object
    }),
    withContext(
      {
        neoform: PropTypes.object
      },
      ({ neoform, setValidationFields, validationFields }) => ({
        neoform: {
          ...neoform,
          getValidation: (name) => validationFields[name] || {},
          validate(name) {
            const validator = validators[name];
            const value = neoform.getValue(name);

            validator(value)
              .then((message) => {
                setValidationFields((prevState) => ({
                  ...prevState,
                  [name]: {
                    status: true,
                    message
                  }
                }));
              })
              .catch((message) => {
                setValidationFields((prevState) => ({
                  ...prevState,
                  [name]: {
                    status: false,
                    message
                  }
                }));
              });
          },
          registerValidator(name, validator) {
            validators[name] = validator;
          },
          unregisterValidator(name) {
            delete validators[name];

            setValidationFields((prevState) => {
              return omit(prevState, name);
            });
          }
        }
      })
    ),
    withHandlers({
      validate: ({ neoform, setValidationFields }) => (externalHandler) => {
        const validationFields = {};

        return Promise.all(
          Object.keys(validators)
            .map((name) => {
              const validator = validators[name];
              const value = neoform.getValue(name);

              return validator(value)
                .then((message) => {
                  validationFields[name] = {
                    status: true,
                    message
                  };
                })
                .catch((message) => {
                  validationFields[name] = {
                    status: false,
                    message
                  };
                });
            })
        )
        .then(() => {
          setValidationFields(validationFields);

          if (isValidForm(validationFields) && typeof externalHandler === 'function') {
            externalHandler();
          }
        });
      }
    }),
    withProps(
      ({ validationFields }) => ({
        validationStatus: isValidForm(validationFields)
      })
    ),
    omitProps([ 'neoform', 'setValidationFields', 'validationFields' ])
  )(FormValidation);
};
<commit_msg>:heavy_plus_sign: Provide an `errorHandler` callback to form validate method when form is invalid<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import compose from 'recompact/compose';
import withState from 'recompact/withState';
import withProps from 'recompact/withProps';
import withHandlers from 'recompact/withHandlers';
import withContext from 'recompact/withContext';
import getContext from 'recompact/getContext';
import omitProps from 'recompact/omitProps';
import omit from 'recompact/utils/omit';

const isValidForm = (validationFields) => {
  return Object
    .keys(validationFields)
    .every((name) => validationFields[name].status);
};

export default (Target) => {
  const validators = {};

  const FormValidation = (props) => (
    <Target {...props}/>
  );

  return compose(
    withState('validationFields', 'setValidationFields', {}),
    getContext({
      neoform: PropTypes.object
    }),
    withContext(
      {
        neoform: PropTypes.object
      },
      ({ neoform, setValidationFields, validationFields }) => ({
        neoform: {
          ...neoform,
          getValidation: (name) => validationFields[name] || {},
          validate(name) {
            const validator = validators[name];
            const value = neoform.getValue(name);

            validator(value)
              .then((message) => {
                setValidationFields((prevState) => ({
                  ...prevState,
                  [name]: {
                    status: true,
                    message
                  }
                }));
              })
              .catch((message) => {
                setValidationFields((prevState) => ({
                  ...prevState,
                  [name]: {
                    status: false,
                    message
                  }
                }));
              });
          },
          registerValidator(name, validator) {
            validators[name] = validator;
          },
          unregisterValidator(name) {
            delete validators[name];

            setValidationFields((prevState) => {
              return omit(prevState, name);
            });
          }
        }
      })
    ),
    withHandlers({
      validate: ({ neoform, setValidationFields }) => (successHandler, errorHandler) => {
        const validationFields = {};

        return Promise.all(
          Object.keys(validators)
            .map((name) => {
              const validator = validators[name];
              const value = neoform.getValue(name);

              return validator(value)
                .then((message) => {
                  validationFields[name] = {
                    status: true,
                    message
                  };
                })
                .catch((message) => {
                  validationFields[name] = {
                    status: false,
                    message
                  };
                });
            })
        )
        .then(() => {
          setValidationFields(validationFields);

          if (isValidForm(validationFields) && typeof successHandler === 'function') {
            successHandler();
          } else if (typeof errorHandler === 'function') {
            errorHandler();
          }
        });
      }
    }),
    withProps(
      ({ validationFields }) => ({
        validationStatus: isValidForm(validationFields)
      })
    ),
    omitProps([ 'neoform', 'setValidationFields', 'validationFields' ])
  )(FormValidation);
};

{'fraction_non_alphanumeric': 0.12005238649592549, 'fraction_numerical': 0.0, 'mean_word_length': 1.5789868667917448, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6706611', 'n_tokens_mistral': 1735, 'n_tokens_neox': 1633, 'n_words': 329}