From b1cecbbc07abf70f2ba6cfd2b73658c91b5d61e0 Mon Sep 17 00:00:00 2001 From: Ren Amamiya <123083837+reyamir@users.noreply.github.com> Date: Tue, 20 Jun 2023 13:48:08 +0700 Subject: [PATCH] add user page --- src/app/space/components/blocks/profile.tsx | 107 ----------- src/app/trending/components/profile.tsx | 2 +- src/app/user/_default.page.tsx | 1 + src/app/user/layout.tsx | 14 ++ src/app/user/pages/index.page.tsx | 192 ++++++++++++++++++++ src/shared/accounts/active.tsx | 6 +- src/shared/user.tsx | 6 +- 7 files changed, 216 insertions(+), 112 deletions(-) delete mode 100644 src/app/space/components/blocks/profile.tsx create mode 100644 src/app/user/_default.page.tsx create mode 100644 src/app/user/layout.tsx create mode 100644 src/app/user/pages/index.page.tsx diff --git a/src/app/space/components/blocks/profile.tsx b/src/app/space/components/blocks/profile.tsx deleted file mode 100644 index 4ec091ad..00000000 --- a/src/app/space/components/blocks/profile.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { ArrowLeftIcon } from "@shared/icons"; -import { Image } from "@shared/image"; -import { useActiveAccount } from "@stores/accounts"; -import { DEFAULT_AVATAR } from "@stores/constants"; -import { useProfile } from "@utils/hooks/useProfile"; -import { compactNumber } from "@utils/number"; -import { shortenKey } from "@utils/shortenKey"; -import useSWR from "swr"; - -const fetcher = (url: string) => fetch(url).then((r) => r.json()); - -export function ProfileBlock({ params }: { params: any }) { - const removeBlock = useActiveAccount((state: any) => state.removeBlock); - - const close = () => { - removeBlock(params.id, true); - }; - - const { user } = useProfile(params.pubkey); - const { data: userStats } = useSWR( - user ? `https://api.nostr.band/v0/stats/profile/${params.pubkey}` : null, - fetcher, - ); - - return ( -
-
- -

{params.title}

-
-
-
-
-
-
-
- {params.pubkey} -
-
-

- {user?.display_name || user?.name || "Anon"} -

-
- {user?.nip05 || shortenKey(params.pubkey)} -
-

- {user?.bio || user.about} -

-
- {!userStats ? ( -

Loading...

- ) : ( -
-
- - {userStats.stats[params.pubkey] - .followers_pubkey_count ?? 0} - - - Followers - -
-
- - {userStats.stats[params.pubkey] - .pub_following_pubkey_count ?? 0} - - - Following - -
-
- - {userStats.stats[params.pubkey].zaps_received - ? compactNumber.format( - userStats.stats[params.pubkey].zaps_received - .msats / 1000, - ) - : 0} - - - Zaps received - -
-
- )} -
-
-
-
-
-
- ); -} diff --git a/src/app/trending/components/profile.tsx b/src/app/trending/components/profile.tsx index 70e98f56..71579fd8 100644 --- a/src/app/trending/components/profile.tsx +++ b/src/app/trending/components/profile.tsx @@ -46,7 +46,7 @@ export function Profile({ data }: { data: any }) {

- {error &&

Failed to fetch

} + {error &&

Failed to fetch user stats

} {!userStats ? (

Loading...

) : ( diff --git a/src/app/user/_default.page.tsx b/src/app/user/_default.page.tsx new file mode 100644 index 00000000..e4596971 --- /dev/null +++ b/src/app/user/_default.page.tsx @@ -0,0 +1 @@ +export { LayoutUser as Layout } from "./layout"; diff --git a/src/app/user/layout.tsx b/src/app/user/layout.tsx new file mode 100644 index 00000000..90a31e26 --- /dev/null +++ b/src/app/user/layout.tsx @@ -0,0 +1,14 @@ +import { MultiAccounts } from "@shared/multiAccounts"; +import { Navigation } from "@shared/navigation"; + +export function LayoutUser({ children }: { children: React.ReactNode }) { + return ( +
+
+ + +
+
{children}
+
+ ); +} diff --git a/src/app/user/pages/index.page.tsx b/src/app/user/pages/index.page.tsx new file mode 100644 index 00000000..5138d834 --- /dev/null +++ b/src/app/user/pages/index.page.tsx @@ -0,0 +1,192 @@ +import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; +import { Image } from "@shared/image"; +import { RelayContext } from "@shared/relayProvider"; +import { useActiveAccount } from "@stores/accounts"; +import { DEFAULT_AVATAR } from "@stores/constants"; +import { dateToUnix } from "@utils/date"; +import { usePageContext } from "@utils/hooks/usePageContext"; +import { useProfile } from "@utils/hooks/useProfile"; +import { compactNumber } from "@utils/number"; +import { shortenKey } from "@utils/shortenKey"; +import { useContext } from "react"; +import useSWR from "swr"; + +const fetcher = (url: string) => fetch(url).then((r) => r.json()); + +export function Page() { + const ndk = useContext(RelayContext); + const pageContext = usePageContext(); + const searchParams: any = pageContext.urlParsed.search; + const pubkey = searchParams.pubkey; + + const { user } = useProfile(pubkey); + const { data: userStats, error } = useSWR( + `https://api.nostr.band/v0/stats/profile/${pubkey}`, + fetcher, + ); + + const account = useActiveAccount((state: any) => state.account); + const follows = account ? JSON.parse(account.follows) : []; + + const follow = (pubkey: string) => { + try { + const followsAsSet = new Set(follows); + followsAsSet.add(pubkey); + + const signer = new NDKPrivateKeySigner(account.privkey); + ndk.signer = signer; + + const tags = []; + followsAsSet.forEach((item) => { + tags.push(["p", item]); + }); + + const event = new NDKEvent(ndk); + event.content = ""; + event.created_at = dateToUnix(); + event.pubkey = pubkey; + event.kind = 3; + event.tags = tags; + // publish event + event.publish(); + } catch (error) { + console.log(error); + } + }; + + const unfollow = (pubkey: string) => { + try { + const followsAsSet = new Set(follows); + followsAsSet.delete(pubkey); + + const signer = new NDKPrivateKeySigner(account.privkey); + ndk.signer = signer; + + const tags = []; + followsAsSet.forEach((item) => { + tags.push(["p", item]); + }); + + const event = new NDKEvent(ndk); + event.content = ""; + event.created_at = dateToUnix(); + event.pubkey = pubkey; + event.kind = 3; + event.tags = tags; + // publish event + event.publish(); + } catch (error) { + console.log(error); + } + }; + + return ( +
+
+
+ {"banner"} +
+
+
+ {pubkey} +
+
+ {user?.displayName || user?.name || "No name"} +
+ + {user?.nip05 || shortenKey(pubkey)} + +

+ {user?.about} +

+
+
+
+ {error &&

Failed to fetch user stats

} + {!userStats ? ( +

Loading...

+ ) : ( +
+
+ + {userStats.stats[pubkey].followers_pubkey_count ?? 0} + + + Followers + +
+
+ + {userStats.stats[pubkey].pub_following_pubkey_count ?? 0} + + + Following + +
+
+ + {userStats.stats[pubkey].zaps_received + ? compactNumber.format( + userStats.stats[pubkey].zaps_received.msats / 1000, + ) + : 0} + + + Zaps received + +
+
+ + {userStats.stats[pubkey].zaps_sent + ? compactNumber.format( + userStats.stats[pubkey].zaps_sent.msats / 1000, + ) + : 0} + + + Zaps sent + +
+
+ )} +
+ {follows.includes(pubkey) ? ( + + ) : ( + + )} + + Message + +
+
+
+
+ ); +} diff --git a/src/shared/accounts/active.tsx b/src/shared/accounts/active.tsx index afe3aa2d..5f3c5cae 100644 --- a/src/shared/accounts/active.tsx +++ b/src/shared/accounts/active.tsx @@ -24,7 +24,7 @@ export function ActiveAccount({ data }: { data: any }) { // subscribe to channel const sub = ndk.subscribe( { - kinds: [4, 42], + kinds: [1, 4, 42], "#p": [data.pubkey], since: since, }, @@ -35,6 +35,10 @@ export function ActiveAccount({ data }: { data: any }) { sub.addListener("event", (event) => { switch (event.kind) { + case 1: + // send native notifiation + sendNativeNotification("Someone mention you"); + break; case 4: // save saveChat(data.pubkey, event); diff --git a/src/shared/user.tsx b/src/shared/user.tsx index 9b6c45d1..42db1997 100644 --- a/src/shared/user.tsx +++ b/src/shared/user.tsx @@ -66,7 +66,7 @@ export function User({ leaveTo="opacity-0 translate-y-1" > -
+