index.tsx raw
1 import AccountManager from '@/components/AccountManager'
2 import LoginDialog from '@/components/LoginDialog'
3 import LogoutDialog from '@/components/LogoutDialog'
4 import NpubQrCode from '@/components/NpubQrCode'
5 import PubkeyCopy from '@/components/PubkeyCopy'
6 import { Button } from '@/components/ui/button'
7 import { Separator } from '@/components/ui/separator'
8 import { SimpleUserAvatar } from '@/components/UserAvatar'
9 import { SimpleUsername } from '@/components/Username'
10 import PrimaryPageLayout from '@/layouts/PrimaryPageLayout'
11 import { toBookmarks, toProfile, toRelaySettings, toSettings, toWallet } from '@/lib/link'
12 import { cn } from '@/lib/utils'
13 import { useSecondaryPage } from '@/PageManager'
14 import { useNostr } from '@/providers/NostrProvider'
15 import { TPageRef } from '@/types'
16 import {
17 ArrowDownUp,
18 Bookmark,
19 ChevronRight,
20 LogOut,
21 Server,
22 Settings,
23 UserRound,
24 Wallet
25 } from 'lucide-react'
26 import { forwardRef, HTMLProps, useState } from 'react'
27 import { useTranslation } from 'react-i18next'
28
29 const MePage = forwardRef<TPageRef>((_, ref) => {
30 const { t } = useTranslation()
31 const { push } = useSecondaryPage()
32 const { pubkey } = useNostr()
33 const [loginDialogOpen, setLoginDialogOpen] = useState(false)
34 const [logoutDialogOpen, setLogoutDialogOpen] = useState(false)
35
36 if (!pubkey) {
37 return (
38 <PrimaryPageLayout
39 ref={ref}
40 pageName="home"
41 titlebar={<MePageTitlebar />}
42 hideTitlebarBottomBorder
43 >
44 <div className="flex flex-col p-4 gap-4 overflow-auto">
45 <AccountManager />
46 </div>
47 </PrimaryPageLayout>
48 )
49 }
50
51 return (
52 <PrimaryPageLayout
53 ref={ref}
54 pageName="home"
55 titlebar={<MePageTitlebar />}
56 hideTitlebarBottomBorder
57 >
58 <div className="flex gap-4 items-center p-4">
59 <SimpleUserAvatar userId={pubkey} size="big" />
60 <div className="space-y-1 flex-1 w-0">
61 <SimpleUsername
62 className="text-xl font-semibold text-wrap"
63 userId={pubkey}
64 skeletonClassName="h-6 w-32"
65 showQrCode={false}
66 />
67 <div className="flex gap-1 mt-1">
68 <PubkeyCopy pubkey={pubkey} />
69 <NpubQrCode pubkey={pubkey} />
70 </div>
71 </div>
72 </div>
73 <div className="mt-4">
74 <Item onClick={() => push(toProfile(pubkey))}>
75 <UserRound />
76 {t('Profile')}
77 </Item>
78 <Item onClick={() => push(toRelaySettings())}>
79 <Server /> {t('Relays')}
80 </Item>
81 <Item onClick={() => push(toBookmarks())}>
82 <Bookmark /> {t('Bookmarks')}
83 </Item>
84 <Item onClick={() => push(toWallet())}>
85 <Wallet />
86 {t('Wallet')}
87 </Item>
88 <Item onClick={() => setLoginDialogOpen(true)}>
89 <ArrowDownUp /> {t('Switch account')}
90 </Item>
91 <Separator className="bg-background" />
92 <Item
93 className="text-destructive focus:text-destructive"
94 onClick={() => setLogoutDialogOpen(true)}
95 hideChevron
96 >
97 <LogOut />
98 {t('Logout')}
99 </Item>
100 </div>
101 <LoginDialog open={loginDialogOpen} setOpen={setLoginDialogOpen} />
102 <LogoutDialog open={logoutDialogOpen} setOpen={setLogoutDialogOpen} />
103 </PrimaryPageLayout>
104 )
105 })
106 MePage.displayName = 'MePage'
107 export default MePage
108
109 function MePageTitlebar() {
110 const { push } = useSecondaryPage()
111 return (
112 <div className="flex justify-end items-center">
113 <Button variant="ghost" size="titlebar-icon" onClick={() => push(toSettings())}>
114 <Settings />
115 </Button>
116 </div>
117 )
118 }
119
120 function Item({
121 children,
122 className,
123 hideChevron = false,
124 ...props
125 }: HTMLProps<HTMLDivElement> & { hideChevron?: boolean }) {
126 return (
127 <div
128 className={cn(
129 'flex clickable justify-between items-center px-4 py-2 h-[52px] rounded-lg [&_svg]:size-4 [&_svg]:shrink-0',
130 className
131 )}
132 {...props}
133 >
134 <div className="flex items-center gap-4">{children}</div>
135 {!hideChevron && <ChevronRight />}
136 </div>
137 )
138 }
139