an app to share curated trails
sidetrail.app
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";
9import { Suspense } from "react";
10
11interface UserMenuClientProps {
12 user: {
13 handle: string;
14 avatar?: string;
15 } | null;
16}
17
18export function UserMenuClient({ user }: UserMenuClientProps) {
19 const { openLoginModal } = useLoginModal();
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 <Suspense fallback={null}>
41 <UserMenuDropdown handle={user.handle} />
42 </Suspense>
43 </DropdownMenu.Root>
44 );
45}
46
47function UserMenuDropdown({ handle }: { handle: string }) {
48 const pathname = usePathname();
49 return (
50 <DropdownMenu.Portal>
51 <DropdownMenu.Content className="UserMenu-content" align="end" sideOffset={8}>
52 <DropdownMenu.Item asChild>
53 <Link href={`/@${handle}`} className="UserMenu-item">
54 profile
55 </Link>
56 </DropdownMenu.Item>
57
58 <DropdownMenu.Separator className="UserMenu-separator" />
59
60 <DropdownMenu.Item className="UserMenu-item" onSelect={() => logout(pathname)}>
61 log out
62 </DropdownMenu.Item>
63 </DropdownMenu.Content>
64 </DropdownMenu.Portal>
65 );
66}