GeneIT/geneit_app/src/routes/ProfileRoute.tsx

284 lines
7.8 KiB
TypeScript

import {
Alert,
Box,
Button,
Card,
CardActions,
CardContent,
Checkbox,
FormControlLabel,
TextField,
Typography,
} from "@mui/material";
import React from "react";
import { ServerApi } from "../api/ServerApi";
import { ReplacePasswordResponse, User, UserApi } from "../api/UserApi";
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
import { useUser } from "../widgets/BaseAuthenticatedPage";
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
import { PasswordInput } from "../widgets/PasswordInput";
import { formatDate } from "../widgets/TimeWidget";
export function ProfileRoute(): React.ReactElement {
const user = useUser();
return (
<div style={{ maxWidth: "500px", margin: "auto" }}>
<Typography variant="h3">Profil</Typography>
<ProfileSettingsCard
user={user.user}
onUpdate={() => user.reloadUserInfo()}
/>
{user.user.has_password && <ChangePasswordCard />}
<DeleteAccountButton />
</div>
);
}
function ProfileSettingsCard(p: { user: User; onUpdate: () => void }) {
const [newName, setNewName] = React.useState(p.user.name);
const [error, setError] = React.useState<string | null>(null);
const [success, setSuccess] = React.useState<string | null>(null);
const updateProfile = async () => {
try {
setSuccess(null);
setError(null);
await UserApi.UpdateProfile(newName);
p.onUpdate();
setSuccess("Informations du profil enregistrées avec succès !");
} catch (e) {
console.error(e);
setError("Echec de la mise à jour du profil !");
}
};
return (
<>
<Card style={{ marginTop: "10px" }}>
{error && <Alert severity="error">{error}</Alert>}
{success && <Alert severity="success">{success}</Alert>}
<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>
</>
);
}
function DeleteAccountButton(): React.ReactElement {
const alert = useAlert();
const confirm = useConfirm();
const requestDelete = async () => {
try {
if (
!(await confirm(
"Voulez-vous initier la suppression de votre compte ?",
"Suppression de compte"
))
)
return;
await UserApi.RequestAccountDeletion();
await alert(
"Demande de suppression de compte enregistrée avec succès. Veuillez consulter votre boîte mail."
);
} catch (e) {
console.error(e);
alert("Echec de la demande de suppression de compte !");
}
};
return (
<div style={{ textAlign: "center", margin: "15px 0px" }}>
<Button onClick={requestDelete} color="error">
Supprimer mon compte
</Button>
</div>
);
}