Can update profile information
This commit is contained in:
parent
b64bc8fb6d
commit
e3bec527f0
11
geneit_app/package-lock.json
generated
11
geneit_app/package-lock.json
generated
@ -22,6 +22,7 @@
|
|||||||
"@types/node": "^16.18.34",
|
"@types/node": "^16.18.34",
|
||||||
"@types/react": "^18.2.8",
|
"@types/react": "^18.2.8",
|
||||||
"@types/react-dom": "^18.2.4",
|
"@types/react-dom": "^18.2.4",
|
||||||
|
"date-and-time": "^3.0.1",
|
||||||
"jotai": "^2.1.1",
|
"jotai": "^2.1.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
@ -6846,6 +6847,11 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/date-and-time": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-Az1hy3IPuh7LR4duPGlgkUzZXtjoWH8pd+XVLpLXMNd+DD48sRdcsWIPbqdHCXg4izb9lPzrKtqUXPXevS9g4Q=="
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
@ -22546,6 +22552,11 @@
|
|||||||
"whatwg-url": "^8.0.0"
|
"whatwg-url": "^8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"date-and-time": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-Az1hy3IPuh7LR4duPGlgkUzZXtjoWH8pd+XVLpLXMNd+DD48sRdcsWIPbqdHCXg4izb9lPzrKtqUXPXevS9g4Q=="
|
||||||
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"@types/node": "^16.18.34",
|
"@types/node": "^16.18.34",
|
||||||
"@types/react": "^18.2.8",
|
"@types/react": "^18.2.8",
|
||||||
"@types/react-dom": "^18.2.4",
|
"@types/react-dom": "^18.2.4",
|
||||||
|
"date-and-time": "^3.0.1",
|
||||||
"jotai": "^2.1.1",
|
"jotai": "^2.1.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
@ -47,8 +47,7 @@ export class APIClient {
|
|||||||
// Handle expired tokens
|
// Handle expired tokens
|
||||||
if (res.status === 412) {
|
if (res.status === 412) {
|
||||||
AuthApi.RemoveAuthToken();
|
AuthApi.RemoveAuthToken();
|
||||||
// eslint-disable-next-line no-self-assign
|
window.location.href = "/";
|
||||||
window.location.href = window.location.href;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args.allowFail && !res.ok)
|
if (!args.allowFail && !res.ok)
|
||||||
|
@ -23,4 +23,17 @@ export class UserApi {
|
|||||||
})
|
})
|
||||||
).data;
|
).data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update user profile
|
||||||
|
*/
|
||||||
|
static async UpdateProfile(name: string): Promise<void> {
|
||||||
|
await APIClient.exec({
|
||||||
|
uri: "/user/update_profile",
|
||||||
|
method: "POST",
|
||||||
|
jsonData: {
|
||||||
|
name: name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,129 @@
|
|||||||
import React, { useRef } from "react";
|
import React, { useRef } from "react";
|
||||||
import { AsyncWidget } from "../widgets/AsyncWidget";
|
import { AsyncWidget } from "../widgets/AsyncWidget";
|
||||||
import { User, UserApi } from "../api/UserApi";
|
import { User, UserApi } from "../api/UserApi";
|
||||||
|
import {
|
||||||
|
Alert,
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
CardActions,
|
||||||
|
CardContent,
|
||||||
|
Checkbox,
|
||||||
|
FormControlLabel,
|
||||||
|
TextField,
|
||||||
|
Typography,
|
||||||
|
} from "@mui/material";
|
||||||
|
import { TimeWidget, formatDate } from "../widgets/TimeWidget";
|
||||||
|
import { ServerApi } from "../api/ServerApi";
|
||||||
|
|
||||||
export function ProfileRoute(): React.ReactElement {
|
export function ProfileRoute(): React.ReactElement {
|
||||||
const [user, setUser] = React.useState<null | User>(null);
|
const [user, setUser] = React.useState<null | User>(null);
|
||||||
|
const [newName, setNewName] = React.useState("");
|
||||||
|
|
||||||
|
const [error, setError] = React.useState<string | null>(null);
|
||||||
|
const [success, setSuccess] = React.useState<string | null>(null);
|
||||||
|
|
||||||
const load = async () => {
|
const load = async () => {
|
||||||
setUser(await UserApi.GetUserInfo());
|
const u = await UserApi.GetUserInfo();
|
||||||
|
setUser(u);
|
||||||
|
setNewName(u.name);
|
||||||
};
|
};
|
||||||
|
|
||||||
const counter = useRef(0);
|
const counter = useRef(0);
|
||||||
|
|
||||||
|
const updateProfile = async () => {
|
||||||
|
try {
|
||||||
|
setSuccess(null);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
await UserApi.UpdateProfile(newName);
|
||||||
|
|
||||||
|
counter.current += 1;
|
||||||
|
setSuccess("Informations du profil mises à jour avec succès !");
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
setError("Echec de la mise à jour du profil !");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncWidget
|
<AsyncWidget
|
||||||
loadKey={counter.current}
|
loadKey={counter.current}
|
||||||
load={load}
|
load={load}
|
||||||
errMsg="Echec du chargement des informations du compte utilisateur !"
|
errMsg="Echec du chargement des informations du compte utilisateur !"
|
||||||
build={() => (
|
build={() => (
|
||||||
<>
|
<div style={{ maxWidth: "500px", margin: "auto" }}>
|
||||||
<p>ready !!! {user!.name}</p>
|
<Typography variant="h3">Profil</Typography>
|
||||||
</>
|
|
||||||
|
{error && <Alert severity="error">{error}</Alert>}
|
||||||
|
{success && <Alert severity="success">{success}</Alert>}
|
||||||
|
|
||||||
|
<Card style={{ marginTop: "10px" }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography gutterBottom variant="h5" component="div">
|
||||||
|
Paramètres du compte
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
component="form"
|
||||||
|
sx={{
|
||||||
|
"& .MuiTextField-root": { m: 1 },
|
||||||
|
}}
|
||||||
|
noValidate
|
||||||
|
autoComplete="off"
|
||||||
|
>
|
||||||
|
<TextField
|
||||||
|
disabled
|
||||||
|
fullWidth
|
||||||
|
label="Identifiant"
|
||||||
|
value={user?.id}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
disabled
|
||||||
|
fullWidth
|
||||||
|
label="Création du compte"
|
||||||
|
value={formatDate(user!.time_create)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
disabled
|
||||||
|
fullWidth
|
||||||
|
label="Activation du compte"
|
||||||
|
value={formatDate(user!.time_activate)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
disabled
|
||||||
|
fullWidth
|
||||||
|
label="Adresse mail"
|
||||||
|
value={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={user!.admin} />}
|
||||||
|
label="Compte administrateur"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
<CardActions>
|
||||||
|
<Button onClick={updateProfile} style={{ marginLeft: "auto" }}>
|
||||||
|
Enregistrer
|
||||||
|
</Button>
|
||||||
|
</CardActions>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
63
geneit_app/src/widgets/TimeWidget.tsx
Normal file
63
geneit_app/src/widgets/TimeWidget.tsx
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { Tooltip } from "@mui/material";
|
||||||
|
import date from "date-and-time";
|
||||||
|
|
||||||
|
export function formatDate(time: number): string {
|
||||||
|
const t = new Date();
|
||||||
|
t.setTime(1000 * time);
|
||||||
|
return date.format(t, "DD/MM/YYYY HH:mm:ss");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function timeDiff(a: number, b: number): string {
|
||||||
|
let diff = b - a;
|
||||||
|
|
||||||
|
if (diff === 0) return "maintenant";
|
||||||
|
if (diff === 1) return "1 seconde";
|
||||||
|
|
||||||
|
if (diff < 60) {
|
||||||
|
return `${diff} secondes`;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = Math.floor(diff / 60);
|
||||||
|
|
||||||
|
if (diff === 1) return "1 minute";
|
||||||
|
if (diff < 24) {
|
||||||
|
return `${diff} minutes`;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = Math.floor(diff / 60);
|
||||||
|
|
||||||
|
if (diff === 1) return "1 heure";
|
||||||
|
if (diff < 24) {
|
||||||
|
return `${diff} heures`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const diffDays = Math.floor(diff / 24);
|
||||||
|
|
||||||
|
if (diffDays === 1) return "1 jour";
|
||||||
|
if (diffDays < 31) {
|
||||||
|
return `${diffDays} jours`;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = Math.floor(diffDays / 31);
|
||||||
|
|
||||||
|
if (diff < 12) {
|
||||||
|
return `${diff} mois`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const diffYears = Math.floor(diffDays / 365);
|
||||||
|
|
||||||
|
if (diffYears === 1) return "1 an";
|
||||||
|
return `${diffYears} ans`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function timeDiffFromNow(time: number): string {
|
||||||
|
return timeDiff(time, Math.floor(new Date().getTime() / 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TimeWidget(p: { time: number }): React.ReactElement {
|
||||||
|
return (
|
||||||
|
<Tooltip title={formatDate(p.time)}>
|
||||||
|
<span>{timeDiffFromNow(p.time)}</span>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user