From 10e5c124fd3c0d8e2d7f247da3edaa051c154904 Mon Sep 17 00:00:00 2001 From: Pierre Hubert Date: Wed, 14 Jun 2023 16:12:09 +0200 Subject: [PATCH] Can request account deletion --- geneit_app/src/api/UserApi.ts | 10 ++ geneit_app/src/index.tsx | 12 ++- geneit_app/src/routes/ProfileRoute.tsx | 37 ++++++++ .../src/widgets/AlertDialogProvider.tsx | 77 ++++++++++++++++ .../src/widgets/ConfirmDialogProvider.tsx | 92 +++++++++++++++++++ 5 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 geneit_app/src/widgets/AlertDialogProvider.tsx create mode 100644 geneit_app/src/widgets/ConfirmDialogProvider.tsx diff --git a/geneit_app/src/api/UserApi.ts b/geneit_app/src/api/UserApi.ts index 204f3e5..cd1e557 100644 --- a/geneit_app/src/api/UserApi.ts +++ b/geneit_app/src/api/UserApi.ts @@ -79,4 +79,14 @@ export class UserApi { return ReplacePasswordResponse.Error; } } + + /** + * Request account deletion + */ + static async RequestAccountDeletion(): Promise { + await APIClient.exec({ + uri: "/user/request_delete", + method: "GET", + }); + } } diff --git a/geneit_app/src/index.tsx b/geneit_app/src/index.tsx index c6a460c..3d41de4 100644 --- a/geneit_app/src/index.tsx +++ b/geneit_app/src/index.tsx @@ -11,6 +11,8 @@ import "@fontsource/roboto/400.css"; import "@fontsource/roboto/500.css"; import "@fontsource/roboto/700.css"; import { BrowserRouter } from "react-router-dom"; +import { ConfirmDialogProvider } from "./widgets/ConfirmDialogProvider"; +import { AlertDialogProvider } from "./widgets/AlertDialogProvider"; async function init() { try { @@ -23,9 +25,13 @@ async function init() { root.render( -
- -
+ + +
+ +
+
+
); diff --git a/geneit_app/src/routes/ProfileRoute.tsx b/geneit_app/src/routes/ProfileRoute.tsx index de17be7..9094ecd 100644 --- a/geneit_app/src/routes/ProfileRoute.tsx +++ b/geneit_app/src/routes/ProfileRoute.tsx @@ -16,6 +16,8 @@ import { ReplacePasswordResponse, User, UserApi } from "../api/UserApi"; import { AsyncWidget } from "../widgets/AsyncWidget"; import { PasswordInput } from "../widgets/PasswordInput"; import { formatDate } from "../widgets/TimeWidget"; +import { useConfirm } from "../widgets/ConfirmDialogProvider"; +import { useAlert } from "../widgets/AlertDialogProvider"; export function ProfileRoute(): React.ReactElement { const [user, setUser] = React.useState(null); @@ -41,6 +43,7 @@ export function ProfileRoute(): React.ReactElement { onUpdate={() => (counter.current += 1)} /> {user?.has_password && } + )} /> @@ -258,3 +261,37 @@ function ChangePasswordCard(): React.ReactElement { ); } + +function DeleteAccountButton(): React.ReactElement { + const alert = useAlert(); + const confirm = useConfirm(); + + const requestDelete = async () => { + try { + if ( + !(await confirm.confirm( + "Voulez-vous initier la suppression de votre compte ?", + "Suppression de compte" + )) + ) + return; + + await UserApi.RequestAccountDeletion(); + + await alert.alert( + "Demande de suppression de compte enregistrée avec succès. Veuillez consulter votre boîte mail." + ); + } catch (e) { + console.error(e); + alert.alert("Echec de la demande de suppression de compte !"); + } + }; + + return ( +
+ +
+ ); +} diff --git a/geneit_app/src/widgets/AlertDialogProvider.tsx b/geneit_app/src/widgets/AlertDialogProvider.tsx new file mode 100644 index 0000000..0bb2aea --- /dev/null +++ b/geneit_app/src/widgets/AlertDialogProvider.tsx @@ -0,0 +1,77 @@ +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, +} from "@mui/material"; +import React, { + PropsWithChildren, + createContext, + useContext, + useRef, +} from "react"; + +interface AlertHook { + alert: (message: string, title?: string) => Promise; +} + +const AlertContext = createContext(null); + +export function AlertDialogProvider(p: PropsWithChildren): React.ReactElement { + const [open, setOpen] = React.useState(false); + + const [title, setTitle] = React.useState(undefined); + const [message, setMessage] = React.useState(""); + + const cb = React.useRef void)>(null); + + const handleClose = () => { + setOpen(false); + + if (cb.current !== null) cb.current(); + cb.current = null; + }; + + const hook: AlertHook = { + alert: (message, title) => { + setTitle(title); + setMessage(message); + setOpen(true); + + return new Promise((res) => { + cb.current = res; + }); + }, + }; + + return ( + <> + {p.children} + + + {title && {title}} + + + {message} + + + + + + + + ); +} + +export function useAlert(): AlertHook { + return useContext(AlertContext)!; +} diff --git a/geneit_app/src/widgets/ConfirmDialogProvider.tsx b/geneit_app/src/widgets/ConfirmDialogProvider.tsx new file mode 100644 index 0000000..725d444 --- /dev/null +++ b/geneit_app/src/widgets/ConfirmDialogProvider.tsx @@ -0,0 +1,92 @@ +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, +} from "@mui/material"; +import React, { + PropsWithChildren, + createContext, + useContext, + useRef, +} from "react"; + +interface ConfirmHook { + confirm: ( + message: string, + title?: string, + confirmButton?: string + ) => Promise; +} + +const ConfirmContext = createContext(null); + +export function ConfirmDialogProvider( + p: PropsWithChildren +): React.ReactElement { + const [open, setOpen] = React.useState(false); + + const [title, setTitle] = React.useState(undefined); + const [message, setMessage] = React.useState(""); + const [confirmButton, setConfirmButton] = React.useState( + undefined + ); + + const cb = React.useRef void)>(null); + + const handleClose = (confirm: boolean) => { + setOpen(false); + + if (cb.current !== null) cb.current(confirm); + cb.current = null; + }; + + const hook: ConfirmHook = { + confirm: (message, title, confirmButton) => { + setTitle(title); + setMessage(message); + setConfirmButton(confirmButton); + setOpen(true); + + return new Promise((res) => { + cb.current = res; + }); + }, + }; + + return ( + <> + + {p.children} + + + handleClose(false)} + aria-labelledby="alert-dialog-title" + aria-describedby="alert-dialog-description" + > + {title && {title}} + + + {message} + + + + + + + + + ); +} + +export function useConfirm(): ConfirmHook { + return useContext(ConfirmContext)!; +}