Skip to content

Instantly share code, notes, and snippets.

@GeDiez
Created November 1, 2018 23:11
Show Gist options
  • Save GeDiez/40ba2d8e3e7dc60cb56e7bd329f4eac1 to your computer and use it in GitHub Desktop.
Save GeDiez/40ba2d8e3e7dc60cb56e7bd329f4eac1 to your computer and use it in GitHub Desktop.
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>
</>
);
};
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