index.tsx raw
1 import { Button } from '@/components/ui/button'
2 import { Pubkey } from '@/domain'
3 import { isSameAccount } from '@/lib/account'
4 import { cn } from '@/lib/utils'
5 import { useNostr } from '@/providers/NostrProvider'
6 import { TAccountPointer } from '@/types'
7 import { Loader, Trash2 } from 'lucide-react'
8 import { useState } from 'react'
9 import SignerTypeBadge from '../SignerTypeBadge'
10 import { SimpleUserAvatar } from '../UserAvatar'
11 import { SimpleUsername } from '../Username'
12
13 export default function AccountList({
14 className,
15 afterSwitch
16 }: {
17 className?: string
18 afterSwitch: () => void
19 }) {
20 const { accounts, account, switchAccount, removeAccount } = useNostr()
21 const [switchingAccount, setSwitchingAccount] = useState<TAccountPointer | null>(null)
22
23 return (
24 <div className={cn('space-y-2', className)}>
25 {accounts.map((act) => (
26 <div
27 key={`${act.pubkey}-${act.signerType}`}
28 className={cn(
29 'relative rounded-lg',
30 isSameAccount(act, account) ? 'border border-primary' : 'clickable'
31 )}
32 onClick={() => {
33 if (isSameAccount(act, account)) return
34 setSwitchingAccount(act)
35 switchAccount(act)
36 .then(() => afterSwitch())
37 .finally(() => setSwitchingAccount(null))
38 }}
39 >
40 <div className="flex justify-between items-center p-2">
41 <div className="flex-1 flex items-center gap-2 relative">
42 <SimpleUserAvatar userId={act.pubkey} />
43 <div className="flex-1 w-0">
44 <SimpleUsername userId={act.pubkey} className="font-semibold truncate" />
45 <div className="text-sm rounded-full bg-muted px-2 w-fit">
46 {Pubkey.tryFromString(act.pubkey)?.formatNpub(12) ?? act.pubkey.slice(0, 8)}
47 </div>
48 </div>
49 </div>
50 <div className="flex items-center gap-2">
51 <div className="flex gap-2 items-center">
52 <SignerTypeBadge signerType={act.signerType} />
53 </div>
54 <Button
55 variant="ghost"
56 size="icon"
57 className="text-muted-foreground hover:text-destructive"
58 onClick={(e) => {
59 e.stopPropagation()
60 removeAccount(act)
61 }}
62 >
63 <Trash2 />
64 </Button>
65 </div>
66 </div>
67 {switchingAccount && isSameAccount(act, switchingAccount) && (
68 <div className="absolute top-0 left-0 flex w-full h-full items-center justify-center rounded-lg bg-muted/60">
69 <Loader size={16} className="animate-spin" />
70 </div>
71 )}
72 </div>
73 ))}
74 </div>
75 )
76 }
77