blob: d34d366114b88a75e9920db1dd67242bb900bbfc [file] [log] [blame]
Michelle Sepkap Sime6967fb92022-11-08 08:39:36 -05001/*
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 */
18import GroupAddRounded from '@mui/icons-material/GroupAddRounded';
19import { Box, Card, CardContent, Container, Fab, Input, Typography } from '@mui/material';
simon94fe53e2022-11-10 12:51:58 -050020import axios from 'axios';
Michelle Sepkap Sime6967fb92022-11-08 08:39:36 -050021import { HttpStatusCode } from 'jami-web-common';
22import { FormEvent, useEffect, useState } from 'react';
23import { useTranslation } from 'react-i18next';
24import { useNavigate } from 'react-router-dom';
25
26import { checkSetupStatus } from '../App';
27import { apiUrl } from '../utils/constants';
Misha Krieger-Raynauld46e9d242022-11-12 18:02:43 -050028import { InvalidPassword } from '../utils/errors';
Michelle Sepkap Sime6967fb92022-11-08 08:39:36 -050029
30export default function SetupLogin() {
31 const [isSetupComplete, setIsSetupComplete] = useState(false);
32 const [password, setPassword] = useState('');
33 const [passwordRepeat, setPasswordRepeat] = useState('');
34 const [loading, setLoading] = useState(false);
35 const { t } = useTranslation();
36 const navigate = useNavigate();
37
38 useEffect(() => {
39 checkSetupStatus().then(setIsSetupComplete);
40 }, []);
41
Misha Krieger-Raynauld46e9d242022-11-12 18:02:43 -050042 const registerAdmin = async (password: string) => {
43 await axios.post('/setup/admin/create', { password }, { baseURL: apiUrl });
Michelle Sepkap Sime6967fb92022-11-08 08:39:36 -050044 };
45
Misha Krieger-Raynauld46e9d242022-11-12 18:02:43 -050046 const loginAdmin = async (password: string) => {
Michelle Sepkap Sime6967fb92022-11-08 08:39:36 -050047 try {
Misha Krieger-Raynauld46e9d242022-11-12 18:02:43 -050048 const { data } = await axios.post('/setup/admin/login', { password }, { baseURL: apiUrl });
49 localStorage.setItem('adminAccessToken', data.accessToken);
50 } catch (e: any) {
51 if (e.response?.status === HttpStatusCode.Forbidden) {
52 throw new InvalidPassword();
53 } else {
54 throw e;
55 }
Michelle Sepkap Sime6967fb92022-11-08 08:39:36 -050056 }
Michelle Sepkap Sime6967fb92022-11-08 08:39:36 -050057 };
58
59 const isValid = isSetupComplete || (password && password === passwordRepeat);
60
61 const handleSubmit = async (e: FormEvent) => {
62 e.preventDefault();
63 setLoading(true);
64 if (!isValid) return;
65
66 try {
67 if (!isSetupComplete) {
Misha Krieger-Raynauld46e9d242022-11-12 18:02:43 -050068 await registerAdmin(password);
Michelle Sepkap Sime6967fb92022-11-08 08:39:36 -050069 }
Misha Krieger-Raynauld46e9d242022-11-12 18:02:43 -050070 await loginAdmin(password);
Michelle Sepkap Sime6967fb92022-11-08 08:39:36 -050071 } catch (e) {
72 console.error(e);
73 navigate('/login');
74 return;
75 }
76 navigate('/setup');
77 };
78
79 return (
80 <Container className="message-list">
81 <Card>
82 <CardContent component="form" onSubmit={handleSubmit}>
83 <Typography gutterBottom variant="h5" component="h2">
84 {t('setup_login_title')}
85 </Typography>
86 <Typography variant="body2" color="textSecondary" component="p">
87 {t('setup_login_welcome')}
88 <br />
89 {isSetupComplete ? '' : t('setup_login_admin_creation')}
90 </Typography>
91
92 <Box style={{ textAlign: 'center', marginTop: 8, marginBottom: 16 }}>
93 <div>
94 <Input value="admin" name="username" autoComplete="username" disabled />
95 </div>
96 <div>
97 <Input
98 value={password}
99 onChange={(e) => setPassword(e.target.value)}
100 name="password"
101 type="password"
102 placeholder={
103 isSetupComplete ? t('password_placeholder') : t('setup_login_password_placeholder_creation')
104 }
105 autoComplete="new-password"
106 disabled={loading}
107 />
108 </div>
109 {!isSetupComplete && (
110 <div>
111 <Input
112 value={passwordRepeat}
113 onChange={(e) => setPasswordRepeat(e.target.value)}
114 name="password"
115 error={!!passwordRepeat && !isValid}
116 type="password"
117 placeholder={t('setup_login_password_placeholder_repeat')}
118 autoComplete="new-password"
119 disabled={loading}
120 />
121 </div>
122 )}
123 </Box>
124 <Box style={{ textAlign: 'center', marginTop: 24 }}>
125 <Fab variant="extended" color="primary" type="submit" disabled={!isValid || loading}>
126 <GroupAddRounded />
127 {isSetupComplete ? t('login_form_submit_button') : t('admin_creation_submit_button')}
128 </Fab>
129 </Box>
130 </CardContent>
131 </Card>
132 </Container>
133 );
134}