Files
workavia-calendar-front/src/components/Menubar/Menubar.tsx
T
lenhanphung 127417e154 fix(menubar): improve user avatar display logic
- Add null safety checks for user object
- Use optional chaining for safer property access
- Add fallback for empty email/name values
2025-09-19 13:40:02 +07:00

112 lines
2.8 KiB
TypeScript

import React, { useState } from "react";
import logo from "../../static/images/calendar.svg";
import AppsIcon from "@mui/icons-material/Apps";
import "./Menubar.css";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { stringToColor } from "../../features/Events/EventDisplay";
import { Avatar, IconButton, Popover } from "@mui/material";
import { push } from "redux-first-history";
export type AppIconProps = {
name: string;
link: string;
icon: string;
};
export function Menubar() {
const user = useAppSelector((state) => state.user.userData);
const applist: AppIconProps[] = (window as any).appList ?? [];
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const dispatch = useAppDispatch();
if (!user) {
dispatch(push("/"));
}
const handleOpen = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const open = Boolean(anchorEl);
return (
<>
<header className="menubar">
<MainTitle />
<div className="menubar-item search-bar">
<p>big search bar</p>
</div>
<div className="menubar-item">
{applist.length > 0 && (
<IconButton onClick={handleOpen}>
<AppsIcon />
</IconButton>
)}
<Avatar
sx={{
bgcolor: stringToColor(
(user && user.family_name) ? user.family_name :
(user && user.email) ? user.email :
''
),
}}
sizes="large"
>
{user?.name && user?.family_name
? `${user.name[0]}${user.family_name[0]}`
: user?.email?.[0] ?? ''}
</Avatar>
</div>
</header>
<Popover
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "right",
}}
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
>
<div className="app-grid">
{applist.map((prop: AppIconProps) => (
<AppIcon key={prop.name} prop={prop} />
))}
</div>
</Popover>
</>
);
}
export function MainTitle() {
return (
<div className="menubar-item tc-home">
<img className="logo" src={logo} />
<p>
<span className="twake">Twake</span>
<span className="calendar-text">Calendar</span>
</p>
</div>
);
}
function AppIcon({ prop }: { prop: AppIconProps }) {
return (
<a
href={prop.link}
target="_blank"
style={{ textDecoration: "none", color: "inherit" }}
>
<div>
<img src={prop.icon} alt={prop.name} />
<p>{prop.name}</p>
</div>
</a>
);
}