react-form-validator-hook
Version:
Simple Library for React to validate forms quickly
172 lines (160 loc) • 7.27 kB
JSX
import React, {useState} from "react";
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/i;
const useValidator = (state, config) => {
const [values, setValues] = useState(state);
const [errors, setErrors] = useState({});
const [passwordErrors, setPasswordErrors] = useState({
minLength: !config.password,
number: !config.password.rules.number || false,
upperCase: !config.password.rules.upperCase || false,
lowerCase: !config.password.rules.lowerCase || false,
specialChar: !config.password.rules.specialChar || false
});
const handleValueChange = (name, value) => {
setValues({...values, [name]: value});
validate(name, value);
}
const handleBlur = (name) => {
validate(name, values[name]);
}
const validateOnSubmit = (event) => {
event.preventDefault();
const errors = Object.keys(config).reduce((acc, name) => {
const value = values[name];
const error = validate(name, value);
return {...acc, [name]: error};
}, {});
setErrors(errors);
}
const validate = (name, value) => {
const rules = config[name].rules;
const errorsArray = [];
if (rules.required && !value) {
errorsArray.push(rules.required.message);
}
if (rules.pattern && !rules.pattern.value.test(value)) {
errorsArray.push(rules.pattern.message);
}
if (rules.minLength && value.length < rules.minLength) {
errorsArray.push(rules.minLength.message);
}
if (rules.maxLength && value.length > rules.maxLength) {
errorsArray.push(rules.maxLength.message);
}
if (rules.min && value < rules.min) {
errorsArray.push(rules.min.message);
}
if (rules.max && value > rules.max) {
errorsArray.push(rules.max.message);
}
if (rules.email && !emailRegex.test(value)) {
errorsArray.push(rules.email.message);
}
if (rules.confirm && value !== values[rules.confirm.field]) {
errorsArray.push(rules.confirm.message);
}
if (rules.password) {
const newPasswordErrors = {
minLength: value.length >= rules.minLengthPassword,
number: rules.number ? /[0-9]/.test(value) : true,
upperCase: rules.upperCase ? /[A-Z]/.test(value) : true,
lowerCase: rules.lowerCase ? /[a-z]/.test(value) : true,
specialChar: rules.specialChar ? /[^A-Za-z0-9]/.test(value) : true
};
setPasswordErrors(newPasswordErrors);
if (!Object.values(newPasswordErrors).every((value) => value)) {
errorsArray.push(rules.error.message);
}
}
setErrors({...errors, [name]: errorsArray});
return errorsArray;
}
const PasswordValidationComponent = ({validIcon = 'ok'}) => {
return (
<div className={"password-validation"}>
<div className={"password-validation-wrapper"}>
<div className={"password-validation__item"}>
<div className={"password-validation__item__icon"}>
{passwordErrors.minLength && validIcon}
</div>
<div className={`password-validation__item__text ${passwordErrors.minLength && ' valid'}`}>
{config.password.rules.minLengthPassword.message}
</div>
</div>
{
config.password.rules.number && (
<div className={"password-validation__item"}>
<div className={"password-validation__item__icon"}>
{passwordErrors.number && validIcon}
</div>
<div className={`password-validation__item__text ${passwordErrors.number && ' valid'}`}>
{config.password.rules.number.message}
</div>
</div>
)
}
{
config.password.rules.upperCase && (
<div className={"password-validation__item"}>
<div className={"password-validation__item__icon"}>
{passwordErrors.upperCase && validIcon}
</div>
<div className={`password-validation__item__text ${passwordErrors.upperCase && ' valid'}`}>
{config.password.rules.upperCase.message}
</div>
</div>
)
}
{
config.password.rules.lowerCase && (
<div className={"password-validation__item"}>
<div className={"password-validation__item__icon"}>
{passwordErrors.lowerCase && validIcon}
</div>
<div className={`password-validation__item__text ${passwordErrors.lowerCase && ' valid'}`}>
{config.password.rules.lowerCase.message}
</div>
</div>
)
}
{
config.password.rules.specialChar && (
<div className={"password-validation__item"}>
<div className={"password-validation__item__icon"}>
{passwordErrors.specialChar && validIcon}
</div>
<div
className={`password-validation__item__text ${passwordErrors.specialChar && ' valid'}`}>
{config.password.rules.specialChar.message}
</div>
</div>
)
}
</div>
</div>
)
}
const ErrorComponent = ({name}) => {
return (
errors[name] && errors[name].length > 0 && (
<div className={"form-error"}>
{errors[name].map((error, index) => (
<div key={index} className={"form-error__item"}>
{error}
</div>
))}
</div>
)
)
}
return {
values,
errors,
handleValueChange,
handleBlur,
validateOnSubmit,
PasswordValidationComponent,
ErrorComponent
}
}
export default useValidator;