blob: 3d069950ee19bb5c5a8aba137a4292c521ed6d65 [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';
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040030import { ChangeEvent, FormEvent, MouseEvent, ReactNode, useState } from 'react';
31import { useTranslation } from 'react-i18next';
32import { Form, 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';
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040037import { loginUser, setAccessToken } from '../utils/auth';
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040038import { inputWidth } from '../utils/constants';
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040039import { InvalidPassword, UsernameNotFound } from '../utils/errors';
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040040
41type JamiLoginProps = {
42 register: () => void;
43};
44
45export default function JamiLogin(props: JamiLoginProps) {
46 const theme: Theme = useTheme();
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040047 const navigate = useNavigate();
48 const { t } = useTranslation();
49
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040050 const [username, setUsername] = useState<string>('');
51 const [password, setPassword] = useState<string>('');
Gabriel Rochon7057b4f2022-11-21 13:28:01 -050052 const [isJams, setIsJams] = useState<boolean>(false);
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040053 const [isLoggingInUser, setIsLoggingInUser] = useState<boolean>(false);
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040054 const [errorAlertContent, setErrorAlertContent] = useState<ReactNode>(undefined);
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040055
56 const handleUsername = (event: ChangeEvent<HTMLInputElement>) => {
57 setUsername(event.target.value);
58 };
59
60 const handlePassword = (event: ChangeEvent<HTMLInputElement>) => {
61 setPassword(event.target.value);
62 };
63
Gabriel Rochon7057b4f2022-11-21 13:28:01 -050064 const handleIsJams = (event: ChangeEvent<HTMLInputElement>) => {
65 setIsJams(event.target.value === 'true');
66 };
67
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040068 const register = (event: MouseEvent<HTMLAnchorElement>) => {
69 event.preventDefault();
70 props.register();
71 };
72
73 const authenticateUser = async (event: FormEvent) => {
74 event.preventDefault();
75 if (username.length > 0 && password.length > 0) {
76 setIsLoggingInUser(true);
77
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040078 try {
Gabriel Rochon7057b4f2022-11-21 13:28:01 -050079 const accessToken = await loginUser(username, password, isJams);
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040080 setAccessToken(accessToken);
idillon3470d072022-11-22 15:22:34 -050081 navigate('/conversation', { replace: true });
simon94fe53e2022-11-10 12:51:58 -050082 } catch (e) {
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040083 setIsLoggingInUser(false);
simon94fe53e2022-11-10 12:51:58 -050084 if (e instanceof UsernameNotFound) {
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040085 setErrorAlertContent(t('login_username_not_found'));
simon94fe53e2022-11-10 12:51:58 -050086 } else if (e instanceof InvalidPassword) {
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040087 setErrorAlertContent(t('login_invalid_password'));
88 } else {
simon94fe53e2022-11-10 12:51:58 -050089 throw e;
Michelle Sepkap Simee580f422022-10-31 23:27:04 -040090 }
91 }
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -040092 }
93 };
94
95 const isMobile: boolean = useMediaQuery(theme.breakpoints.only('xs'));
96
97 return (
98 <>
99 <ProcessingRequest open={isLoggingInUser} />
100
Michelle Sepkap Simee580f422022-10-31 23:27:04 -0400101 <AlertSnackbar severity={'error'} open={!!errorAlertContent} onClose={() => setErrorAlertContent(undefined)}>
102 {errorAlertContent}
103 </AlertSnackbar>
104
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400105 <Stack
106 sx={{
107 minHeight: `${isMobile ? 'auto' : '100%'}`,
108 display: 'flex',
109 alignItems: 'center',
110 justifyContent: 'center',
111 }}
112 >
113 <Box sx={{ mt: theme.typography.pxToRem(50), mb: theme.typography.pxToRem(20) }}>
114 <Typography component={'span'} variant="h2">
Michelle Sepkap Sime559cc802022-11-05 12:06:40 -0400115 {t('login_form_title')}
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400116 </Typography>
117 </Box>
118
119 <Form method="post" id="login-form">
120 <div>
121 <UsernameInput
122 onChange={handleUsername}
Michelle Sepkap Sime559cc802022-11-05 12:06:40 -0400123 tooltipTitle={t('login_form_username_tooltip')}
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400124 sx={{ width: theme.typography.pxToRem(inputWidth) }}
125 />
126 </div>
127 <div>
128 <PasswordInput
129 onChange={handlePassword}
Michelle Sepkap Sime559cc802022-11-05 12:06:40 -0400130 tooltipTitle={t('login_form_password_tooltip')}
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400131 sx={{ width: theme.typography.pxToRem(inputWidth) }}
132 />
133 </div>
Gabriel Rochon7057b4f2022-11-21 13:28:01 -0500134 <div>
135 <FormControl
136 sx={{
137 width: theme.typography.pxToRem(inputWidth),
138 alignItems: 'center',
139 justifyContent: 'space-between',
140 }}
141 >
142 <RadioGroup row onChange={handleIsJams} value={isJams}>
143 <FormControlLabel value="false" control={<Radio />} label={t('jami')} />
144 <FormControlLabel value="true" control={<Radio />} label={t('jams')} />
145 </RadioGroup>
146 </FormControl>
147 </div>
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400148
149 <Button
150 variant="contained"
151 type="submit"
152 onClick={authenticateUser}
153 sx={{ width: theme.typography.pxToRem(inputWidth), mt: theme.typography.pxToRem(20) }}
154 >
Michelle Sepkap Sime559cc802022-11-05 12:06:40 -0400155 {t('login_form_submit_button')}
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400156 </Button>
157 </Form>
158
159 <Box sx={{ mt: theme.typography.pxToRem(50), mb: theme.typography.pxToRem(50) }}>
160 <Typography variant="body1">
Michelle Sepkap Sime559cc802022-11-05 12:06:40 -0400161 {t('login_form_to_registration_text')} &nbsp;
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400162 <a href="" onClick={register}>
Michelle Sepkap Sime559cc802022-11-05 12:06:40 -0400163 {t('login_form_to_registration_link')}
Michelle Sepkap Sime51c00452022-10-31 21:26:38 -0400164 </a>
165 </Typography>
166 </Box>
167 </Stack>
168 </>
169 );
170}