/** * Renders the avatar menu that leads the header's icon row at every width: it * holds the profile link, the user's own playlists (the header's text link * leads to everyone's), the community page, the settings, the site's tools, and * logging out. * * @module */ import { useEffect, useRef, useState } from "react"; import { Link } from "react-router"; import { t } from "@lingui/core/macro"; import { Trans } from "@lingui/react/macro"; import { useLingui } from "@lingui/react"; import { DIGEST_MESSAGES } from "../../../shared/digest-messages.ts"; import { Avatar } from "../shared/Avatar.tsx"; import type { SelfUser } from "../../../shared/user.ts"; import { can } from "../../utils/auth/permissions.ts"; import { communityPath, userPath } from "../../../shared/paths.ts"; import { useAuth } from "../../hooks/auth/useAuth.ts"; /** Passed to {@link UserMenu} by `AppHeader`, for a signed-in user. */ export interface UserMenuProps { user: SelfUser; } /** * Renders the signed-in user's avatar, which opens a menu with links to their * profile, their playlists, `/community` and `/settings`, to `/manage` for * those who hold `category:manage` or `federation:manage`, and a Log out * button. A click outside or Escape closes it. */ export function UserMenu({ user }: UserMenuProps): React.JSX.Element { const { i18n } = useLingui(); const { logout } = useAuth(); const [open, setOpen] = useState(false); const ref = useRef(null); useEffect(() => { if (!open) return; function onMouseDown(e: MouseEvent) { if (ref.current && !ref.current.contains(e.target as Node)) { setOpen(false); } } function onKeyDown(e: KeyboardEvent) { if (e.key === "Escape") setOpen(false); } document.addEventListener("mousedown", onMouseDown); document.addEventListener("keydown", onKeyDown); return () => { document.removeEventListener("mousedown", onMouseDown); document.removeEventListener("keydown", onKeyDown); }; }, [open]); return (
{open && (
setOpen(false)} > @{user.username} setOpen(false)} > My playlists setOpen(false)} > {i18n._(DIGEST_MESSAGES.community)} setOpen(false)} > Settings {(can(user, "category:manage") || can(user, "federation:manage")) && ( setOpen(false)} > Manage )}
)}
); }