From cd27d81ccdc2b9256379a008d5ce02a006181187 Mon Sep 17 00:00:00 2001 From: Sergey Yarkov Date: Mon, 30 Aug 2021 14:18:11 +0300 Subject: [PATCH] feat: yup validator & some refactor in layout --- package-lock.json | 46 +++++++++ package.json | 4 +- src/components/Auth/AuthForm.tsx | 57 ----------- src/components/Forms/Auth/AuthForm.tsx | 93 ++++++++++++++++++ .../Forms/User/UpdateUserContactsForm.tsx | 41 ++++++++ src/components/User/UserAccountInfo.tsx | 66 +++++++++++++ src/hooks/useLoginQuery.ts | 1 + src/pages/auth.tsx | 16 +--- src/pages/profile.tsx | 95 +------------------ src/validators/LoginValidatorSchema.ts | 8 ++ 10 files changed, 265 insertions(+), 162 deletions(-) delete mode 100644 src/components/Auth/AuthForm.tsx create mode 100644 src/components/Forms/Auth/AuthForm.tsx create mode 100644 src/components/Forms/User/UpdateUserContactsForm.tsx create mode 100644 src/components/User/UserAccountInfo.tsx create mode 100644 src/validators/LoginValidatorSchema.ts diff --git a/package-lock.json b/package-lock.json index aebfe43..1b7e9c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2062,6 +2062,11 @@ "@hapi/hoek": "^8.3.0" } }, + "@hookform/resolvers": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.8.0.tgz", + "integrity": "sha512-ALlr0Bg6zDHdRsdqkwfWGPMnIxP4hqMRPvFDHp7lWXQeA7rKykto3cWqQQh1s0PzX043RHwMB6OHVPMwFJqwxg==" + }, "@humanwhocodes/config-array": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", @@ -9816,6 +9821,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", @@ -10283,6 +10293,11 @@ "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", "optional": true }, + "nanoclone": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz", + "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==" + }, "nanoid": { "version": "3.1.25", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", @@ -12176,6 +12191,11 @@ "react-is": "^16.8.1" } }, + "property-expr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz", + "integrity": "sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg==" + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -14808,6 +14828,11 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=" + }, "tough-cookie": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", @@ -16695,6 +16720,27 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + }, + "yup": { + "version": "0.32.9", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.9.tgz", + "integrity": "sha512-Ci1qN+i2H0XpY7syDQ0k5zKQ/DoxO0LzPg8PAR/X4Mpj6DqaeCoIYEEjDJwhArh3Fa7GWbQQVDZKeXYlSH4JMg==", + "requires": { + "@babel/runtime": "^7.10.5", + "@types/lodash": "^4.14.165", + "lodash": "^4.17.20", + "lodash-es": "^4.17.15", + "nanoclone": "^0.2.1", + "property-expr": "^2.0.4", + "toposort": "^2.0.2" + }, + "dependencies": { + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + } + } } } } diff --git a/package.json b/package.json index 5ac4519..a2fd2a8 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "@chakra-ui/react": "^1.0.0", "@emotion/react": "^11.0.0", "@emotion/styled": "^11.0.0", + "@hookform/resolvers": "^2.8.0", "@testing-library/jest-dom": "^5.9.0", "@testing-library/react": "^10.2.1", "@testing-library/user-event": "^12.0.2", @@ -27,7 +28,8 @@ "react-router-dom": "^5.2.0", "react-scripts": "4.0.3", "typescript": "^3.9.5", - "web-vitals": "^0.2.2" + "web-vitals": "^0.2.2", + "yup": "^0.32.9" }, "scripts": { "start": "react-scripts start", diff --git a/src/components/Auth/AuthForm.tsx b/src/components/Auth/AuthForm.tsx deleted file mode 100644 index d2299f4..0000000 --- a/src/components/Auth/AuthForm.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from 'react'; -import { MdAccountCircle, MdVpnKey } from 'react-icons/md'; -import { FormControl, FormLabel, InputGroup, Input, InputLeftElement, Button, Icon } from '@chakra-ui/react'; -import { SubmitHandler, useForm } from 'react-hook-form'; -import useLoginQuery from 'hooks/useLoginQuery'; - -type AuthInputs = { - login: string; - password: string; -}; - -const AuthForm: React.FC = () => { - const { register, reset, handleSubmit } = useForm(); - const { login, loading } = useLoginQuery(); - - const onSubmit: SubmitHandler = async data => { - try { - await login(data.login, data.password); - } catch (error) { - console.error(error); - } finally { - reset(); - } - }; - - return ( -
- - Login - - } /> - - - - - Password - - } /> - - - - -
- ); -}; - -export default AuthForm; diff --git a/src/components/Forms/Auth/AuthForm.tsx b/src/components/Forms/Auth/AuthForm.tsx new file mode 100644 index 0000000..e04712b --- /dev/null +++ b/src/components/Forms/Auth/AuthForm.tsx @@ -0,0 +1,93 @@ +import React from 'react'; +import { MdAccountCircle, MdSchool, MdVpnKey } from 'react-icons/md'; +import { + FormControl, + FormLabel, + InputGroup, + Input, + InputLeftElement, + Button, + Icon, + Text, + Flex, + Box, +} from '@chakra-ui/react'; +import { SubmitHandler, useForm } from 'react-hook-form'; +import { yupResolver } from '@hookform/resolvers/yup'; +import useLoginQuery from 'hooks/useLoginQuery'; +import LoginValidatorSchema from 'validators/LoginValidatorSchema'; + +type AuthInputType = { + login: string; + password: string; +}; + +const AuthForm: React.FC = () => { + const { + register, + reset, + formState: { errors }, + handleSubmit, + } = useForm({ + resolver: yupResolver(LoginValidatorSchema), + }); + const { login, loading } = useLoginQuery(); + + const onSubmit: SubmitHandler = data => { + login(data.login, data.password).finally(() => reset()); + }; + + return ( + +
+ + + + + + + + + Login + + } /> + + + + {errors.login?.message} + + + + Password + + } /> + + + + {errors.password?.message} + + + + + +
+
+ ); +}; + +export default AuthForm; diff --git a/src/components/Forms/User/UpdateUserContactsForm.tsx b/src/components/Forms/User/UpdateUserContactsForm.tsx new file mode 100644 index 0000000..9f43541 --- /dev/null +++ b/src/components/Forms/User/UpdateUserContactsForm.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { MdSave } from 'react-icons/md'; +import { Box, Heading, Stack } from '@chakra-ui/layout'; +import { FormControl, FormHelperText } from '@chakra-ui/form-control'; +import { Input } from '@chakra-ui/input'; +import { Button } from '@chakra-ui/button'; + +const UpdateUserContactsForm: React.FC = () => { + return ( + + + + My Contacts + + + + Telephone + + + + Twitter + + + + Telegram + + + + VKontakte + + + + + + + ); +}; + +export default UpdateUserContactsForm; diff --git a/src/components/User/UserAccountInfo.tsx b/src/components/User/UserAccountInfo.tsx new file mode 100644 index 0000000..71358aa --- /dev/null +++ b/src/components/User/UserAccountInfo.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { Box, Heading, Stack, Flex, StackDivider, Text, Button } from '@chakra-ui/react'; +import { IUser } from 'interfaces'; + +type UserAccountInfoPropsType = { + user: IUser; +}; + +const UserAccountInfo: React.FC = ({ user }) => { + return ( + + + Account information + + }> + + + + First Name + + + {user.first_name} + + + + + + + + Last Name + + + {user.last_name} + + + + + + + + Email + + + {user.email} + + + + + + + + + Password + + + ********** + + + + + + + ); +}; + +export default UserAccountInfo; diff --git a/src/hooks/useLoginQuery.ts b/src/hooks/useLoginQuery.ts index 2553460..7be4b5d 100644 --- a/src/hooks/useLoginQuery.ts +++ b/src/hooks/useLoginQuery.ts @@ -53,6 +53,7 @@ const useLoginQuery = () => { break; } } else { + console.error(error); handleError(error); } } finally { diff --git a/src/pages/auth.tsx b/src/pages/auth.tsx index 6ab8fc1..c5d0622 100644 --- a/src/pages/auth.tsx +++ b/src/pages/auth.tsx @@ -3,11 +3,10 @@ import Helmet from 'react-helmet'; import { Redirect } from 'react-router-dom'; import { observer } from 'mobx-react'; import { IPageProps } from 'interfaces'; -import { Flex, Box } from '@chakra-ui/react'; +import { Flex } from '@chakra-ui/react'; import { useRootStore } from 'hooks/useRootStore'; -import { MdSchool } from 'react-icons/md'; -import AuthForm from 'components/Auth/AuthForm'; +import AuthForm from 'components/Forms/Auth/AuthForm'; /** * Auth page @@ -25,16 +24,7 @@ const AuthPage: React.FC = () => { Auth - - - - - - - - - - + ); diff --git a/src/pages/profile.tsx b/src/pages/profile.tsx index d63a53f..89d109a 100644 --- a/src/pages/profile.tsx +++ b/src/pages/profile.tsx @@ -6,27 +6,21 @@ import { Avatar, useColorMode, Text, - Stack, - Button, - StackDivider, - FormControl, - Input, Tabs, TabList, Tab, TabPanels, TabPanel, - FormHelperText, } from '@chakra-ui/react'; -import { MdSave } from 'react-icons/md'; - import { IPageProps } from 'interfaces'; import { useRootStore } from 'hooks/useRootStore'; import { useHistory } from 'react-router-dom'; import { observer } from 'mobx-react'; import UserBadge from 'components/User/UserBadge'; import LoadingProfilePage from 'components/Loading/LoadingProfilePage'; +import UserAccountInfo from 'components/User/UserAccountInfo'; +import UpdateUserContactsForm from 'components/Forms/User/UpdateUserContactsForm'; /** * Profile page @@ -110,92 +104,11 @@ const ProfilePage: React.FC = ({ title }) => { My contacts - {/* Account info */} - - - Account information - - }> - - - - First Name - - - {userStore.me.first_name} - - - - - - - - Last Name - - - {userStore.me.last_name} - - - - - - - - Email - - - {userStore.me.email} - - - - - - - - - Password - - - ********** - - - - - - + - - {/* Contacts */} - - - - My Contacts - - - - Telephone - - - - Twitter - - - - Telegram - - - - VKontakte - - - - - - + diff --git a/src/validators/LoginValidatorSchema.ts b/src/validators/LoginValidatorSchema.ts new file mode 100644 index 0000000..fda13e3 --- /dev/null +++ b/src/validators/LoginValidatorSchema.ts @@ -0,0 +1,8 @@ +import * as yup from 'yup'; + +const LoginValidatorSchema = yup.object().shape({ + login: yup.string().required('Login is required'), + password: yup.string().min(6, 'Password must be at least 6 characters').required('Password is required'), +}); + +export default LoginValidatorSchema;