import React from 'react' import hoistNonReactStatics from 'hoist-non-react-statics' import { assoc, assocPath, identity, is, map, prop } from 'ramda' import isValid from './isValid' // random helper function // extract the needed information from the event const getValueName = (e) => { const target = e.target const name = target.name const value = target.type === 'checkbox' ? target.checked : target.value return {name, value} } const revalidation = ({ validateFn, mapPropsToState = identity, mapSetStateToProps = (updateState, actions) => ({ onChange: e => { const { name, value } = getValueName(e) return updateState(actions.update(name, value)) }, validate: e => { const { name, value } = getValueName(e) return updateState(actions.validate(name, value)) }, onSubmit: (onsSubmitFn) => { return updateState(actions.validateAll(onsSubmitFn)) } }), actions = { update: (name, value, state) => { return [ assocPath(['values', name], value, state) ] }, validate: (name, value, state, validate) => { return [ assoc('errors', validate.input(name, value), state) ] }, validateAll: (cbFn, state, validate) => { return [ assoc('errors', validate.all(state.values), state), (state) => { if (isValid(state.errors)) { cbFn(state.values) } } ] } } }) => Component => { class HigherOrderFormComponent extends React.Component { constructor(props) { super(props) this.state = { errors: {}, values: mapPropsToState(prop('values', props)) } this.actions = map(f => (...args) => f(...args, this.state, validateFn), actions) this.updateState = this.updateState.bind(this) } updateState(setState) { const [setStateFn, effects = () => {}] = setState this.setState(setStateFn, () => effects(this.state)) } render() { const { values, errors } = this.state const dispatched = mapSetStateToProps(this.updateState, this.actions) return React.createElement(Component, { ...this.props, ...dispatched, form: values, errors }) } } HigherOrderFormComponent.displayName = `Revalidation_(${Component.displayName || Component.name || 'Component'})` return hoistNonReactStatics(HigherOrderFormComponent, Component) } export default revalidation export { isValid }