blob: 4608a59e564d032a8578ebc5a4bef99a824e6aa7 [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';
28
29export default function SetupLogin() {
30 const [isSetupComplete, setIsSetupComplete] = useState(false);
31 const [password, setPassword] = useState('');
32 const [passwordRepeat, setPasswordRepeat] = useState('');
33 const [loading, setLoading] = useState(false);
34 const { t } = useTranslation();
35 const navigate = useNavigate();
36
37 useEffect(() => {
38 checkSetupStatus().then(setIsSetupComplete);
39 }, []);
40
41 const adminCreation = async (password: string) => {
Michelle Sepkap Sime6967fb92022-11-08 08:39:36 -050042 let response: Response;
43 try {
simon94fe53e2022-11-10 12:51:58 -050044 response = await axios.post(
45 '/setup/admin/create',
46 { password },
47 {
48 baseURL: apiUrl,
49 }
50 );
Michelle Sepkap Sime6967fb92022-11-08 08:39:36 -050051 } catch (e) {
52 throw new Error(`Admin creation failed`);
53 }
54
55 if (response.status !== HttpStatusCode.Created) {
56 throw new Error('Admin creation failed');
57 }
58 };
59
60 const adminLogin = async (password: string) => {
Michelle Sepkap Sime6967fb92022-11-08 08:39:36 -050061 let response: Response;
62 try {
simon94fe53e2022-11-10 12:51:58 -050063 response = await axios.post(
64 '/setup/admin/login',
65 { password },
66 {
67 baseURL: apiUrl,
68 }
69 );
70 } catch (e) {
Michelle Sepkap Sime6967fb92022-11-08 08:39:36 -050071 throw new Error(`Admin login failed`);
72 }
73
74 if (response.status === HttpStatusCode.Forbidden) {
75 throw new Error('Invalid password');
76 }
77
78 if (response.status !== HttpStatusCode.Ok) {
79 throw new Error('Admin login failed');
80 }
81
82 const data: { accessToken: string } = await response.json();
83 localStorage.setItem('adminAccessToken', data.accessToken);
84 };
85
86 const isValid = isSetupComplete || (password && password === passwordRepeat);
87
88 const handleSubmit = async (e: FormEvent) => {
89 e.preventDefault();
90 setLoading(true);
91 if (!isValid) return;
92
93 try {
94 if (!isSetupComplete) {
95 await adminCreation(password);
96 }
97 await adminLogin(password);
98 } catch (e) {
99 console.error(e);
100 navigate('/login');
101 return;
102 }
103 navigate('/setup');
104 };
105
106 return (
107 <Container className="message-list">
108 <Card>
109 <CardContent component="form" onSubmit={handleSubmit}>
110 <Typography gutterBottom variant="h5" component="h2">
111 {t('setup_login_title')}
112 </Typography>
113 <Typography variant="body2" color="textSecondary" component="p">
114 {t('setup_login_welcome')}
115 <br />
116 {isSetupComplete ? '' : t('setup_login_admin_creation')}
117 </Typography>
118
119 <Box style={{ textAlign: 'center', marginTop: 8, marginBottom: 16 }}>
120 <div>
121 <Input value="admin" name="username" autoComplete="username" disabled />
122 </div>
123 <div>
124 <Input
125 value={password}
126 onChange={(e) => setPassword(e.target.value)}
127 name="password"
128 type="password"
129 placeholder={
130 isSetupComplete ? t('password_placeholder') : t('setup_login_password_placeholder_creation')
131 }
132 autoComplete="new-password"
133 disabled={loading}
134 />
135 </div>
136 {!isSetupComplete && (
137 <div>
138 <Input
139 value={passwordRepeat}
140 onChange={(e) => setPasswordRepeat(e.target.value)}
141 name="password"
142 error={!!passwordRepeat && !isValid}
143 type="password"
144 placeholder={t('setup_login_password_placeholder_repeat')}
145 autoComplete="new-password"
146 disabled={loading}
147 />
148 </div>
149 )}
150 </Box>
151 <Box style={{ textAlign: 'center', marginTop: 24 }}>
152 <Fab variant="extended" color="primary" type="submit" disabled={!isValid || loading}>
153 <GroupAddRounded />
154 {isSetupComplete ? t('login_form_submit_button') : t('admin_creation_submit_button')}
155 </Fab>
156 </Box>
157 </CardContent>
158 </Card>
159 </Container>
160 );
161}