AccountButton.tsx raw
1 import { Button } from '@/components/ui/button'
2 import {
3 DropdownMenu,
4 DropdownMenuContent,
5 DropdownMenuItem,
6 DropdownMenuLabel,
7 DropdownMenuSeparator,
8 DropdownMenuTrigger
9 } from '@/components/ui/dropdown-menu'
10 import { toWallet } from '@/lib/link'
11 import { cn } from '@/lib/utils'
12 import { useSecondaryPage, useSidebarDrawer } from '@/PageManager'
13 import { useNostr } from '@/providers/NostrProvider'
14 import { useScreenSize } from '@/providers/ScreenSizeProvider'
15 import { LogIn, LogOut, Plus, RefreshCw, Wallet } from 'lucide-react'
16 import { useState } from 'react'
17 import { useTranslation } from 'react-i18next'
18 import LoginDialog from '../LoginDialog'
19 import LogoutDialog from '../LogoutDialog'
20 import SignerTypeBadge from '../SignerTypeBadge'
21 import { SimpleUserAvatar } from '../UserAvatar'
22 import { SimpleUsername } from '../Username'
23 import SidebarItem from './SidebarItem'
24
25 export default function AccountButton({ collapse }: { collapse: boolean }) {
26 const { pubkey } = useNostr()
27
28 if (pubkey) {
29 return <ProfileButton collapse={collapse} />
30 } else {
31 return <LoginButton collapse={collapse} />
32 }
33 }
34
35 function ProfileButton({ collapse }: { collapse: boolean }) {
36 const { t } = useTranslation()
37 const { account, accounts, switchAccount } = useNostr()
38 const pubkey = account?.pubkey
39 const { push } = useSecondaryPage()
40 const { isSmallScreen } = useScreenSize()
41 const { close: closeSidebarDrawer } = useSidebarDrawer()
42 const [dropdownOpen, setDropdownOpen] = useState(false)
43 const [loginDialogOpen, setLoginDialogOpen] = useState(false)
44 const [logoutDialogOpen, setLogoutDialogOpen] = useState(false)
45 if (!pubkey) return null
46
47 const handleOpenLoginDialog = () => {
48 setDropdownOpen(false)
49 if (isSmallScreen) {
50 closeSidebarDrawer()
51 setTimeout(() => setLoginDialogOpen(true), 150)
52 } else {
53 setLoginDialogOpen(true)
54 }
55 }
56
57 const handleOpenLogoutDialog = () => {
58 setDropdownOpen(false)
59 if (isSmallScreen) {
60 closeSidebarDrawer()
61 setTimeout(() => setLogoutDialogOpen(true), 150)
62 } else {
63 setLogoutDialogOpen(true)
64 }
65 }
66
67 return (
68 <>
69 <DropdownMenu open={dropdownOpen} onOpenChange={setDropdownOpen}>
70 <DropdownMenuTrigger asChild>
71 <Button
72 variant="ghost"
73 className={cn(
74 'clickable shadow-none p-2 flex items-center bg-transparent text-foreground hover:text-accent-foreground rounded-lg justify-start gap-4 text-lg font-semibold',
75 collapse ? 'w-12 h-12' : 'w-full h-auto'
76 )}
77 >
78 <div className="flex gap-2 items-center flex-1 w-0">
79 <SimpleUserAvatar size="medium" userId={pubkey} />
80 {!collapse && (
81 <SimpleUsername className="truncate font-semibold text-lg" userId={pubkey} />
82 )}
83 </div>
84 </Button>
85 </DropdownMenuTrigger>
86 <DropdownMenuContent side="top" className="w-72">
87 <DropdownMenuItem onClick={() => push(toWallet())}>
88 <Wallet />
89 {t('Wallet')}
90 </DropdownMenuItem>
91 <DropdownMenuSeparator />
92 <DropdownMenuLabel>{t('Switch account')}</DropdownMenuLabel>
93 {accounts.map((act) => (
94 <DropdownMenuItem
95 className={act.pubkey === pubkey ? 'cursor-default focus:bg-background' : ''}
96 key={`${act.pubkey}:${act.signerType}`}
97 onClick={() => {
98 if (act.pubkey !== pubkey) {
99 switchAccount(act)
100 }
101 }}
102 >
103 <div className="flex gap-2 items-center flex-1">
104 <SimpleUserAvatar userId={act.pubkey} />
105 <div className="flex-1 w-0">
106 <SimpleUsername
107 userId={act.pubkey}
108 className="font-medium truncate"
109 skeletonClassName="h-3"
110 />
111 <SignerTypeBadge signerType={act.signerType} />
112 </div>
113 </div>
114 <div
115 className={cn(
116 'border border-muted-foreground rounded-full size-3.5',
117 act.pubkey === pubkey && 'size-4 border-4 border-primary'
118 )}
119 />
120 </DropdownMenuItem>
121 ))}
122 <DropdownMenuItem
123 onClick={handleOpenLoginDialog}
124 className="border border-dashed m-2 focus:border-muted-foreground focus:bg-background"
125 >
126 <div className="flex gap-2 items-center justify-center w-full py-2">
127 <Plus />
128 {t('Add an Account')}
129 </div>
130 </DropdownMenuItem>
131 <DropdownMenuItem
132 className="text-destructive focus:text-destructive"
133 onClick={handleOpenLogoutDialog}
134 >
135 <LogOut />
136 <span className="shrink-0">{t('Logout')}</span>
137 <SimpleUsername
138 userId={pubkey}
139 className="text-muted-foreground border border-muted-foreground px-1 rounded-md text-xs truncate"
140 />
141 </DropdownMenuItem>
142 <DropdownMenuSeparator />
143 <DropdownMenuItem
144 onClick={() => window.location.reload()}
145 >
146 <RefreshCw />
147 {t('Force Reload')}
148 </DropdownMenuItem>
149 </DropdownMenuContent>
150 </DropdownMenu>
151 <LoginDialog open={loginDialogOpen} setOpen={setLoginDialogOpen} />
152 <LogoutDialog open={logoutDialogOpen} setOpen={setLogoutDialogOpen} />
153 </>
154 )
155 }
156
157 function LoginButton({ collapse }: { collapse: boolean }) {
158 const { checkLogin } = useNostr()
159
160 return (
161 <SidebarItem onClick={() => checkLogin()} title="Login" collapse={collapse}>
162 <LogIn />
163 </SidebarItem>
164 )
165 }
166