Skip to content

Instantly share code, notes, and snippets.

@busypeoples
Last active March 23, 2018 00:29
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save busypeoples/ec79da7da72bc6cd6bc240810f54a511 to your computer and use it in GitHub Desktop.
Save busypeoples/ec79da7da72bc6cd6bc240810f54a511 to your computer and use it in GitHub Desktop.
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
}
import {
filter,
is,
isEmpty
} from 'ramda'
/* eslint-disable no-mixed-operators, indent */
const isObject = a => (is(Object, a) && !is(Array, a) && !is(Function, a))
/**
* check if object keys contain any string, function, non empty array or object values.
*
* @param obj the object to validate
* @returns {boolean}
*/
export default function isValid(obj = {}) {
const a = filter(i => i &&
isObject(i)
? !isValid(i)
: (typeof i === 'string' ||
typeof i === 'function' ||
(is(Array, i) && !isEmpty(i)))
, obj // eslint-disable-line comma-dangle
)
return isEmpty(a) // eslint-disable-line comma-dangle
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment