mega-plant/components/AccountMenu.tsx

63 lines
3.2 KiB
TypeScript
Raw Normal View History

"use client";
import { useEffect, useId, useRef, useState } from "react";
import Link from "next/link";
import { ChevronDown, Moon, Settings, Sun, UserRound } from "lucide-react";
import { useTheme } from "./ThemeProvider";
import { LogoutButton } from "./auth/LogoutButton";
export function AccountMenu({ name, email }: { name: string; email: string }) {
const [open, setOpen] = useState(false);
const root = useRef<HTMLDivElement>(null);
const trigger = useRef<HTMLButtonElement>(null);
const panelId = useId();
const { theme, toggle } = useTheme();
useEffect(() => {
if (!open) return;
const closeOutside = (event: Event) => {
if (!root.current?.contains(event.target as Node)) setOpen(false);
};
const closeOnEscape = (event: KeyboardEvent) => {
if (event.key === "Escape") {
setOpen(false);
trigger.current?.focus();
}
};
document.addEventListener("pointerdown", closeOutside);
document.addEventListener("focusin", closeOutside);
document.addEventListener("keydown", closeOnEscape);
return () => {
document.removeEventListener("pointerdown", closeOutside);
document.removeEventListener("focusin", closeOutside);
document.removeEventListener("keydown", closeOnEscape);
};
}, [open]);
const itemClass = "flex min-h-11 w-full items-center gap-3 rounded-lg px-3 text-sm text-text hover:bg-gray-100 focus-visible:outline-2 focus-visible:outline-[#30638E] dark:hover:bg-white/5";
return <div ref={root} className="relative">
<button ref={trigger} type="button" aria-label="Account and settings" title="Account and settings" aria-expanded={open} aria-controls={panelId}
onClick={() => setOpen(!open)}
className="flex min-h-11 min-w-11 items-center justify-center gap-2 rounded-xl border border-border px-1.5 text-text transition hover:bg-gray-100 focus-visible:outline-2 focus-visible:outline-[#30638E] dark:hover:bg-white/5 md:px-3">
<span className="grid h-8 w-8 shrink-0 place-items-center rounded-lg bg-[#30638E]/10 text-[#30638E] dark:text-indigo-ink"><UserRound className="h-4 w-4" /></span>
<span className="hidden max-w-32 truncate text-sm font-medium md:block">{name || "Account"}</span>
<ChevronDown className="hidden h-4 w-4 text-text-muted md:block" />
</button>
{open && <div id={panelId} className="absolute right-0 top-full mt-2 w-72 max-w-[calc(100vw-2rem)] rounded-xl border border-border bg-surface p-2 shadow-xl">
<div className="border-b border-border px-3 pb-3 pt-2">
<p className="break-words text-sm font-semibold text-text">{name || "Your account"}</p>
<p className="mt-1 break-all text-xs text-text-muted">{email}</p>
</div>
<nav aria-label="Account options" className="mt-2">
<Link href="/settings" className={itemClass} onClick={() => setOpen(false)}><Settings className="h-4 w-4" />Settings</Link>
<button type="button" onClick={toggle} className={itemClass}>
{theme === "dark" ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />}
{theme === "dark" ? "Switch to light mode" : "Switch to dark mode"}
</button>
<div className="mt-2 border-t border-border pt-2"><LogoutButton fullWidth /></div>
</nav>
</div>}
</div>;
}