diff --git a/backend/src/users/dto/update-user.dto.ts b/backend/src/users/dto/update-user.dto.ts index 7fe8130f..7cf4f942 100644 --- a/backend/src/users/dto/update-user.dto.ts +++ b/backend/src/users/dto/update-user.dto.ts @@ -26,7 +26,7 @@ export class UpdateUserDto { @IsString() @Matches(/^[\w\S]*$/) @Validate(CheckUsername, { - message: 'Уже существует!', + message: 'usernameIsUsed', }) username?: string; @@ -39,7 +39,7 @@ export class UpdateUserDto { @IsString() @IsEmail() @Validate(CheckEmail, { - message: 'Уже существует!', + message: 'emailIsUsed', }) email?: string; diff --git a/frontend/package.json b/frontend/package.json index 66acb27d..17139a5a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -4,6 +4,7 @@ "private": true, "proxy": "http://localhost:5001", "dependencies": { + "@faker-js/faker": "^8.4.0", "@monaco-editor/react": "^4.5.1", "@reduxjs/toolkit": "^1.9.5", "@sentry/react": "^7.47.0", diff --git a/frontend/src/components/Forms/GuestSignUpForm.jsx b/frontend/src/components/Forms/GuestSignUpForm.jsx new file mode 100644 index 00000000..c5e564f0 --- /dev/null +++ b/frontend/src/components/Forms/GuestSignUpForm.jsx @@ -0,0 +1,211 @@ +import axios from 'axios'; +import { useFormik } from 'formik'; +import { useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { object } from 'yup'; + +import Button from 'react-bootstrap/Button'; +import Form from 'react-bootstrap/Form'; + +import { useDispatch, useSelector } from 'react-redux'; +import { useNavigate } from 'react-router-dom'; +import routes from '../../routes'; +import { email, password, username } from '../../utils/validationSchemas'; + +import GithubSignInButton from './GithubSignInButton.jsx'; +import PasswordVisibilityButton from './PasswordVisibilityButton.jsx'; +import FormAlert from './FormAlert.jsx'; +import { actions as userActions } from '../../slices/userSlice'; +import { actions as modalActions } from '../../slices/modalSlice.js'; + +function GuestSignupForm() { + const { t } = useTranslation(); + const emailRef = useRef(); + const usernameRef = useRef(); + const dispatch = useDispatch(); + const navigate = useNavigate(); + + const userInfo = useSelector((state) => state.user.userInfo); + + const initialFormState = { state: 'initial', message: '' }; + const [formState, setFormState] = useState(initialFormState); + + const [isPasswordVisible, setPasswordVisibility] = useState(false); + const handlePasswordVisibility = () => { + setPasswordVisibility(!isPasswordVisible); + }; + + useEffect(() => { + usernameRef.current.focus(); + }, []); + + const validationSchema = object().shape({ + username: username(), + email: email(), + password: password(), + }); + + const formik = useFormik({ + initialValues: { + username: '', + email: '', + password: '', + }, + validationSchema, + validateOnBlur: false, + onSubmit: async (values, actions) => { + setFormState(initialFormState); + const preparedValues = validationSchema.cast(values); + console.log(preparedValues); + try { + actions.setSubmitting(true); + + const response = await axios.put(routes.updateUserPath(userInfo.id), { + id: userInfo.id, + username: preparedValues.username, + email: preparedValues.email, + currPassword: JSON.parse(localStorage.getItem('guestUserData')) + .guestId, + password: values.password, + }); + dispatch(userActions.setUserInfo(response.data)); + localStorage.removeItem('guestUserData'); + dispatch(modalActions.closeModal()); + navigate(routes.profilePagePath(preparedValues.username)); + actions.setSubmitting(false); + } catch (err) { + if (!err.isAxiosError) { + formik.resetForm(); + setFormState({ + state: 'failed', + message: 'errors.unknown', + }); + throw err; + } + if ( + err.response?.status === 400 && + Array.isArray(err.response?.data?.errs?.message) + ) { + err.response.data.errs.message.forEach((e) => { + switch (e) { + case 'usernameIsUsed': + actions.setFieldError( + 'username', + 'errors.validation.usernameIsUsed', + ); + usernameRef.current.select(); + break; + case 'emailIsUsed': + actions.setFieldError('email', 'errors.validation.emailIsUsed'); + emailRef.current.select(); + break; + default: + setFormState({ + state: 'failed', + message: 'errors.network', + }); + throw err; + } + }); + } else { + formik.resetForm(); + setFormState({ + state: 'failed', + message: 'errors.network', + }); + throw err; + } + } + }, + }); + + return ( +