mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 18:29:15 +03:00
feat: yup validator & some refactor in layout
This commit is contained in:
parent
846d96473f
commit
cd27d81ccd
46
package-lock.json
generated
46
package-lock.json
generated
@ -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=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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<AuthInputs>();
|
||||
const { login, loading } = useLoginQuery();
|
||||
|
||||
const onSubmit: SubmitHandler<AuthInputs> = async data => {
|
||||
try {
|
||||
await login(data.login, data.password);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<FormControl isRequired={true}>
|
||||
<FormLabel>Login</FormLabel>
|
||||
<InputGroup>
|
||||
<InputLeftElement children={<Icon as={MdAccountCircle} />} />
|
||||
<Input type='text' placeholder='Type your login' {...register('login', { required: true })} />
|
||||
</InputGroup>
|
||||
</FormControl>
|
||||
<FormControl mt={5} isRequired={true}>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<InputGroup>
|
||||
<InputLeftElement children={<Icon as={MdVpnKey} />} />
|
||||
<Input type='password' placeholder='********' {...register('password', { required: true })} />
|
||||
</InputGroup>
|
||||
</FormControl>
|
||||
<Button
|
||||
loadingText='Logging in...'
|
||||
isLoading={loading}
|
||||
type='submit'
|
||||
colorScheme='blue'
|
||||
variant='outline'
|
||||
width='full'
|
||||
mt={4}
|
||||
>
|
||||
Log in
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuthForm;
|
||||
93
src/components/Forms/Auth/AuthForm.tsx
Normal file
93
src/components/Forms/Auth/AuthForm.tsx
Normal file
@ -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<AuthInputType>({
|
||||
resolver: yupResolver(LoginValidatorSchema),
|
||||
});
|
||||
const { login, loading } = useLoginQuery();
|
||||
|
||||
const onSubmit: SubmitHandler<AuthInputType> = data => {
|
||||
login(data.login, data.password).finally(() => reset());
|
||||
};
|
||||
|
||||
return (
|
||||
<Box w='full' maxW='450px' borderWidth='1px' borderRadius='lg' p='8'>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<Flex justifyContent='center' alignItems='center'>
|
||||
<Box w='full'>
|
||||
<Box textAlign='center'>
|
||||
<Flex justifyContent='center'>
|
||||
<Box as={MdSchool} color='blue.500' size='64px' />
|
||||
</Flex>
|
||||
</Box>
|
||||
<FormControl>
|
||||
<FormLabel>Login</FormLabel>
|
||||
<InputGroup>
|
||||
<InputLeftElement children={<Icon as={MdAccountCircle} />} />
|
||||
<Input type='text' placeholder='Login' {...register('login')} isInvalid={errors.login ? true : false} />
|
||||
</InputGroup>
|
||||
<Text as='small' color='red.500'>
|
||||
{errors.login?.message}
|
||||
</Text>
|
||||
</FormControl>
|
||||
<FormControl mt={5}>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<InputGroup>
|
||||
<InputLeftElement children={<Icon as={MdVpnKey} />} />
|
||||
<Input
|
||||
type='password'
|
||||
placeholder='******'
|
||||
{...register('password')}
|
||||
isInvalid={errors.password ? true : false}
|
||||
/>
|
||||
</InputGroup>
|
||||
<Text as='small' color='red.500'>
|
||||
{errors.password?.message}
|
||||
</Text>
|
||||
</FormControl>
|
||||
<Button
|
||||
loadingText='Logging in...'
|
||||
isLoading={loading}
|
||||
type='submit'
|
||||
colorScheme='blue'
|
||||
variant='outline'
|
||||
width='full'
|
||||
mt={4}
|
||||
>
|
||||
Log in
|
||||
</Button>
|
||||
</Box>
|
||||
</Flex>
|
||||
</form>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuthForm;
|
||||
41
src/components/Forms/User/UpdateUserContactsForm.tsx
Normal file
41
src/components/Forms/User/UpdateUserContactsForm.tsx
Normal file
@ -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 (
|
||||
<Box as='form'>
|
||||
<Box borderRadius='md' borderWidth='1px' padding='20px'>
|
||||
<Heading as='h3' size='lg'>
|
||||
My Contacts
|
||||
</Heading>
|
||||
<Stack spacing='5px' margin='20px 0'>
|
||||
<FormControl id='tel'>
|
||||
<FormHelperText color='gray.500'>Telephone</FormHelperText>
|
||||
<Input type='number' size='md' variant='flushed' placeholder='123-456-7890' />
|
||||
</FormControl>
|
||||
<FormControl id='twitter'>
|
||||
<FormHelperText color='gray.500'>Twitter</FormHelperText>
|
||||
<Input type='text' size='md' variant='flushed' placeholder='https://twitter.com/id' />
|
||||
</FormControl>
|
||||
<FormControl id='telegram'>
|
||||
<FormHelperText color='gray.500'>Telegram</FormHelperText>
|
||||
<Input type='text' size='md' variant='flushed' placeholder='@tag' />
|
||||
</FormControl>
|
||||
<FormControl id='vk'>
|
||||
<FormHelperText color='gray.500'>VKontakte</FormHelperText>
|
||||
<Input type='text' size='md' variant='flushed' placeholder='https://vk.com/id' />
|
||||
</FormControl>
|
||||
</Stack>
|
||||
</Box>
|
||||
<Button colorScheme='blue' mt='4' type='submit' size='md' variant='outline' rightIcon={<MdSave />}>
|
||||
Save
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateUserContactsForm;
|
||||
66
src/components/User/UserAccountInfo.tsx
Normal file
66
src/components/User/UserAccountInfo.tsx
Normal file
@ -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<UserAccountInfoPropsType> = ({ user }) => {
|
||||
return (
|
||||
<Box borderRadius='md' borderWidth='1px' padding='20px'>
|
||||
<Heading as='h3' size='lg'>
|
||||
Account information
|
||||
</Heading>
|
||||
<Stack spacing='10px' mt='20px' divider={<StackDivider />}>
|
||||
<Flex>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
First Name
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
{user.first_name}
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<Flex>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
Last Name
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
{user.last_name}
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<Flex justifyContent='space-between' alignItems='center'>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
Email
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
{user.email}
|
||||
</Text>
|
||||
</Box>
|
||||
<Button>Edit</Button>
|
||||
</Flex>
|
||||
|
||||
<Flex justifyContent='space-between' alignItems='center'>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
Password
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
**********
|
||||
</Text>
|
||||
</Box>
|
||||
<Button>Change</Button>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserAccountInfo;
|
||||
@ -53,6 +53,7 @@ const useLoginQuery = () => {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
console.error(error);
|
||||
handleError(error);
|
||||
}
|
||||
} finally {
|
||||
|
||||
@ -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<IPageProps> = () => {
|
||||
<title>Auth</title>
|
||||
</Helmet>
|
||||
<Flex minHeight='100vh' align='center' justifyContent='center' padding='5'>
|
||||
<Box p={8} width='full' maxWidth='450px' borderWidth={1} borderRadius={8}>
|
||||
<Box textAlign='center'>
|
||||
<Flex justifyContent='center'>
|
||||
<Box as={MdSchool} color='blue.500' size='64px' />
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<AuthForm />
|
||||
</Box>
|
||||
</Box>
|
||||
<AuthForm />
|
||||
</Flex>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -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<IPageProps> = ({ title }) => {
|
||||
<Tab>My contacts</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
{/* Account info */}
|
||||
<TabPanel padding='10px 0' mt='20px'>
|
||||
<Box borderRadius='md' borderWidth='1px' padding='20px'>
|
||||
<Heading as='h3' size='lg'>
|
||||
Account information
|
||||
</Heading>
|
||||
<Stack spacing='10px' mt='20px' divider={<StackDivider />}>
|
||||
<Flex>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
First Name
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
{userStore.me.first_name}
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<Flex>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
Last Name
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
{userStore.me.last_name}
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<Flex justifyContent='space-between' alignItems='center'>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
Email
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
{userStore.me.email}
|
||||
</Text>
|
||||
</Box>
|
||||
<Button>Edit</Button>
|
||||
</Flex>
|
||||
|
||||
<Flex justifyContent='space-between' alignItems='center'>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
Password
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
**********
|
||||
</Text>
|
||||
</Box>
|
||||
<Button>Change</Button>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Box>
|
||||
<UserAccountInfo user={userStore.me} />
|
||||
</TabPanel>
|
||||
|
||||
{/* Contacts */}
|
||||
<TabPanel padding='10px 0' mt='20px'>
|
||||
<Box as='form'>
|
||||
<Box borderRadius='md' borderWidth='1px' padding='20px'>
|
||||
<Heading as='h3' size='lg'>
|
||||
My Contacts
|
||||
</Heading>
|
||||
<Stack spacing='5px' margin='20px 0'>
|
||||
<FormControl id='tel'>
|
||||
<FormHelperText color='gray.500'>Telephone</FormHelperText>
|
||||
<Input type='number' size='md' variant='flushed' placeholder='123-456-7890' />
|
||||
</FormControl>
|
||||
<FormControl id='twitter'>
|
||||
<FormHelperText color='gray.500'>Twitter</FormHelperText>
|
||||
<Input type='text' size='md' variant='flushed' placeholder='https://twitter.com/id' />
|
||||
</FormControl>
|
||||
<FormControl id='telegram'>
|
||||
<FormHelperText color='gray.500'>Telegram</FormHelperText>
|
||||
<Input type='text' size='md' variant='flushed' placeholder='@tag' />
|
||||
</FormControl>
|
||||
<FormControl id='vk'>
|
||||
<FormHelperText color='gray.500'>VKontakte</FormHelperText>
|
||||
<Input type='text' size='md' variant='flushed' placeholder='https://vk.com/id' />
|
||||
</FormControl>
|
||||
</Stack>
|
||||
</Box>
|
||||
<Button colorScheme='blue' mt='4' type='submit' size='md' variant='outline' rightIcon={<MdSave />}>
|
||||
Save
|
||||
</Button>
|
||||
</Box>
|
||||
<UpdateUserContactsForm />
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
|
||||
8
src/validators/LoginValidatorSchema.ts
Normal file
8
src/validators/LoginValidatorSchema.ts
Normal file
@ -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;
|
||||
Loading…
x
Reference in New Issue
Block a user