an app to share curated trails
sidetrail.app
atproto
nextjs
react
rsc
1"use client";
2
3import { usePathname } from "next/navigation";
4import Link from "next/link";
5import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
6import { useLoginModal } from "@/app/LoginModalContext";
7import { logout } from "@/auth/actions";
8import "./UserMenu.css";
9
10interface UserMenuClientProps {
11 user: {
12 handle: string;
13 avatar?: string;
14 } | null;
15}
16
17export function UserMenuClient({ user }: UserMenuClientProps) {
18 const { openLoginModal } = useLoginModal();
19 const pathname = usePathname();
20
21 if (!user) {
22 return (
23 <button onClick={openLoginModal} className="UserMenu-loginButton">
24 log in
25 </button>
26 );
27 }
28
29 return (
30 <DropdownMenu.Root>
31 <DropdownMenu.Trigger asChild>
32 <button className="UserMenu-trigger" aria-label="User menu">
33 {user.avatar ? (
34 <img src={user.avatar} alt={user.handle} className="UserMenu-avatar" />
35 ) : (
36 <span className="UserMenu-avatarFallback">{user.handle[0].toUpperCase()}</span>
37 )}
38 </button>
39 </DropdownMenu.Trigger>
40
41 <DropdownMenu.Portal>
42 <DropdownMenu.Content className="UserMenu-content" align="end" sideOffset={8}>
43 <DropdownMenu.Item asChild>
44 <Link href={`/@${user.handle}`} className="UserMenu-item">
45 profile
46 </Link>
47 </DropdownMenu.Item>
48
49 <DropdownMenu.Separator className="UserMenu-separator" />
50
51 <DropdownMenu.Item className="UserMenu-item" onSelect={() => logout(pathname)}>
52 log out
53 </DropdownMenu.Item>
54 </DropdownMenu.Content>
55 </DropdownMenu.Portal>
56 </DropdownMenu.Root>
57 );
58}