Created
November 1, 2018 23:11
-
-
Save GeDiez/40ba2d8e3e7dc60cb56e7bd329f4eac1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState } from 'react'; | |
import { Field, Input, Label, Control, Select, TextArea, Checkbox, Radio, Button, Help, Notification, Delete } from "bloomer"; | |
import joinString from "classnames"; | |
import { useForm } from "../Hooks"; | |
export const FormExample = ({isHidden}) => { | |
const FIELD_REQUIRED = 'This field is required'; | |
const SELECT_FIELD = 'Please select this field'; | |
const NOTIFICATION_MESSAGE_SUCCESS = 'Success message here!'; | |
const NOTIFICATION_MESSAGE_FAILED = 'Validations form has failed, please check the fields again!'; | |
const validate = ({ values }) => ({ | |
name: values.name === '' ? FIELD_REQUIRED : '', | |
email: values.email === '' ? FIELD_REQUIRED : '', | |
username: values.username === '' ? FIELD_REQUIRED : '', | |
select: values.select === '' ? FIELD_REQUIRED : '', | |
checkbox: !values.checkbox ? SELECT_FIELD : '', | |
}); | |
const { values, errors, touched, setValue, touchValue, isValid, reset, setAllValues, submitProps, inputFieldProps } = useForm({ | |
initialValues: { | |
name: '', | |
email: 'juan@amezQA', | |
checkbox: false, | |
select: '', | |
radioButton: 'yes' | |
} | |
}, { validate }); | |
const [showNotification, toggleNotification] = useState(false); | |
const onSuccess = () => { | |
toggleNotification(true); | |
} | |
const onError = () => { | |
toggleNotification(true); | |
} | |
const handleInput = ({target: { name, value }}) => { | |
setValue(name, value); | |
toggleNotification(false); | |
} | |
const setColorToInput = name => | |
joinString({ | |
success: errors[name] === '', | |
danger: errors[name] && touched[name], | |
}); | |
const getErrorMessageToInput = name => | |
joinString({ [errors[name]]: errors[name] && touched[name] }); | |
return ( | |
<> | |
<Notification isHidden={!showNotification} isColor={joinString({ success: isValid, danger: !isValid })}> | |
<Delete onClick={() => toggleNotification(false)} /> | |
{isValid ? NOTIFICATION_MESSAGE_SUCCESS : NOTIFICATION_MESSAGE_FAILED} | |
</Notification> | |
<TextArea rows={10} className={joinString({'is-hidden': isHidden})} value={JSON.stringify({ values, touched, errors }, null, 2)}> | |
</TextArea> | |
<form action="" {...submitProps({onSuccess, onError})} className={joinString({'is-hidden': isHidden})}> | |
<Field> | |
<Label>Name</Label> | |
<Control> | |
<Input | |
isColor={setColorToInput('name')} | |
type="text" | |
placeholder='Your name' | |
value={values.name} | |
name='name' | |
onInput={handleInput} | |
onBlur={() => touchValue('name')} | |
/> | |
</Control> | |
<Help isColor='danger'>{getErrorMessageToInput('name')}</Help> | |
</Field> | |
<Field> | |
<Label>Username</Label> | |
<Control> | |
<Input | |
isColor={setColorToInput('username')} | |
type="text" | |
placeholder='Your username' | |
{...inputFieldProps('username')} | |
/> | |
</Control> | |
<Help isColor='danger'>{getErrorMessageToInput('username')}</Help> | |
</Field> | |
<Field> | |
<Label>Email</Label> | |
<Control> | |
<Input | |
isColor={setColorToInput('email')} | |
placeholder='You email' | |
value={values.email} | |
name='email' | |
onInput={handleInput} | |
onBlur={() => touchValue('email')} | |
/> | |
</Control> | |
<Help isColor='danger'>{getErrorMessageToInput('email')}</Help> | |
</Field> | |
<Field> | |
<Label>Select:</Label> | |
<Control> | |
<Select | |
isColor={setColorToInput('select')} | |
{...inputFieldProps('select')} | |
> | |
<option value=''>Gender</option> | |
<option value='M'>Male</option> | |
<option value='F'>Female</option> | |
</Select> | |
</Control> | |
<Help isColor='danger'>{getErrorMessageToInput('select')}</Help> | |
</Field> | |
<Field> | |
<Label>Message</Label> | |
<Control> | |
<TextArea | |
{...inputFieldProps('textArea')} | |
placeholder={'<TextArea />'} | |
/> | |
</Control> | |
<Help isColor='danger'>{getErrorMessageToInput('textArea')}</Help> | |
</Field> | |
<Field> | |
<Control> | |
<Checkbox | |
onChange={({ target: { name, checked } }) => setValue(name, checked)} | |
checked={values.checkbox} | |
name='checkbox' | |
onBlur={() => touchValue('checkbox')} | |
> | |
I agree | |
</Checkbox> | |
</Control> | |
<Help isColor='danger'>{getErrorMessageToInput('checkbox')}</Help> | |
</Field> | |
<Field> | |
<Control> | |
<Radio | |
name="radioButton" | |
value="yes" | |
checked={values.radioButton === 'yes'} | |
onChange={handleInput} | |
onBlur={() => touchValue('radioButton')} | |
> | |
Yes | |
</Radio> | |
<Radio | |
name="radioButton" | |
value="no" | |
checked={values.radioButton === 'no'} | |
onChange={handleInput} | |
onBlur={() => touchValue('radioButton')} | |
> | |
No | |
</Radio> | |
</Control> | |
</Field> | |
<Field isGrouped> | |
<Control> | |
<Button isColor='primary' type="submit">Submit</Button> | |
</Control> | |
<Control> | |
<Button isColor='info' onClick={reset}>Reset</Button> | |
</Control> | |
<Control> | |
<Button | |
isColor='link' | |
onClick={() => setAllValues({name: 'default name', email: 'default email', checkbox: true, radioButton: 'no', select: 'M', textArea: 'text area example'})} | |
> | |
set new values | |
</Button> | |
</Control> | |
</Field> | |
</form> | |
</> | |
); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState } from "react"; | |
import { Object } from "core-js"; | |
export const useForm = ({ initialValues }, { validate = () => true }) => { | |
const [values, setValues] = useState(initialValues || {}); | |
const [errors, setErrors] = useState({}); | |
const [touched, setTouched] = useState({}); | |
const [isValid, setValid] = useState(false); | |
const setError = (name) => { | |
if (typeof(validate) !== 'function') { | |
throw Error('validate option should be a function'); | |
} | |
const error = validate({ values })[name]; | |
setErrors({ ...errors, [name]: error }); | |
} | |
const setValue = (name, value) => { | |
setValues({ | |
...values, | |
[name]: value, | |
}); | |
} | |
const touchValue = (name) => { | |
setError(name); | |
setTouched({ ...touched, [name]: true }); | |
} | |
const reset = () => { | |
setTouched({}); | |
setErrors({}); | |
setValues(initialValues); | |
setValid(false); | |
} | |
const setAllValues = (values) => { | |
setValuesAsTouched(); | |
setValues(values); | |
validateValues(values); | |
} | |
const validateValues = (values) => { | |
const fullErrors = validate({ values }); | |
const isValid = Object.keys(fullErrors).every(name => fullErrors[name] === ''); | |
setErrors(fullErrors); | |
setValuesAsTouched(); | |
setValid(isValid); | |
return isValid; | |
} | |
//DOM props | |
const submitProps = ({onSuccess, onError}) => ({ | |
onSubmit: (ev) => { | |
const isValid = validateValues(values); | |
if (!isValid) { | |
ev.preventDefault(); | |
onError(); | |
} else { | |
onSuccess(); | |
} | |
} | |
}); | |
const inputFieldProps = (name) => ({ | |
name, | |
value: values[name], | |
onInput: ({target: { value }}) => | |
setValue(name, value), | |
onBlur: () => touchValue(name), | |
}); | |
//Privated Functions | |
const setValuesAsTouched = () => { | |
setTouched(Object.keys(values).reduce((acc, name) => ({...acc, [name]: true}), {})); | |
} | |
return { | |
// Variables | |
values, | |
touched, | |
errors, | |
reset, | |
isValid, | |
// Actions | |
setAllValues, | |
setValue, | |
touchValue, | |
validateValues, | |
// DOM props | |
submitProps, | |
inputFieldProps, | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment