Provide user info in context

This commit is contained in:
Pierre HUBERT 2023-06-15 08:52:04 +02:00
parent 1934354665
commit fc58e65ea1
2 changed files with 89 additions and 85 deletions

View File

@ -10,47 +10,33 @@ import {
TextField, TextField,
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import React, { useRef } from "react"; import React from "react";
import { ServerApi } from "../api/ServerApi"; import { ServerApi } from "../api/ServerApi";
import { ReplacePasswordResponse, User, UserApi } from "../api/UserApi"; import { ReplacePasswordResponse, User, UserApi } from "../api/UserApi";
import { AsyncWidget } from "../widgets/AsyncWidget"; import { useAlert } from "../widgets/AlertDialogProvider";
import { useUser } from "../widgets/BaseAuthenticatedPage";
import { useConfirm } from "../widgets/ConfirmDialogProvider";
import { PasswordInput } from "../widgets/PasswordInput"; import { PasswordInput } from "../widgets/PasswordInput";
import { formatDate } from "../widgets/TimeWidget"; import { formatDate } from "../widgets/TimeWidget";
import { useConfirm } from "../widgets/ConfirmDialogProvider";
import { useAlert } from "../widgets/AlertDialogProvider";
export function ProfileRoute(): React.ReactElement { export function ProfileRoute(): React.ReactElement {
const [user, setUser] = React.useState<null | User>(null); const user = useUser();
const load = async () => {
const u = await UserApi.GetUserInfo();
setUser(u);
};
const counter = useRef(0);
return ( return (
<AsyncWidget <div style={{ maxWidth: "500px", margin: "auto" }}>
loadKey={counter.current} <Typography variant="h3">Profil</Typography>
load={load}
errMsg="Echec du chargement des informations du compte utilisateur !"
build={() => (
<div style={{ maxWidth: "500px", margin: "auto" }}>
<Typography variant="h3">Profil</Typography>
<ProfileSettingsCard <ProfileSettingsCard
user={user!} user={user.user}
onUpdate={() => (counter.current += 1)} onUpdate={() => user.reloadUserInfo()}
/> />
{user?.has_password && <ChangePasswordCard />} {user.user.has_password && <ChangePasswordCard />}
<DeleteAccountButton /> <DeleteAccountButton />
</div> </div>
)}
/>
); );
} }
function ProfileSettingsCard(p: { user: User; onUpdate: () => {} }) { function ProfileSettingsCard(p: { user: User; onUpdate: () => void }) {
const [newName, setNewName] = React.useState(p.user.name); const [newName, setNewName] = React.useState(p.user.name);
const [error, setError] = React.useState<string | null>(null); const [error, setError] = React.useState<string | null>(null);

View File

@ -15,6 +15,13 @@ import { User, UserApi } from "../api/UserApi";
import { AsyncWidget } from "./AsyncWidget"; import { AsyncWidget } from "./AsyncWidget";
import { RouterLink } from "./RouterLink"; import { RouterLink } from "./RouterLink";
interface UserContext {
user: User;
reloadUserInfo: () => void;
}
const UserContextK = React.createContext<UserContext | null>(null);
export function BaseAuthenticatedPage(): React.ReactElement { export function BaseAuthenticatedPage(): React.ReactElement {
const [user, setUser] = React.useState<null | User>(null); const [user, setUser] = React.useState<null | User>(null);
@ -48,69 +55,80 @@ export function BaseAuthenticatedPage(): React.ReactElement {
load={load} load={load}
errMsg="Echec du chargement des informations utilisateur !" errMsg="Echec du chargement des informations utilisateur !"
build={() => ( build={() => (
<div <UserContextK.Provider
style={{ value={{
minHeight: "100vh", user: user!,
display: "flex", reloadUserInfo: load,
flexDirection: "column",
}} }}
> >
<AppBar position="sticky"> <div
<Toolbar> style={{
<Icon minHeight: "100vh",
path={mdiFamilyTree} display: "flex",
size={1} flexDirection: "column",
style={{ marginRight: "1rem" }} }}
/> >
<AppBar position="sticky">
<Toolbar>
<Icon
path={mdiFamilyTree}
size={1}
style={{ marginRight: "1rem" }}
/>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}> <Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
<RouterLink to="/">GeneIT</RouterLink> <RouterLink to="/">GeneIT</RouterLink>
</Typography> </Typography>
<div> <div>
<Button size="large" color="inherit"> <Button size="large" color="inherit">
{user!.name} {user!.name}
</Button> </Button>
<Button <Button
size="large" size="large"
aria-label="account of current user" aria-label="account of current user"
aria-controls="menu-appbar" aria-controls="menu-appbar"
aria-haspopup="true" aria-haspopup="true"
onClick={handleMenu} onClick={handleMenu}
color="inherit" color="inherit"
>
<SettingsIcon />
</Button>
<Menu
id="menu-appbar"
anchorEl={anchorEl}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
open={Boolean(anchorEl)}
onClose={handleCloseMenu}
>
<Link
to="/profile"
style={{ color: "inherit", textDecoration: "none" }}
> >
<MenuItem onClick={handleCloseMenu}>Profil</MenuItem> <SettingsIcon />
</Link> </Button>
<MenuItem onClick={signOut}>Déconnexion</MenuItem> <Menu
</Menu> id="menu-appbar"
</div> anchorEl={anchorEl}
</Toolbar> anchorOrigin={{
</AppBar> vertical: "top",
<Outlet /> horizontal: "right",
</div> }}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
open={Boolean(anchorEl)}
onClose={handleCloseMenu}
>
<Link
to="/profile"
style={{ color: "inherit", textDecoration: "none" }}
>
<MenuItem onClick={handleCloseMenu}>Profil</MenuItem>
</Link>
<MenuItem onClick={signOut}>Déconnexion</MenuItem>
</Menu>
</div>
</Toolbar>
</AppBar>
<Outlet />
</div>
</UserContextK.Provider>
)} )}
/> />
); );
} }
export function useUser(): UserContext {
return React.useContext(UserContextK)!;
}