From a44327ddb00d7385196b8a22fe15eecb4b3017d2 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Wed, 5 Nov 2025 08:31:47 +0100 Subject: [PATCH] Display user name in application header --- matrixgw_backend/src/main.rs | 1 + matrixgw_frontend/src/api/AuthApi.ts | 6 +- .../dashboard/BaseAuthenticatedPage.tsx | 132 ++++++++++++------ .../src/widgets/dashboard/DashboardHeader.tsx | 44 +++++- .../src/widgets/dashboard/ThemeSwitcher.tsx | 32 ++--- 5 files changed, 147 insertions(+), 68 deletions(-) diff --git a/matrixgw_backend/src/main.rs b/matrixgw_backend/src/main.rs index a3fd905..a7073fe 100644 --- a/matrixgw_backend/src/main.rs +++ b/matrixgw_backend/src/main.rs @@ -17,6 +17,7 @@ async fn main() -> std::io::Result<()> { let secret_key = Key::from(AppConfig::get().secret().as_bytes()); + log::info!("Connect to Redis session store..."); let redis_store = RedisSessionStore::new(AppConfig::get().redis_connection_string()) .await .expect("Failed to connect to Redis!"); diff --git a/matrixgw_frontend/src/api/AuthApi.ts b/matrixgw_frontend/src/api/AuthApi.ts index eb4b105..d3f60eb 100644 --- a/matrixgw_frontend/src/api/AuthApi.ts +++ b/matrixgw_frontend/src/api/AuthApi.ts @@ -1,6 +1,6 @@ import { APIClient } from "./ApiClient"; -export interface AuthInfo { +export interface UserInfo { id: number; time_create: number; time_update: number; @@ -58,9 +58,9 @@ export class AuthApi { } /** - * Get auth information + * Get user information */ - static async GetAuthInfo(): Promise { + static async GetUserInfo(): Promise { return ( await APIClient.exec({ uri: "/auth/info", diff --git a/matrixgw_frontend/src/widgets/dashboard/BaseAuthenticatedPage.tsx b/matrixgw_frontend/src/widgets/dashboard/BaseAuthenticatedPage.tsx index 60ae762..47e8be3 100644 --- a/matrixgw_frontend/src/widgets/dashboard/BaseAuthenticatedPage.tsx +++ b/matrixgw_frontend/src/widgets/dashboard/BaseAuthenticatedPage.tsx @@ -3,13 +3,39 @@ import { useTheme } from "@mui/material/styles"; import Toolbar from "@mui/material/Toolbar"; import useMediaQuery from "@mui/material/useMediaQuery"; import * as React from "react"; -import { Outlet } from "react-router"; +import { Outlet, useNavigate } from "react-router"; import DashboardHeader from "./DashboardHeader"; import DashboardSidebar from "./DashboardSidebar"; +import { AuthApi, type UserInfo } from "../../api/AuthApi"; +import { AsyncWidget } from "../AsyncWidget"; +import { Button } from "@mui/material"; +import { useAuth } from "../../App"; + +interface UserInfoContext { + info: UserInfo; + reloadUserInfo: () => void; + signOut: () => void; +} + +const UserInfoContextK = React.createContext(null); export default function BaseAuthenticatedPage(): React.ReactElement { const theme = useTheme(); + const [userInfo, setuserInfo] = React.useState(null); + const loadUserInfo = async () => { + setuserInfo(await AuthApi.GetUserInfo()); + }; + + const auth = useAuth(); + const navigate = useNavigate(); + + const signOut = () => { + AuthApi.SignOut(); + navigate("/"); + auth.setSignedIn(false); + }; + const [isDesktopNavigationExpanded, setIsDesktopNavigationExpanded] = React.useState(false); const [isMobileNavigationExpanded, setIsMobileNavigationExpanded] = @@ -46,47 +72,71 @@ export default function BaseAuthenticatedPage(): React.ReactElement { const layoutRef = React.useRef(null); return ( - - - - - - ( + <> + + + )} + build={() => ( + - - - - + + + + + + + + + + + + )} + /> ); } + +export function userUserInfo(): UserInfoContext { + return React.use(UserInfoContextK)!; +} diff --git a/matrixgw_frontend/src/widgets/dashboard/DashboardHeader.tsx b/matrixgw_frontend/src/widgets/dashboard/DashboardHeader.tsx index 44444bc..0f76b97 100644 --- a/matrixgw_frontend/src/widgets/dashboard/DashboardHeader.tsx +++ b/matrixgw_frontend/src/widgets/dashboard/DashboardHeader.tsx @@ -1,7 +1,9 @@ import { mdiMessageTextFast } from "@mdi/js"; import Icon from "@mdi/react"; +import LogoutIcon from "@mui/icons-material/Logout"; import MenuIcon from "@mui/icons-material/Menu"; import MenuOpenIcon from "@mui/icons-material/MenuOpen"; +import { Avatar } from "@mui/material"; import MuiAppBar from "@mui/material/AppBar"; import Box from "@mui/material/Box"; import IconButton from "@mui/material/IconButton"; @@ -12,6 +14,7 @@ import Tooltip from "@mui/material/Tooltip"; import Typography from "@mui/material/Typography"; import * as React from "react"; import { RouterLink } from "../RouterLink"; +import { userUserInfo as useUserInfo } from "./BaseAuthenticatedPage"; import ThemeSwitcher from "./ThemeSwitcher"; const AppBar = styled(MuiAppBar)(({ theme }) => ({ @@ -42,6 +45,8 @@ export default function DashboardHeader({ menuOpen, onToggleMenu, }: DashboardHeaderProps) { + const user = useUserInfo(); + const handleMenuOpen = React.useCallback(() => { onToggleMenu(!menuOpen); }, [menuOpen, onToggleMenu]); @@ -101,6 +106,7 @@ export default function DashboardHeader({ ml: 1, whiteSpace: "nowrap", lineHeight: 1, + display: { xs: "none", sm: "block" }, }} > MatrixGW @@ -108,17 +114,41 @@ export default function DashboardHeader({ + + {/* User avatar */} - - - + + + + {user.info.name} + + + {user.info.email} + + + + + + + + - Hi TODO USER SIGN OUT diff --git a/matrixgw_frontend/src/widgets/dashboard/ThemeSwitcher.tsx b/matrixgw_frontend/src/widgets/dashboard/ThemeSwitcher.tsx index 0fd38c6..7c22dc3 100644 --- a/matrixgw_frontend/src/widgets/dashboard/ThemeSwitcher.tsx +++ b/matrixgw_frontend/src/widgets/dashboard/ThemeSwitcher.tsx @@ -34,24 +34,22 @@ export default function ThemeSwitcher() { } mode`} onClick={toggleMode} > - - - - + }, + }} + /> +