Files
dta_webapp/ditch-the-agent/src/pages/authentication/Login.tsx

206 lines
6.9 KiB
TypeScript

import { ReactElement, Suspense, useContext, useState } from 'react';
import {
Alert,
Button,
FormControl,
IconButton,
InputAdornment,
InputLabel,
Link,
Skeleton,
Stack,
TextField,
Typography,
} from '@mui/material';
import loginBanner from 'assets/authentication-banners/green.png';
import IconifyIcon from 'components/base/IconifyIcon';
import logo from 'assets/logo/favicon-logo.png';
import Image from 'components/base/Image';
import { axiosInstance } from '../../axiosApi.js';
import { useNavigate } from 'react-router-dom';
import { Form, Formik } from 'formik';
import { AuthContext } from 'contexts/AuthContext.js';
type loginValues = {
email: string;
password: string;
};
const Login = (): ReactElement => {
const [showPassword, setShowPassword] = useState(false);
const handleClickShowPassword = () => setShowPassword(!showPassword);
const [errorMessage, setErrorMessage] = useState<any | null>(null);
const navigate = useNavigate();
const { setAuthentication } = useContext(AuthContext);
const handleLogin = async ({ email, password }: loginValues): Promise<void> => {
try {
const response = await axiosInstance.post('/token/', {
email: email,
password: password,
});
axiosInstance.defaults.headers['Authorization'] = 'JWT ' + response.data.access;
localStorage.setItem('access_token', response.data.access);
localStorage.setItem('refresh_token', response.data.refresh);
const get_user_response = await axiosInstance.get('/user/');
setAuthentication(true);
navigate('/dashboard');
} catch (error) {
const hasErrors = Object.keys(error.response.data).length > 0;
if (hasErrors) {
setErrorMessage(error.response.data);
} else {
setErrorMessage(null);
}
}
};
return (
<Stack
direction="row"
bgcolor="background.paper"
boxShadow={(theme) => theme.shadows[3]}
height={560}
width={{ md: 960 }}
>
<Stack width={{ md: 0.5 }} m={2.5} gap={10}>
<Link href="/" height="fit-content">
<Image src={logo} width={82.6} />
</Link>
<Stack alignItems="center" gap={2.5} width={330} mx="auto">
<Typography variant="h3">Login</Typography>
<Formik
initialValues={{
email: '',
password: '',
}}
onSubmit={handleLogin}
>
{({ setFieldValue }) => (
<Form>
<FormControl variant="standard" fullWidth>
{errorMessage ? (
<Alert severity="error">
{errorMessage.detail ? (
<Typography>{errorMessage.detail}</Typography>
) : (
<ul>
{Object.entries(errorMessage).map(([fieldName, errorMessages]) => (
<li key={fieldName}>
<strong>{fieldName}</strong>
{Array.isArray(errorMessages) ? (
<ul>
{errorMessages.map((message, index) => (
<li key={`${fieldName}-${index}`}>{message}</li>
))}
</ul>
) : (
<span>: {String(errorMessages)}</span>
)}
</li>
))}
</ul>
)}
</Alert>
) : null}
<InputLabel shrink htmlFor="email">
Email
</InputLabel>
<TextField
variant="filled"
placeholder="Enter your email"
id="email"
onChange={(event) => setFieldValue('email', event.target.value)}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconifyIcon icon="ic:baseline-email" />
</InputAdornment>
),
}}
/>
</FormControl>
<FormControl variant="standard" fullWidth>
<InputLabel shrink htmlFor="password">
Password
</InputLabel>
<TextField
variant="filled"
placeholder="********"
onChange={(event) => setFieldValue('password', event.target.value)}
type={showPassword ? 'text' : 'password'}
id="password"
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
edge="end"
sx={{
color: 'text.secondary',
}}
>
{showPassword ? (
<IconifyIcon icon="ic:baseline-key-off" />
) : (
<IconifyIcon icon="ic:baseline-key" />
)}
</IconButton>
</InputAdornment>
),
}}
/>
</FormControl>
<Typography
variant="body1"
sx={{
alignSelf: 'flex-end',
}}
>
<Link href="/authentication/forgot-password" underline="hover">
Forget password
</Link>
</Typography>
<Button variant="contained" type={'submit'} fullWidth>
Log in
</Button>
</Form>
)}
</Formik>
<Typography variant="body2" color="text.secondary">
Don't have an account ?{' '}
<Link
href="/authentication/sign-up"
underline="hover"
fontSize={(theme) => theme.typography.body1.fontSize}
>
Sign up
</Link>
</Typography>
</Stack>
</Stack>
<Suspense
fallback={
<Skeleton variant="rectangular" height={1} width={1} sx={{ bgcolor: 'primary.main' }} />
}
>
<Image
alt="Login banner"
src={loginBanner}
sx={{
width: 0.5,
display: { xs: 'none', md: 'block' },
}}
/>
</Suspense>
</Stack>
);
};
export default Login;