Paulo Gustavo Veiga cbca2e6184 JWT impl.
2024-02-06 21:48:04 -08:00

173 lines
5.2 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { FormattedMessage, useIntl } from 'react-intl';
import { Link as RouterLink, useNavigate } from 'react-router-dom';
import Header from '../layout/header';
import Footer from '../layout/footer';
import SubmitButton from '../form/submit-button';
import Input from '../form/input';
import GlobalError from '../form/global-error';
import FormContainer from '../layout/form-container';
import Typography from '@mui/material/Typography';
import FormControl from '@mui/material/FormControl';
import Link from '@mui/material/Link';
import ReactGA from 'react-ga4';
import Separator from '../common/separator';
import GoogleButton from '../common/google-button';
import AppConfig from '../../classes/app-config';
import CSRFInput from '../common/csrf-input';
import { useMutation } from 'react-query';
import { useSelector } from 'react-redux';
import Client, { ErrorInfo } from '../../classes/client';
import { activeInstance } from '../../redux/clientSlice';
export type Model = {
email: string;
password: string;
};
const defaultModel: Model = { email: '', password: '' };
const LoginError = () => {
// @Todo: This must be reviewed to be based on navigation state.
// Login error example: http://localhost:8080/c/login?login.error=2
const errorCode = new URLSearchParams(window.location.search).get('login_error');
const intl = useIntl();
let msg: null | string = null;
if (errorCode) {
switch (errorCode) {
case '3':
msg = intl.formatMessage({
id: 'login.userinactive',
defaultMessage:
"Sorry, your account has not been activated yet. You'll receive a notification email when it becomes active. Stay tuned!.",
});
break;
default:
msg = intl.formatMessage({
id: 'login.error',
defaultMessage: 'The email address or password you entered is not valid.',
});
}
}
return msg ? <GlobalError error={{ msg: msg }} /> : null;
};
const LoginPage = (): React.ReactElement => {
const intl = useIntl();
const [model, setModel] = useState<Model>(defaultModel);
const client: Client = useSelector(activeInstance);
const navigate = useNavigate();
useEffect(() => {
document.title = intl.formatMessage({
id: 'login.page-title',
defaultMessage: 'Login | WiseMapping',
});
ReactGA.send({ hitType: 'pageview', page: window.location.pathname, title: 'Login' });
}, []);
const mutation = useMutation<void, ErrorInfo, Model>(
(model: Model) => client.login({ ...model }),
{
onSuccess: () => navigate('/c/maps/'),
onError: (error) => {
console.log(error);
},
},
);
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
mutation.mutate(model);
event.preventDefault();
};
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
event.preventDefault();
const name = event.target.name;
const value = event.target.value;
setModel({ ...model, [name as keyof Model]: value });
};
return (
<div>
<Header type="only-signup" />
<FormContainer>
<Typography variant="h4" component="h1">
<FormattedMessage id="login.title" defaultMessage="Welcome" />
</Typography>
<Typography paragraph>
<FormattedMessage id="login.desc" defaultMessage="Log into your account" />
</Typography>
<LoginError />
<FormControl>
<form onSubmit={handleOnSubmit}>
<CSRFInput />
<Input
onChange={handleOnChange}
name="email"
type="email"
label={intl.formatMessage({
id: 'login.email',
defaultMessage: 'Email',
})}
required
autoComplete="email"
/>
<Input
onChange={handleOnChange}
name="password"
type="password"
label={intl.formatMessage({
id: 'login.password',
defaultMessage: 'Password',
})}
required
autoComplete="current-password"
/>
<SubmitButton
value={intl.formatMessage({
id: 'login.signin',
defaultMessage: 'Sign In',
})}
/>
</form>
</FormControl>
<Link component={RouterLink} to="/c/forgot-password">
<FormattedMessage id="login.forgotpwd" defaultMessage="Forgot Password ?" />
</Link>
<Separator
responsive={false}
text={intl.formatMessage({
id: 'login.division',
defaultMessage: 'or',
})}
/>
<GoogleButton
text={intl.formatMessage({
id: 'login.google.button',
defaultMessage: 'Sign in with Google',
})}
onClick={() => {
const authUrl = AppConfig.getGoogleOauth2Url();
if (authUrl) {
window.location.href = authUrl;
} else {
console.log('GoogleOauth2Url is not configured.');
}
}}
/>
</FormContainer>
<Footer />
</div>
);
};
export default LoginPage;