GeneIT/geneit_app/src/routes/ProfileRoute.tsx

298 lines
8.2 KiB
TypeScript
Raw Normal View History

2023-06-14 12:14:46 +00:00
import {
Alert,
Box,
Button,
Card,
CardActions,
CardContent,
Checkbox,
FormControlLabel,
TextField,
Typography,
} from "@mui/material";
2023-06-14 13:30:16 +00:00
import React, { useRef } from "react";
2023-06-14 12:14:46 +00:00
import { ServerApi } from "../api/ServerApi";
2023-06-14 13:30:16 +00:00
import { ReplacePasswordResponse, User, UserApi } from "../api/UserApi";
import { AsyncWidget } from "../widgets/AsyncWidget";
2023-06-14 13:23:23 +00:00
import { PasswordInput } from "../widgets/PasswordInput";
2023-06-14 13:30:16 +00:00
import { formatDate } from "../widgets/TimeWidget";
2023-06-14 14:12:09 +00:00
import { useConfirm } from "../widgets/ConfirmDialogProvider";
import { useAlert } from "../widgets/AlertDialogProvider";
2023-06-13 14:16:07 +00:00
export function ProfileRoute(): React.ReactElement {
const [user, setUser] = React.useState<null | User>(null);
const load = async () => {
2023-06-14 12:14:46 +00:00
const u = await UserApi.GetUserInfo();
setUser(u);
2023-06-13 14:16:07 +00:00
};
const counter = useRef(0);
2023-06-14 13:23:23 +00:00
return (
<AsyncWidget
loadKey={counter.current}
load={load}
errMsg="Echec du chargement des informations du compte utilisateur !"
build={() => (
<div style={{ maxWidth: "500px", margin: "auto" }}>
<Typography variant="h3">Profil</Typography>
<ProfileSettingsCard
user={user!}
onUpdate={() => (counter.current += 1)}
/>
{user?.has_password && <ChangePasswordCard />}
2023-06-14 14:12:09 +00:00
<DeleteAccountButton />
2023-06-14 13:23:23 +00:00
</div>
)}
/>
);
}
function ProfileSettingsCard(p: { user: User; onUpdate: () => {} }) {
const [newName, setNewName] = React.useState(p.user.name);
const [error, setError] = React.useState<string | null>(null);
const [success, setSuccess] = React.useState<string | null>(null);
2023-06-14 12:14:46 +00:00
const updateProfile = async () => {
try {
setSuccess(null);
setError(null);
await UserApi.UpdateProfile(newName);
2023-06-14 13:23:23 +00:00
p.onUpdate();
setSuccess("Informations du profil enregistrées avec succès !");
2023-06-14 12:14:46 +00:00
} catch (e) {
console.error(e);
setError("Echec de la mise à jour du profil !");
}
};
2023-06-13 14:16:07 +00:00
return (
2023-06-14 13:23:23 +00:00
<>
<Card style={{ marginTop: "10px" }}>
{error && <Alert severity="error">{error}</Alert>}
{success && <Alert severity="success">{success}</Alert>}
2023-06-14 12:14:46 +00:00
2023-06-14 13:23:23 +00:00
<CardContent>
<Typography gutterBottom variant="h5" component="div">
Paramètres du compte
</Typography>
<Box
component="form"
sx={{
"& .MuiTextField-root": { my: 1 },
}}
noValidate
autoComplete="off"
>
<TextField
disabled
fullWidth
label="Identifiant"
value={p.user.id}
/>
<TextField
disabled
fullWidth
label="Création du compte"
value={formatDate(p.user.time_create)}
/>
<TextField
disabled
fullWidth
label="Activation du compte"
value={formatDate(p.user.time_activate)}
/>
<TextField
disabled
fullWidth
label="Adresse mail"
value={p.user.email}
/>
<TextField
fullWidth
label="Nom d'utilisateur"
value={newName}
onChange={(e) => setNewName(e.target.value)}
inputProps={{
maxLength: ServerApi.Config.constraints.user_name_len.max,
}}
/>
<FormControlLabel
disabled
control={<Checkbox checked={p.user.admin} />}
label="Compte administrateur"
/>
</Box>
</CardContent>
<CardActions>
<Button onClick={updateProfile} style={{ marginLeft: "auto" }}>
Enregistrer
</Button>
</CardActions>
</Card>
</>
);
}
function ChangePasswordCard(): React.ReactElement {
const [loading, setLoading] = React.useState(false);
const [error, setError] = React.useState<string | null>(null);
const [success, setSuccess] = React.useState<string | null>(null);
const [oldPassword, setOldpassword] = React.useState("");
const [newPassword, setNewpassword] = React.useState("");
const [confirmNewPassword, setConfirmNewpassword] = React.useState("");
const isValid =
ServerApi.CheckPassword(newPassword) === null &&
oldPassword.length > 0 &&
confirmNewPassword === newPassword;
const updatePassword = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!isValid || loading) return;
setLoading(true);
setSuccess(null);
setError(null);
try {
const result = await UserApi.ReplacePassword(oldPassword, newPassword);
switch (result) {
case ReplacePasswordResponse.Error:
setError("Echec du changement de mot de passe !");
break;
case ReplacePasswordResponse.Success:
setSuccess("Mot de passe changé avec succès !");
break;
case ReplacePasswordResponse.InvalidOldPassword:
setError("Ancien mot de passe saisi invalide !");
break;
case ReplacePasswordResponse.InvalidNewPassword:
setError("Nouveau mot de passe saisi invalide !");
break;
case ReplacePasswordResponse.TooManyRequests:
setError(
"Trop de tentatives de changement de mot de passe, veuillez réessayer ultérieurement !"
);
break;
}
} catch (e) {
console.error(e);
setError("Echec de la mise à jour du mot de passe !");
}
setLoading(false);
};
return (
<>
<Card style={{ marginTop: "10px" }}>
{error && <Alert severity="error">{error}</Alert>}
{success && <Alert severity="success">{success}</Alert>}
<Box
component="form"
sx={{
"& .MuiTextField-root": { my: 1 },
}}
noValidate
autoComplete="off"
onSubmit={updatePassword}
>
<CardContent>
<Typography gutterBottom variant="h5" component="div">
Changement du mot de passe
</Typography>
<TextField
fullWidth
label="Mot de passe actuel"
value={oldPassword}
type="password"
onChange={(e) => setOldpassword(e.target.value)}
/>
<PasswordInput
value={newPassword}
onChange={(n) => setNewpassword(n)}
label={"Nouveau mot de passe"}
/>
<TextField
fullWidth
error={
confirmNewPassword !== "" && confirmNewPassword !== newPassword
}
helperText={
confirmNewPassword !== newPassword
? "Le nouveau mot de passe et sa confirmation doivent être identiques !"
: ""
}
label="Confirmation du nouveau mot de passe"
value={confirmNewPassword}
type="password"
onChange={(e) => setConfirmNewpassword(e.target.value)}
/>
</CardContent>
<CardActions>
<Button
disabled={!isValid && !loading}
type="submit"
style={{ marginLeft: "auto" }}
>
Enregistrer
</Button>
</CardActions>{" "}
</Box>
</Card>
</>
2023-06-13 14:16:07 +00:00
);
}
2023-06-14 14:12:09 +00:00
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 (
<div style={{ textAlign: "center" }}>
<Button onClick={requestDelete} color="error">
Supprimer mon compte
</Button>
</div>
);
}