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