diff --git a/src/app/personal/components/contactCard.tsx b/src/app/personal/components/contactCard.tsx
new file mode 100644
index 00000000..8d80dd8e
--- /dev/null
+++ b/src/app/personal/components/contactCard.tsx
@@ -0,0 +1,40 @@
+import { useQuery } from '@tanstack/react-query';
+
+import { useNDK } from '@libs/ndk/provider';
+import { useStorage } from '@libs/storage/provider';
+
+import { LoaderIcon } from '@shared/icons';
+
+import { compactNumber } from '@utils/number';
+
+export function ContactCard() {
+ const { db } = useStorage();
+ const { ndk } = useNDK();
+ const { status, data } = useQuery({
+ queryKey: ['contacts'],
+ queryFn: async () => {
+ const user = ndk.getUser({ hexpubkey: db.account.pubkey });
+ return await user.follows();
+ },
+ refetchOnWindowFocus: false,
+ });
+
+ return (
+
+ {status === 'pending' ? (
+
+
+
+ ) : (
+
+
+ {compactNumber.format(data.size)}
+
+
+ Contacts
+
+
+ )}
+
+ );
+}
diff --git a/src/app/personal/components/postCard.tsx b/src/app/personal/components/postCard.tsx
new file mode 100644
index 00000000..1a9fb05a
--- /dev/null
+++ b/src/app/personal/components/postCard.tsx
@@ -0,0 +1,51 @@
+import { useQuery } from '@tanstack/react-query';
+
+import { useStorage } from '@libs/storage/provider';
+
+import { LoaderIcon } from '@shared/icons';
+
+import { compactNumber } from '@utils/number';
+
+export function PostCard() {
+ const { db } = useStorage();
+ const { status, data } = useQuery({
+ queryKey: ['user-stats', db.account.pubkey],
+ queryFn: async ({ signal }: { signal: AbortSignal }) => {
+ const res = await fetch(
+ `https://api.nostr.band/v0/stats/profile/${db.account.pubkey}`,
+ {
+ signal,
+ }
+ );
+
+ if (!res.ok) {
+ throw new Error('Error');
+ }
+
+ return await res.json();
+ },
+ refetchOnWindowFocus: false,
+ refetchOnMount: false,
+ refetchOnReconnect: false,
+ staleTime: Infinity,
+ });
+
+ return (
+
+ {status === 'pending' ? (
+
+
+
+ ) : (
+
+
+ {compactNumber.format(data.stats[db.account.pubkey].pub_note_count)}
+
+
+ Posts
+
+
+ )}
+
+ );
+}
diff --git a/src/app/personal/components/profileCard.tsx b/src/app/personal/components/profileCard.tsx
new file mode 100644
index 00000000..16ada6b1
--- /dev/null
+++ b/src/app/personal/components/profileCard.tsx
@@ -0,0 +1,58 @@
+import * as Avatar from '@radix-ui/react-avatar';
+import { minidenticon } from 'minidenticons';
+
+import { useStorage } from '@libs/storage/provider';
+
+import { LoaderIcon } from '@shared/icons';
+
+import { useProfile } from '@utils/hooks/useProfile';
+import { displayNpub } from '@utils/shortenKey';
+
+export function ProfileCard() {
+ const { db } = useStorage();
+ const { status, user } = useProfile(db.account.pubkey);
+
+ const svgURI =
+ 'data:image/svg+xml;utf8,' +
+ encodeURIComponent(minidenticon(db.account.pubkey, 90, 50));
+
+ return (
+
+ {status === 'pending' ? (
+
+
+
+ ) : (
+
+
+
+
+
+
+
+
+
+
+ {user?.display_name || user?.name}
+
+
+ {user.nip05 || displayNpub(db.account.pubkey, 16)}
+
+
+
+
+ )}
+
+ );
+}
diff --git a/src/app/personal/components/relayCard.tsx b/src/app/personal/components/relayCard.tsx
new file mode 100644
index 00000000..1bcb7570
--- /dev/null
+++ b/src/app/personal/components/relayCard.tsx
@@ -0,0 +1,40 @@
+import { useQuery } from '@tanstack/react-query';
+
+import { useNDK } from '@libs/ndk/provider';
+import { useStorage } from '@libs/storage/provider';
+
+import { LoaderIcon } from '@shared/icons';
+
+import { compactNumber } from '@utils/number';
+
+export function RelayCard() {
+ const { db } = useStorage();
+ const { ndk } = useNDK();
+ const { status, data } = useQuery({
+ queryKey: ['relays'],
+ queryFn: async () => {
+ const user = ndk.getUser({ hexpubkey: db.account.pubkey });
+ return await user.relayList();
+ },
+ refetchOnWindowFocus: false,
+ });
+
+ return (
+
+ {status === 'pending' ? (
+
+
+
+ ) : (
+
+
+ {compactNumber.format(data.relays.length)}
+
+
+ Relays
+
+
+ )}
+
+ );
+}
diff --git a/src/app/personal/components/zapCard.tsx b/src/app/personal/components/zapCard.tsx
new file mode 100644
index 00000000..7741553f
--- /dev/null
+++ b/src/app/personal/components/zapCard.tsx
@@ -0,0 +1,53 @@
+import { useQuery } from '@tanstack/react-query';
+
+import { useStorage } from '@libs/storage/provider';
+
+import { LoaderIcon } from '@shared/icons';
+
+import { compactNumber } from '@utils/number';
+
+export function ZapCard() {
+ const { db } = useStorage();
+ const { status, data } = useQuery({
+ queryKey: ['user-stats', db.account.pubkey],
+ queryFn: async ({ signal }: { signal: AbortSignal }) => {
+ const res = await fetch(
+ `https://api.nostr.band/v0/stats/profile/${db.account.pubkey}`,
+ {
+ signal,
+ }
+ );
+
+ if (!res.ok) {
+ throw new Error('Error');
+ }
+
+ return await res.json();
+ },
+ refetchOnWindowFocus: false,
+ refetchOnMount: false,
+ refetchOnReconnect: false,
+ staleTime: Infinity,
+ });
+
+ return (
+
+ {status === 'pending' ? (
+
+
+
+ ) : (
+
+
+ {compactNumber.format(
+ data.stats[db.account.pubkey].zaps_received.msats / 1000
+ )}
+
+
+ Sats received
+
+
+ )}
+
+ );
+}
diff --git a/src/app/personal/index.tsx b/src/app/personal/index.tsx
index c6dc0404..268f0aeb 100644
--- a/src/app/personal/index.tsx
+++ b/src/app/personal/index.tsx
@@ -1,9 +1,19 @@
-import { useStorage } from '@libs/storage/provider';
-
-import { UserProfile } from '@shared/userProfile';
+import { ContactCard } from '@app/personal/components/contactCard';
+import { PostCard } from '@app/personal/components/postCard';
+import { ProfileCard } from '@app/personal/components/profileCard';
+import { RelayCard } from '@app/personal/components/relayCard';
+import { ZapCard } from '@app/personal/components/zapCard';
export function PersonalScreen() {
- const { db } = useStorage();
-
- return ;
+ return (
+
+ );
}
diff --git a/src/main.jsx b/src/main.jsx
index 88fe7483..039b2bd9 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -25,7 +25,17 @@ const container = document.getElementById('root');
const root = createRoot(container);
root.render(
-
+ {
+ if (query.queryKey !== 'widgets') return true;
+ },
+ },
+ }}
+ >