Skip to content

Commit

Permalink
frontend: add button to delete account to user page.
Browse files Browse the repository at this point in the history
  • Loading branch information
ffreddow committed Oct 15, 2024
1 parent df4df17 commit 45fbbd7
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 12 deletions.
5 changes: 4 additions & 1 deletion frontend/public/locales/de-DE/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
"current_password_error_message": "Darf nicht leer sein.",
"new_password": "Neues Passwort",
"new_password_error_message": "Muss mindestens 8 Zeichen lang sein und jeweils mindestens einen Klein- und Großbuchstaben sowie ein Sonderzeichen enthalten.",
"close": "Schließen"
"close": "Schließen",
"delete_user": "Account löschen",
"password": "Passwort",
"password_invalid": "Passwort ist falsch"
},
"recovery": {
"recovery": "Passwort zurücksetzen",
Expand Down
5 changes: 4 additions & 1 deletion frontend/public/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
"current_password_error_message": "Darf nicht leer sein.",
"new_password": "Neues Passwort",
"new_password_error_message": "Muss mindestens 8 Zeichen lang sein und jeweils mindestens einen Klein- und Großbuchstaben sowie ein Sonderzeichen enthalten.",
"close": "Schließen"
"close": "Schließen",
"delete_user": "Account löschen",
"password": "Passwort",
"password_invalid": "Passwort ist falsch"
},
"recovery": {
"recovery": "Passwort zurücksetzen",
Expand Down
5 changes: 4 additions & 1 deletion frontend/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
"current_password_error_message": "Must not be empty.",
"new_password": "New password",
"new_password_error_message": "Must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters",
"close": "Close"
"close": "Close",
"delete_user": "Delete account",
"password": "Password",
"password_invalid": "Password is wrong"
},
"recovery": {
"recovery": "Password recovery",
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ export class Login extends Component<{}, LoginState> {
return;
}

const loginSaltBs64 = Base64.fromUint8Array(login_salt);
window.localStorage.setItem("LoginKey", loginSaltBs64);

const login_key = await generate_hash(this.state.password, login_salt);

const login_schema: LoginSchema = {
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ async function refresh_access_token() {
credentials: "include"
});

if (!localStorage.getItem("loginKey") || !localStorage.getItem("secret_key")) {
loggedIn.value = AppState.LoggedOut
}

if (resp.status == 200) {
loggedIn.value = AppState.LoggedIn;
} else {
Expand Down
81 changes: 72 additions & 9 deletions frontend/src/pages/user.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ import { useTranslation } from "react-i18next";
import { Card, Container } from "react-bootstrap";
import { signal } from "@preact/signals";
import { PasswordComponent } from "../components/password_component";
import i18n from "../i18n";
import { showAlert } from "../components/Alert";
import { Base64 } from "js-base64";


interface UserState {
Expand Down Expand Up @@ -116,15 +119,18 @@ class UserComponent extends Component<{}, State> {
}

export function User() {
const [show, setShow] = useState(false);
const [showPasswordReset, setShowPasswordReset] = useState(false);
const [deleteUser, setDeleteUser] = useState({show: false, password: "", password_valid: true});
const [currentPassword, setCurrentPassword] = useState("");
const [currentPasswordIsValid, setCurrentPasswordIsValid] = useState(true);
const [newPassword, setNewPassword] = useState("");
const [newPasswordIsValid, setNewPasswordIsValid] = useState(true);
const validated = signal(false);

const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const handleUpdatePasswordClose = () => setShowPasswordReset(false);
const handleUpdatePasswordShow = () => setShowPasswordReset(true);
const handleDelteUserClose = () => setDeleteUser({...deleteUser, show: false});
const handleDeleteUserShow = () => setDeleteUser({...deleteUser, show: true});

const checkPasswords = () => {
let ret = true;
Expand All @@ -147,7 +153,7 @@ export function User() {
return ret;
}

const submit = async (e: SubmitEvent) => {
const submitUpdatePassword = async (e: SubmitEvent) => {
e.preventDefault();

if (!checkPasswords()) {
Expand Down Expand Up @@ -202,24 +208,81 @@ export function User() {
});
if (resp.status === 200) {
logout(true);
handleClose();
handleUpdatePasswordClose();
}
};

const submitDeleteUser = async (e: SubmitEvent) => {
e.preventDefault();

const t = i18n.t;

const loginSaltBs64 = window.localStorage.getItem("LoginKey");
const loginSalt = Base64.toUint8Array(loginSaltBs64);
const loginKey = await generate_hash(deleteUser.password, loginSalt)

const resp = await fetch(BACKEND + "/user/delete", {
credentials: "include",
method: "DELETE",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({login_key: [].slice.call(loginKey)})
});

if (resp.status === 200) {
location.reload();
} else if (resp.status === 400) {
setDeleteUser({...deleteUser, password_valid: false})
} else {
showAlert(`${t("alert_default_text")}: ${resp.status} ${await resp.text()}`, "danger")
handleDelteUserClose();
}
}

const {t} = useTranslation("", {useSuspense: false, keyPrefix: "user"});

return (<>
<Container fluid>
<Card className="p-3 my-3">
<UserComponent/>
<Button variant="primary" className="col col-sm-6 col-md-4 col-lg-3 col-xl-2" onClick={handleShow}>
<Button variant="primary" className="col col-sm-6 col-md-4 col-lg-3 col-xl-2 mb-3" onClick={handleUpdatePasswordShow}>
{t("change_password")}
</Button>
<Button variant="danger" className="col col-sm-6 col-md-4 col-lg-3 col-xl-2" onClick={handleDeleteUserShow}>
{t("delete_user")}
</Button>
</Card>
</Container>

<Modal show={show} onHide={handleClose} centered>
<Form onSubmit={submit} validated={validated.value} noValidate>
{/* Delete user modal */}
<Modal show={deleteUser.show} onHide={handleDelteUserClose} centered>
<Form onSubmit={submitDeleteUser} validated={validated.value} noValidate>
<Modal.Header>
<Modal.Title>
{t("delete_user")}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form.Group className="pb-3" controlId="deleteUserPassword">
<Form.Label>{t("password")}</Form.Label>
<PasswordComponent onChange={(e) => setDeleteUser({...deleteUser, password: (e.target as HTMLInputElement).value})} isInvalid={!deleteUser.password_valid} invalidMessage={t("password_invalid")} />
</Form.Group>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleDelteUserClose}>
{t("close")}
</Button>
<Button variant="danger" type="submit">
{t("delete_user")}
</Button>
</Modal.Footer>
</Form>
</Modal>

{/* Reset password modal */}
<Modal show={showPasswordReset} onHide={handleUpdatePasswordClose} centered>
<Form onSubmit={submitUpdatePassword} validated={validated.value} noValidate>
<Modal.Header>
<Modal.Title>
{t("change_password")}
Expand All @@ -238,7 +301,7 @@ export function User() {
</Form.Group>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
<Button variant="secondary" onClick={handleUpdatePasswordClose}>
{t("close")}
</Button>
<Button variant="primary" type="submit">
Expand Down

0 comments on commit 45fbbd7

Please sign in to comment.