Files
full-stack-fastapi-template/new-frontend/src/pages/Login.tsx

89 lines
3.0 KiB
TypeScript
Raw Normal View History

import React from 'react';
2024-01-23 11:48:56 -05:00
import { ViewIcon, ViewOffIcon } from '@chakra-ui/icons';
import { Button, Center, Container, FormControl, FormErrorMessage, Icon, Image, Input, InputGroup, InputRightElement, Link, useBoolean } from '@chakra-ui/react';
import { SubmitHandler, useForm } from 'react-hook-form';
import { Link as ReactRouterLink } from 'react-router-dom';
2024-01-23 11:48:56 -05:00
import Logo from '../assets/images/fastapi-logo.svg';
import { ApiError } from '../client';
import { Body_login_login_access_token as AccessToken } from '../client/models/Body_login_login_access_token';
import useAuth from '../hooks/useAuth';
2024-01-23 11:48:56 -05:00
const Login: React.FC = () => {
const [show, setShow] = useBoolean();
const [error, setError] = React.useState<string | null>(null);
const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm<AccessToken>({
mode: 'onBlur',
criteriaMode: 'all',
defaultValues: {
username: '',
password: ''
}
});
const { login } = useAuth();
2024-01-23 11:48:56 -05:00
const onSubmit: SubmitHandler<AccessToken> = async (data) => {
try {
await login(data);
} catch (err) {
const errDetail = (err as ApiError).body.detail;
setError(errDetail)
}
2024-01-23 11:48:56 -05:00
};
return (
<>
<Container
as='form'
onSubmit={handleSubmit(onSubmit)}
h='100vh'
maxW='sm'
alignItems='stretch'
justifyContent='center'
gap={4}
centerContent
>
<Image src={Logo} alt='FastAPI logo' height='auto' maxW='2xs' alignSelf='center' mb={4} />
<FormControl id='username' isInvalid={!!errors.username || !!error}>
<Input id='username' {...register('username', { pattern: { value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i, message: 'Invalid email address' } })} placeholder='Email' type='text' />
{errors.username && <FormErrorMessage>{errors.username.message}</FormErrorMessage>}
</FormControl>
<FormControl id='password' isInvalid={!!error}>
<InputGroup>
<Input
{...register('password')}
type={show ? 'text' : 'password'}
placeholder='Password'
/>
<InputRightElement
color='gray.400'
_hover={{
cursor: 'pointer',
}}
>
<Icon onClick={setShow.toggle} aria-label={show ? 'Hide password' : 'Show password'}>
{show ? <ViewOffIcon /> : <ViewIcon />}
</Icon>
</InputRightElement>
</InputGroup>
{error && <FormErrorMessage>
{error}
</FormErrorMessage>}
</FormControl>
<Center>
<Link as={ReactRouterLink} to='/recover-password' color='blue.500'>
Forgot password?
</Link>
</Center>
<Button bg='ui.main' color='white' _hover={{ opacity: 0.8 }} type='submit' isLoading={isSubmitting}>
Log In
</Button>
</Container>
</>
2024-01-23 11:48:56 -05:00
);
};
export default Login;