Skip to content

Commit

Permalink
feat: add form validation
Browse files Browse the repository at this point in the history
  • Loading branch information
j-aroq committed Jan 31, 2024
1 parent 8c2e063 commit f39b72b
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 4 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,4 @@
"storybook": "^7.6.4",
"webpack": "^5.89.0"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
align-items: start;
}
&__question {
@include m.LinkS;
Expand All @@ -28,3 +28,9 @@
margin-bottom: 32px;
}
}

.error {
color: v.$error;
@include m.Description;
margin-top: 4px;
}
29 changes: 27 additions & 2 deletions src/components/Forms/AuthorizationForm/AuthorizationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,52 @@ import PasswordInput from 'ui-lib/Inputs/PasswordInput/PasswordInput';
import loginUserThunk from 'thunks/login-user-thunk';
import { NavLink } from 'react-router-dom';
import { UniversalButton } from 'ui-lib/Buttons';
import { validateField } from 'utils/validateFields';
import { useDispatch } from '../../../services/hooks';
import styles from './AuthorizationForm.module.scss';

const AuthorizationForm = () => {
type Values = Record<string, string>;
type FormErrors = Record<string, string>;
const dispatch = useDispatch();
const [values, setValues] = useState<Values>({});
const [errors, setErrors] = useState<FormErrors>({ email: '', password: '' });
const onSubmitLogin = (event: SyntheticEvent) => {
event.preventDefault();
dispatch(loginUserThunk({ email: values.email, password: values.password }));
const newErrors: FormErrors = {};
Object.entries(values).forEach(([name, value]) => {
const error = validateField(name, value);
if (error) {
newErrors[name] = error;
}
});

if (Object.keys(newErrors).length > 0) {
setErrors(newErrors);
} else {
dispatch(loginUserThunk({ email: values.email, password: values.password }));
}
};
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const { target } = event;
const { name, value } = target;
setValues({ ...values, [name]: value });
const error = validateField(name, value);
setErrors((prevErrors) => ({
...prevErrors,
[name]: error,
}));
setValues((prevValues) => ({
...prevValues,
[name]: value,
}));
};
return (
<form className={styles.AuthorizationForm} onSubmit={onSubmitLogin}>
<div className={styles.AuthorizationForm__container}>
<EmailInput id='email' name='email' onChange={handleChange} />
{errors.email && <div className={styles.error}>{errors.email}</div>}
<PasswordInput id='password' name='password' onChange={handleChange} />
{errors.password && <div className={styles.error}>{errors.password}</div>}
</div>
<NavLink to='pass' className={styles.AuthorizationForm__question}>
Забыли пароль?
Expand Down
64 changes: 64 additions & 0 deletions src/utils/useForm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useState, ChangeEvent, FormEvent } from 'react';

interface FormValues {
[key: string]: string;
}

interface FormErrors {
[key: string]: string | null;
}

interface UseFormProps {
initialValues: FormValues;
validationFunction: (name: string, value: string) => string | null;
onSubmit: (values: FormValues) => void;
}

export const useForm = ({
initialValues,
validationFunction,
onSubmit,
}: UseFormProps) => {
const [values, setValues] = useState<FormValues>(initialValues);
const [errors, setErrors] = useState<FormErrors>({});

const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.target;
const error = validationFunction(name, value);

setValues((prevValues) => ({
...prevValues,
[name]: value,
}));

setErrors((prevErrors) => ({
...prevErrors,
[name]: error,
}));
};

const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
const newErrors: FormErrors = {};

Object.entries(values).forEach(([name, value]) => {
const error = validationFunction(name, value);
if (error) {
newErrors[name] = error;
}
});

if (Object.keys(newErrors).length > 0) {
setErrors(newErrors);
} else {
onSubmit(values);
}
};

return {
values,
errors,
handleChange,
handleSubmit,
};
};
18 changes: 18 additions & 0 deletions src/utils/validateFields.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export const validateField = (name: string, value: string): string => {
switch (name) {
case 'email':
if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value)) {
return 'Email введен некорректно';
}
break;
case 'password':
if ((value.length !== 0 && value.length < 6) || value.length > 10) {
return 'Минимум 6 и максимум 10 символов';
}
break;
default:
return '';
}

return '';
};

0 comments on commit f39b72b

Please sign in to comment.