import { useEffect, useRef, useState } from "react"; import { Form, Link } from "react-router"; import { useTranslation } from "react-i18next"; import { Avatar } from "./Avatar"; interface Props { user: { username: string; displayName: string | null }; } export function AccountDropdown({ user }: Props) { const { t } = useTranslation("journal"); const [open, setOpen] = useState(false); const containerRef = useRef(null); // Click-outside + Escape close. Mounted only while open to keep the // listener cost zero in the steady state. useEffect(() => { if (!open) return; const onClick = (e: MouseEvent) => { if (!containerRef.current) return; if (!containerRef.current.contains(e.target as Node)) setOpen(false); }; const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") setOpen(false); }; document.addEventListener("mousedown", onClick); document.addEventListener("keydown", onKey); return () => { document.removeEventListener("mousedown", onClick); document.removeEventListener("keydown", onKey); }; }, [open]); return (
{open && (

{user.displayName ?? user.username}

@{user.username}

setOpen(false)} className="block px-3 py-2 text-sm text-gray-700 hover:bg-gray-50" > {t("nav.profile")} setOpen(false)} className="block px-3 py-2 text-sm text-gray-700 hover:bg-gray-50" > {t("nav.settings")}
)}
); }