2024-02-26 09:39:09 -05:00
|
|
|
import React from 'react';
|
2024-01-23 11:48:56 -05:00
|
|
|
|
2024-02-26 09:39:09 -05:00
|
|
|
import { ViewIcon, ViewOffIcon } from '@chakra-ui/icons';
|
2024-02-28 18:30:59 -05:00
|
|
|
import { Button, Center, Container, FormControl, FormErrorMessage, Icon, Image, Input, InputGroup, InputRightElement, Link, useBoolean } from '@chakra-ui/react';
|
2024-03-07 19:16:23 +01:00
|
|
|
import { Link as RouterLink, createFileRoute, redirect } from '@tanstack/react-router';
|
2024-02-26 09:39:09 -05:00
|
|
|
import { SubmitHandler, useForm } from 'react-hook-form';
|
2024-01-23 11:48:56 -05:00
|
|
|
|
2024-02-26 09:39:09 -05:00
|
|
|
import Logo from '../assets/images/fastapi-logo.svg';
|
2024-02-28 18:30:59 -05:00
|
|
|
import { ApiError } from '../client';
|
2024-02-26 09:39:09 -05:00
|
|
|
import { Body_login_login_access_token as AccessToken } from '../client/models/Body_login_login_access_token';
|
2024-03-07 19:16:23 +01:00
|
|
|
import useAuth, { isLoggedIn } from '../hooks/useAuth';
|
2024-01-23 11:48:56 -05:00
|
|
|
|
2024-03-07 19:16:23 +01:00
|
|
|
export const Route = createFileRoute('/login')({
|
|
|
|
component: Login,
|
|
|
|
beforeLoad: async () => {
|
|
|
|
if (isLoggedIn()) {
|
|
|
|
throw redirect({
|
|
|
|
to: '/',
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
function Login() {
|
2024-02-15 17:17:26 -05:00
|
|
|
const [show, setShow] = useBoolean();
|
2024-03-07 19:16:23 +01:00
|
|
|
const { login } = useAuth();
|
2024-02-28 18:30:59 -05:00
|
|
|
const [error, setError] = React.useState<string | null>(null);
|
|
|
|
const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm<AccessToken>({
|
|
|
|
mode: 'onBlur',
|
|
|
|
criteriaMode: 'all',
|
|
|
|
defaultValues: {
|
|
|
|
username: '',
|
|
|
|
password: ''
|
|
|
|
}
|
|
|
|
});
|
2024-02-26 09:39:09 -05:00
|
|
|
|
2024-01-23 11:48:56 -05:00
|
|
|
const onSubmit: SubmitHandler<AccessToken> = async (data) => {
|
2024-02-28 18:30:59 -05:00
|
|
|
try {
|
|
|
|
await login(data);
|
|
|
|
} catch (err) {
|
|
|
|
const errDetail = (err as ApiError).body.detail;
|
|
|
|
setError(errDetail)
|
|
|
|
}
|
2024-01-23 11:48:56 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
2024-02-12 16:46:51 -05:00
|
|
|
<>
|
|
|
|
<Container
|
2024-02-26 09:39:09 -05:00
|
|
|
as='form'
|
2024-02-12 16:46:51 -05:00
|
|
|
onSubmit={handleSubmit(onSubmit)}
|
2024-02-26 09:39:09 -05:00
|
|
|
h='100vh'
|
|
|
|
maxW='sm'
|
|
|
|
alignItems='stretch'
|
|
|
|
justifyContent='center'
|
2024-02-12 16:46:51 -05:00
|
|
|
gap={4}
|
|
|
|
centerContent
|
|
|
|
>
|
2024-02-28 18:30:59 -05:00
|
|
|
<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>}
|
2024-02-12 16:46:51 -05:00
|
|
|
</FormControl>
|
2024-02-28 18:30:59 -05:00
|
|
|
<FormControl id='password' isInvalid={!!error}>
|
2024-02-12 16:46:51 -05:00
|
|
|
<InputGroup>
|
|
|
|
<Input
|
2024-02-26 09:39:09 -05:00
|
|
|
{...register('password')}
|
|
|
|
type={show ? 'text' : 'password'}
|
2024-02-12 16:46:51 -05:00
|
|
|
|
2024-02-26 09:39:09 -05:00
|
|
|
placeholder='Password'
|
2024-02-12 16:46:51 -05:00
|
|
|
/>
|
|
|
|
<InputRightElement
|
2024-02-26 09:39:09 -05:00
|
|
|
color='gray.400'
|
2024-02-12 16:46:51 -05:00
|
|
|
_hover={{
|
2024-02-26 09:39:09 -05:00
|
|
|
cursor: 'pointer',
|
2024-02-12 16:46:51 -05:00
|
|
|
}}
|
|
|
|
>
|
2024-02-26 09:39:09 -05:00
|
|
|
<Icon onClick={setShow.toggle} aria-label={show ? 'Hide password' : 'Show password'}>
|
2024-02-12 16:46:51 -05:00
|
|
|
{show ? <ViewOffIcon /> : <ViewIcon />}
|
|
|
|
</Icon>
|
|
|
|
</InputRightElement>
|
|
|
|
</InputGroup>
|
2024-02-28 18:30:59 -05:00
|
|
|
{error && <FormErrorMessage>
|
|
|
|
{error}
|
|
|
|
</FormErrorMessage>}
|
2024-02-12 16:46:51 -05:00
|
|
|
</FormControl>
|
2024-02-28 18:30:59 -05:00
|
|
|
<Center>
|
2024-03-07 19:16:23 +01:00
|
|
|
<Link as={RouterLink} to='/recover-password' color='blue.500'>
|
2024-02-28 18:30:59 -05:00
|
|
|
Forgot password?
|
|
|
|
</Link>
|
|
|
|
</Center>
|
|
|
|
<Button bg='ui.main' color='white' _hover={{ opacity: 0.8 }} type='submit' isLoading={isSubmitting}>
|
2024-02-12 16:46:51 -05:00
|
|
|
Log In
|
|
|
|
</Button>
|
|
|
|
</Container>
|
|
|
|
</>
|
2024-01-23 11:48:56 -05:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default Login;
|