blob: 193497b62dee17926104dc51d0030941ed535af7 [file] [log] [blame]
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -04001/*
2 * Copyright (C) 2022 Savoir-faire Linux Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as
6 * published by the Free Software Foundation; either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public
15 * License along with this program. If not, see
16 * <https://www.gnu.org/licenses/>.
17 */
Gabriel Rochon7057b4f2022-11-21 13:28:01 -050018import {
19 Box,
20 Button,
21 FormControl,
22 FormControlLabel,
23 Radio,
24 RadioGroup,
25 Stack,
26 Typography,
27 useMediaQuery,
28} from '@mui/material';
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040029import { Theme, useTheme } from '@mui/material/styles';
Ziwei Wang3ce1ac02023-02-03 11:59:03 -050030import { ChangeEvent, FormEvent, ReactNode, useState } from 'react';
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040031import { useTranslation } from 'react-i18next';
Ziwei Wang3ce1ac02023-02-03 11:59:03 -050032import { Form, Link, useNavigate } from 'react-router-dom';
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040033
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040034import { AlertSnackbar } from '../components/AlertSnackbar';
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040035import { PasswordInput, UsernameInput } from '../components/Input';
36import ProcessingRequest from '../components/ProcessingRequest';
Ziwei Wang3ce1ac02023-02-03 11:59:03 -050037import withAuthUI from '../components/WithAuthUI';
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040038import { loginUser, setAccessToken } from '../utils/auth';
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040039import { inputWidth } from '../utils/constants';
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040040import { InvalidPassword, UsernameNotFound } from '../utils/errors';
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040041
Ziwei Wang3ce1ac02023-02-03 11:59:03 -050042function LoginForm() {
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040043 const theme: Theme = useTheme();
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040044 const navigate = useNavigate();
45 const { t } = useTranslation();
46
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040047 const [username, setUsername] = useState<string>('');
48 const [password, setPassword] = useState<string>('');
Gabriel Rochon7057b4f2022-11-21 13:28:01 -050049 const [isJams, setIsJams] = useState<boolean>(false);
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040050 const [isLoggingInUser, setIsLoggingInUser] = useState<boolean>(false);
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040051 const [errorAlertContent, setErrorAlertContent] = useState<ReactNode>(undefined);
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040052
53 const handleUsername = (event: ChangeEvent<HTMLInputElement>) => {
54 setUsername(event.target.value);
55 };
56
57 const handlePassword = (event: ChangeEvent<HTMLInputElement>) => {
58 setPassword(event.target.value);
59 };
60
Gabriel Rochon7057b4f2022-11-21 13:28:01 -050061 const handleIsJams = (event: ChangeEvent<HTMLInputElement>) => {
62 setIsJams(event.target.value === 'true');
63 };
64
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040065 const authenticateUser = async (event: FormEvent) => {
66 event.preventDefault();
67 if (username.length > 0 && password.length > 0) {
68 setIsLoggingInUser(true);
69
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040070 try {
Gabriel Rochon7057b4f2022-11-21 13:28:01 -050071 const accessToken = await loginUser(username, password, isJams);
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040072 setAccessToken(accessToken);
idillon3470d072022-11-22 15:22:34 -050073 navigate('/conversation', { replace: true });
simon94fe53e2022-11-10 12:51:58 -050074 } catch (e) {
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040075 setIsLoggingInUser(false);
simon94fe53e2022-11-10 12:51:58 -050076 if (e instanceof UsernameNotFound) {
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040077 setErrorAlertContent(t('login_username_not_found'));
simon94fe53e2022-11-10 12:51:58 -050078 } else if (e instanceof InvalidPassword) {
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040079 setErrorAlertContent(t('login_invalid_password'));
80 } else {
Ziwei Wangce81edd2023-02-03 13:43:22 -050081 setErrorAlertContent(t('unknown_error_alert'));
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040082 }
83 }
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040084 }
85 };
86
87 const isMobile: boolean = useMediaQuery(theme.breakpoints.only('xs'));
88
89 return (
90 <>
91 <ProcessingRequest open={isLoggingInUser} />
92
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040093 <AlertSnackbar severity={'error'} open={!!errorAlertContent} onClose={() => setErrorAlertContent(undefined)}>
94 {errorAlertContent}
95 </AlertSnackbar>
96
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040097 <Stack
98 sx={{
99 minHeight: `${isMobile ? 'auto' : '100%'}`,
100 display: 'flex',
101 alignItems: 'center',
102 justifyContent: 'center',
103 }}
104 >
105 <Box sx={{ mt: theme.typography.pxToRem(50), mb: theme.typography.pxToRem(20) }}>
106 <Typography component={'span'} variant="h2">
Michelle Sepkap Sime559cc802022-11-05 12:06:40 -0400107 {t('login_form_title')}
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400108 </Typography>
109 </Box>
110
111 <Form method="post" id="login-form">
112 <div>
113 <UsernameInput
114 onChange={handleUsername}
Michelle Sepkap Sime559cc802022-11-05 12:06:40 -0400115 tooltipTitle={t('login_form_username_tooltip')}
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400116 sx={{ width: theme.typography.pxToRem(inputWidth) }}
117 />
118 </div>
119 <div>
120 <PasswordInput
121 onChange={handlePassword}
Michelle Sepkap Sime559cc802022-11-05 12:06:40 -0400122 tooltipTitle={t('login_form_password_tooltip')}
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400123 sx={{ width: theme.typography.pxToRem(inputWidth) }}
124 />
125 </div>
Gabriel Rochon7057b4f2022-11-21 13:28:01 -0500126 <div>
127 <FormControl
128 sx={{
129 width: theme.typography.pxToRem(inputWidth),
130 alignItems: 'center',
131 justifyContent: 'space-between',
132 }}
133 >
134 <RadioGroup row onChange={handleIsJams} value={isJams}>
135 <FormControlLabel value="false" control={<Radio />} label={t('jami')} />
136 <FormControlLabel value="true" control={<Radio />} label={t('jams')} />
137 </RadioGroup>
138 </FormControl>
139 </div>
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400140
141 <Button
142 variant="contained"
143 type="submit"
144 onClick={authenticateUser}
145 sx={{ width: theme.typography.pxToRem(inputWidth), mt: theme.typography.pxToRem(20) }}
146 >
Michelle Sepkap Sime559cc802022-11-05 12:06:40 -0400147 {t('login_form_submit_button')}
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400148 </Button>
149 </Form>
150
151 <Box sx={{ mt: theme.typography.pxToRem(50), mb: theme.typography.pxToRem(50) }}>
152 <Typography variant="body1">
Michelle Sepkap Sime559cc802022-11-05 12:06:40 -0400153 {t('login_form_to_registration_text')} &nbsp;
Ziwei Wang3ce1ac02023-02-03 11:59:03 -0500154 <Link to={'/register'}>{t('login_form_to_registration_link')}</Link>
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400155 </Typography>
156 </Box>
157 </Stack>
158 </>
159 );
160}
Ziwei Wang3ce1ac02023-02-03 11:59:03 -0500161
162export default withAuthUI(LoginForm);