Skip to content

Commit 45fbbd7

Browse files
committed
frontend: add button to delete account to user page.
1 parent df4df17 commit 45fbbd7

File tree

6 files changed

+91
-12
lines changed

6 files changed

+91
-12
lines changed

frontend/public/locales/de-DE/translation.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
"current_password_error_message": "Darf nicht leer sein.",
1313
"new_password": "Neues Passwort",
1414
"new_password_error_message": "Muss mindestens 8 Zeichen lang sein und jeweils mindestens einen Klein- und Großbuchstaben sowie ein Sonderzeichen enthalten.",
15-
"close": "Schließen"
15+
"close": "Schließen",
16+
"delete_user": "Account löschen",
17+
"password": "Passwort",
18+
"password_invalid": "Passwort ist falsch"
1619
},
1720
"recovery": {
1821
"recovery": "Passwort zurücksetzen",

frontend/public/locales/de/translation.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
"current_password_error_message": "Darf nicht leer sein.",
1313
"new_password": "Neues Passwort",
1414
"new_password_error_message": "Muss mindestens 8 Zeichen lang sein und jeweils mindestens einen Klein- und Großbuchstaben sowie ein Sonderzeichen enthalten.",
15-
"close": "Schließen"
15+
"close": "Schließen",
16+
"delete_user": "Account löschen",
17+
"password": "Passwort",
18+
"password_invalid": "Passwort ist falsch"
1619
},
1720
"recovery": {
1821
"recovery": "Passwort zurücksetzen",

frontend/public/locales/en/translation.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
"current_password_error_message": "Must not be empty.",
1313
"new_password": "New password",
1414
"new_password_error_message": "Must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters",
15-
"close": "Close"
15+
"close": "Close",
16+
"delete_user": "Delete account",
17+
"password": "Password",
18+
"password_invalid": "Password is wrong"
1619
},
1720
"recovery": {
1821
"recovery": "Password recovery",

frontend/src/components/login.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ export class Login extends Component<{}, LoginState> {
4949
return;
5050
}
5151

52+
const loginSaltBs64 = Base64.fromUint8Array(login_salt);
53+
window.localStorage.setItem("LoginKey", loginSaltBs64);
54+
5255
const login_key = await generate_hash(this.state.password, login_salt);
5356

5457
const login_schema: LoginSchema = {

frontend/src/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ async function refresh_access_token() {
5353
credentials: "include"
5454
});
5555

56+
if (!localStorage.getItem("loginKey") || !localStorage.getItem("secret_key")) {
57+
loggedIn.value = AppState.LoggedOut
58+
}
59+
5660
if (resp.status == 200) {
5761
loggedIn.value = AppState.LoggedIn;
5862
} else {

frontend/src/pages/user.tsx

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ import { useTranslation } from "react-i18next";
3030
import { Card, Container } from "react-bootstrap";
3131
import { signal } from "@preact/signals";
3232
import { PasswordComponent } from "../components/password_component";
33+
import i18n from "../i18n";
34+
import { showAlert } from "../components/Alert";
35+
import { Base64 } from "js-base64";
3336

3437

3538
interface UserState {
@@ -116,15 +119,18 @@ class UserComponent extends Component<{}, State> {
116119
}
117120

118121
export function User() {
119-
const [show, setShow] = useState(false);
122+
const [showPasswordReset, setShowPasswordReset] = useState(false);
123+
const [deleteUser, setDeleteUser] = useState({show: false, password: "", password_valid: true});
120124
const [currentPassword, setCurrentPassword] = useState("");
121125
const [currentPasswordIsValid, setCurrentPasswordIsValid] = useState(true);
122126
const [newPassword, setNewPassword] = useState("");
123127
const [newPasswordIsValid, setNewPasswordIsValid] = useState(true);
124128
const validated = signal(false);
125129

126-
const handleClose = () => setShow(false);
127-
const handleShow = () => setShow(true);
130+
const handleUpdatePasswordClose = () => setShowPasswordReset(false);
131+
const handleUpdatePasswordShow = () => setShowPasswordReset(true);
132+
const handleDelteUserClose = () => setDeleteUser({...deleteUser, show: false});
133+
const handleDeleteUserShow = () => setDeleteUser({...deleteUser, show: true});
128134

129135
const checkPasswords = () => {
130136
let ret = true;
@@ -147,7 +153,7 @@ export function User() {
147153
return ret;
148154
}
149155

150-
const submit = async (e: SubmitEvent) => {
156+
const submitUpdatePassword = async (e: SubmitEvent) => {
151157
e.preventDefault();
152158

153159
if (!checkPasswords()) {
@@ -202,24 +208,81 @@ export function User() {
202208
});
203209
if (resp.status === 200) {
204210
logout(true);
205-
handleClose();
211+
handleUpdatePasswordClose();
206212
}
207213
};
208214

215+
const submitDeleteUser = async (e: SubmitEvent) => {
216+
e.preventDefault();
217+
218+
const t = i18n.t;
219+
220+
const loginSaltBs64 = window.localStorage.getItem("LoginKey");
221+
const loginSalt = Base64.toUint8Array(loginSaltBs64);
222+
const loginKey = await generate_hash(deleteUser.password, loginSalt)
223+
224+
const resp = await fetch(BACKEND + "/user/delete", {
225+
credentials: "include",
226+
method: "DELETE",
227+
headers: {
228+
"Content-Type": "application/json"
229+
},
230+
body: JSON.stringify({login_key: [].slice.call(loginKey)})
231+
});
232+
233+
if (resp.status === 200) {
234+
location.reload();
235+
} else if (resp.status === 400) {
236+
setDeleteUser({...deleteUser, password_valid: false})
237+
} else {
238+
showAlert(`${t("alert_default_text")}: ${resp.status} ${await resp.text()}`, "danger")
239+
handleDelteUserClose();
240+
}
241+
}
242+
209243
const {t} = useTranslation("", {useSuspense: false, keyPrefix: "user"});
210244

211245
return (<>
212246
<Container fluid>
213247
<Card className="p-3 my-3">
214248
<UserComponent/>
215-
<Button variant="primary" className="col col-sm-6 col-md-4 col-lg-3 col-xl-2" onClick={handleShow}>
249+
<Button variant="primary" className="col col-sm-6 col-md-4 col-lg-3 col-xl-2 mb-3" onClick={handleUpdatePasswordShow}>
216250
{t("change_password")}
217251
</Button>
252+
<Button variant="danger" className="col col-sm-6 col-md-4 col-lg-3 col-xl-2" onClick={handleDeleteUserShow}>
253+
{t("delete_user")}
254+
</Button>
218255
</Card>
219256
</Container>
220257

221-
<Modal show={show} onHide={handleClose} centered>
222-
<Form onSubmit={submit} validated={validated.value} noValidate>
258+
{/* Delete user modal */}
259+
<Modal show={deleteUser.show} onHide={handleDelteUserClose} centered>
260+
<Form onSubmit={submitDeleteUser} validated={validated.value} noValidate>
261+
<Modal.Header>
262+
<Modal.Title>
263+
{t("delete_user")}
264+
</Modal.Title>
265+
</Modal.Header>
266+
<Modal.Body>
267+
<Form.Group className="pb-3" controlId="deleteUserPassword">
268+
<Form.Label>{t("password")}</Form.Label>
269+
<PasswordComponent onChange={(e) => setDeleteUser({...deleteUser, password: (e.target as HTMLInputElement).value})} isInvalid={!deleteUser.password_valid} invalidMessage={t("password_invalid")} />
270+
</Form.Group>
271+
</Modal.Body>
272+
<Modal.Footer>
273+
<Button variant="secondary" onClick={handleDelteUserClose}>
274+
{t("close")}
275+
</Button>
276+
<Button variant="danger" type="submit">
277+
{t("delete_user")}
278+
</Button>
279+
</Modal.Footer>
280+
</Form>
281+
</Modal>
282+
283+
{/* Reset password modal */}
284+
<Modal show={showPasswordReset} onHide={handleUpdatePasswordClose} centered>
285+
<Form onSubmit={submitUpdatePassword} validated={validated.value} noValidate>
223286
<Modal.Header>
224287
<Modal.Title>
225288
{t("change_password")}
@@ -238,7 +301,7 @@ export function User() {
238301
</Form.Group>
239302
</Modal.Body>
240303
<Modal.Footer>
241-
<Button variant="secondary" onClick={handleClose}>
304+
<Button variant="secondary" onClick={handleUpdatePasswordClose}>
242305
{t("close")}
243306
</Button>
244307
<Button variant="primary" type="submit">

0 commit comments

Comments
 (0)