diff --git a/src/renderer/src/components/AccountButton/ProfileButton.tsx b/src/renderer/src/components/AccountButton/ProfileButton.tsx index 8804c5f..ba43c97 100644 --- a/src/renderer/src/components/AccountButton/ProfileButton.tsx +++ b/src/renderer/src/components/AccountButton/ProfileButton.tsx @@ -20,10 +20,11 @@ export default function ProfileButton({ variant?: 'titlebar' | 'sidebar' }) { const { logout } = useNostr() - const { - profile: { avatar, username } - } = useFetchProfile(pubkey) + const { profile } = useFetchProfile(pubkey) const { push } = useSecondaryPage() + if (!profile) return null + + const { username, avatar } = profile const defaultAvatar = generateImageByPubkey(pubkey) let triggerComponent: React.ReactNode diff --git a/src/renderer/src/components/Note/index.tsx b/src/renderer/src/components/Note/index.tsx index 037b149..e35fc0c 100644 --- a/src/renderer/src/components/Note/index.tsx +++ b/src/renderer/src/components/Note/index.tsx @@ -35,6 +35,7 @@ export default function Note({
{formatTimestamp(event.created_at)} diff --git a/src/renderer/src/components/NoteCard/RepostNoteCard.tsx b/src/renderer/src/components/NoteCard/RepostNoteCard.tsx index 2da8a69..3212adf 100644 --- a/src/renderer/src/components/NoteCard/RepostNoteCard.tsx +++ b/src/renderer/src/components/NoteCard/RepostNoteCard.tsx @@ -16,7 +16,11 @@ export default function RepostNoteCard({ event, className }: { event: Event; cla
- +
reposted
diff --git a/src/renderer/src/components/PostDialog/Metions.tsx b/src/renderer/src/components/PostDialog/Metions.tsx index f8ead16..5299307 100644 --- a/src/renderer/src/components/PostDialog/Metions.tsx +++ b/src/renderer/src/components/PostDialog/Metions.tsx @@ -41,7 +41,11 @@ export default function Mentions({ {pubkeys.map((pubkey, index) => (
- +
))}
diff --git a/src/renderer/src/components/ProfileCard/index.tsx b/src/renderer/src/components/ProfileCard/index.tsx index 3348788..f7c1f64 100644 --- a/src/renderer/src/components/ProfileCard/index.tsx +++ b/src/renderer/src/components/ProfileCard/index.tsx @@ -7,11 +7,12 @@ import Nip05 from '../Nip05' import ProfileAbout from '../ProfileAbout' export default function ProfileCard({ pubkey }: { pubkey: string }) { - const { - profile: { avatar = '', username, nip05, about } - } = useFetchProfile(pubkey) + const { profile } = useFetchProfile(pubkey) const defaultImage = useMemo(() => generateImageByPubkey(pubkey), [pubkey]) + if (!profile) return null + const { avatar = '', username, nip05, about } = profile + return (
diff --git a/src/renderer/src/components/ReplyNote/index.tsx b/src/renderer/src/components/ReplyNote/index.tsx index d69d5b8..6fc9764 100644 --- a/src/renderer/src/components/ReplyNote/index.tsx +++ b/src/renderer/src/components/ReplyNote/index.tsx @@ -27,6 +27,7 @@ export default function ReplyNote({ {parentEvent && ( onClickParent(parentEvent.id)} /> diff --git a/src/renderer/src/components/ReplyNoteList/index.tsx b/src/renderer/src/components/ReplyNoteList/index.tsx index aff5d54..15899f0 100644 --- a/src/renderer/src/components/ReplyNoteList/index.tsx +++ b/src/renderer/src/components/ReplyNoteList/index.tsx @@ -67,13 +67,13 @@ export default function ReplyNoteList({ event, className }: { event: Event; clas return ( <>
{loading ? 'loading...' : hasMore ? 'load more older replies' : null}
- {eventsWithParentIds.length > 0 && (loading || hasMore) && } -
+ {eventsWithParentIds.length > 0 && (loading || hasMore) && } +
{eventsWithParentIds.map(([event, parentEventId], index) => (
(replyRefs.current[event.id] = el)} key={index}> (pubkey ? generateImageByPubkey(pubkey) : ''), [pubkey]) + const { profile } = useFetchProfile(userId) + const defaultAvatar = useMemo( + () => (profile?.pubkey ? generateImageByPubkey(profile.pubkey) : ''), + [profile] + ) - if (!pubkey) { + if (!profile) { return } + const { avatar, pubkey } = profile return ( diff --git a/src/renderer/src/components/Username/index.tsx b/src/renderer/src/components/Username/index.tsx index 04974cc..a11a082 100644 --- a/src/renderer/src/components/Username/index.tsx +++ b/src/renderer/src/components/Username/index.tsx @@ -1,4 +1,5 @@ import { HoverCard, HoverCardContent, HoverCardTrigger } from '@renderer/components/ui/hover-card' +import { Skeleton } from '@renderer/components/ui/skeleton' import { useFetchProfile } from '@renderer/hooks' import { toProfile } from '@renderer/lib/link' import { cn } from '@renderer/lib/utils' @@ -8,16 +9,18 @@ import ProfileCard from '../ProfileCard' export default function Username({ userId, showAt = false, - className + className, + skeletonClassName }: { userId: string showAt?: boolean className?: string + skeletonClassName?: string }) { - const { - profile: { username, pubkey } - } = useFetchProfile(userId) - if (!pubkey) return null + const { profile } = useFetchProfile(userId) + if (!profile) return + + const { username, pubkey } = profile return ( diff --git a/src/renderer/src/hooks/useFetchProfile.tsx b/src/renderer/src/hooks/useFetchProfile.tsx index 5f9b9e5..c137746 100644 --- a/src/renderer/src/hooks/useFetchProfile.tsx +++ b/src/renderer/src/hooks/useFetchProfile.tsx @@ -7,12 +7,11 @@ import { useEffect, useState } from 'react' export function useFetchProfile(id?: string) { const [isFetching, setIsFetching] = useState(true) const [error, setError] = useState(null) - const [profile, setProfile] = useState({ - username: id ? (id.length > 9 ? id.slice(0, 4) + '...' + id.slice(-4) : id) : 'username' - }) + const [profile, setProfile] = useState(null) useEffect(() => { const fetchProfile = async () => { + let pubkey: string | undefined try { if (!id) { setIsFetching(false) @@ -20,8 +19,6 @@ export function useFetchProfile(id?: string) { return } - let pubkey: string | undefined - if (/^[0-9a-f]{64}$/.test(id)) { pubkey = id } else { @@ -41,7 +38,6 @@ export function useFetchProfile(id?: string) { setError(new Error('Invalid id')) return } - setProfile({ pubkey, username: formatPubkey(pubkey) }) const profile = await client.fetchProfile(pubkey) if (profile) { @@ -50,6 +46,12 @@ export function useFetchProfile(id?: string) { } catch (err) { setError(err as Error) } finally { + if (pubkey) { + setProfile((pre) => { + if (pre) return pre + return { pubkey, username: formatPubkey(pubkey!) } as TProfile + }) + } setIsFetching(false) } } diff --git a/src/renderer/src/pages/secondary/FollowingListPage/index.tsx b/src/renderer/src/pages/secondary/FollowingListPage/index.tsx index 614f0c3..27f5896 100644 --- a/src/renderer/src/pages/secondary/FollowingListPage/index.tsx +++ b/src/renderer/src/pages/secondary/FollowingListPage/index.tsx @@ -7,10 +7,8 @@ import SecondaryPageLayout from '@renderer/layouts/SecondaryPageLayout' import { useEffect, useRef, useState } from 'react' export default function FollowingListPage({ id }: { id?: string }) { - const { - profile: { username, pubkey } - } = useFetchProfile(id) - const { followings } = useFetchFollowings(pubkey) + const { profile } = useFetchProfile(id) + const { followings } = useFetchFollowings(profile?.pubkey) const [visibleFollowings, setVisibleFollowings] = useState([]) const observer = useRef(null) const bottomRef = useRef(null) @@ -47,7 +45,9 @@ export default function FollowingListPage({ id }: { id?: string }) { }, [visibleFollowings]) return ( - +
{visibleFollowings.map((pubkey, index) => ( @@ -59,15 +59,14 @@ export default function FollowingListPage({ id }: { id?: string }) { } function FollowingItem({ pubkey }: { pubkey: string }) { - const { - profile: { about, nip05 } - } = useFetchProfile(pubkey) + const { profile } = useFetchProfile(pubkey) + const { nip05, about } = profile || {} return (
- +
- +
{about}
diff --git a/src/renderer/src/pages/secondary/NotePage/index.tsx b/src/renderer/src/pages/secondary/NotePage/index.tsx index af95f10..81c7d70 100644 --- a/src/renderer/src/pages/secondary/NotePage/index.tsx +++ b/src/renderer/src/pages/secondary/NotePage/index.tsx @@ -5,12 +5,12 @@ import UserAvatar from '@renderer/components/UserAvatar' import Username from '@renderer/components/Username' import { Card } from '@renderer/components/ui/card' import { Separator } from '@renderer/components/ui/separator' +import { Skeleton } from '@renderer/components/ui/skeleton' import { useFetchEventById } from '@renderer/hooks' import SecondaryPageLayout from '@renderer/layouts/SecondaryPageLayout' import { getParentEventId, getRootEventId } from '@renderer/lib/event' import { toNote } from '@renderer/lib/link' import { useMemo } from 'react' -import LoadingPage from '../LoadingPage' import NotFoundPage from '../NotFoundPage' export default function NotePage({ id }: { id?: string }) { @@ -18,7 +18,13 @@ export default function NotePage({ id }: { id?: string }) { const parentEventId = useMemo(() => getParentEventId(event), [event]) const rootEventId = useMemo(() => getRootEventId(event), [event]) - if (!event && isFetching) return + if (!event && isFetching) { + return ( + + + + ) + } if (!event) return return ( @@ -44,7 +50,7 @@ function ParentNote({ eventId }: { eventId?: string }) { onClick={() => push(toNote(event.id))} > - +
{event.content}
diff --git a/src/renderer/src/pages/secondary/ProfilePage/index.tsx b/src/renderer/src/pages/secondary/ProfilePage/index.tsx index 1756570..bc22915 100644 --- a/src/renderer/src/pages/secondary/ProfilePage/index.tsx +++ b/src/renderer/src/pages/secondary/ProfilePage/index.tsx @@ -18,26 +18,40 @@ import PubkeyCopy from './PubkeyCopy' import QrCodePopover from './QrCodePopover' import LoadingPage from '../LoadingPage' import NotFoundPage from '../NotFoundPage' +import { Skeleton } from '@renderer/components/ui/skeleton' export default function ProfilePage({ id }: { id?: string }) { - const { - profile: { banner, username, nip05, about, avatar, pubkey }, - isFetching - } = useFetchProfile(id) - const relayList = useFetchRelayList(pubkey) + const { profile, isFetching } = useFetchProfile(id) + const relayList = useFetchRelayList(profile?.pubkey) const { pubkey: accountPubkey } = useNostr() const { followings: selfFollowings } = useFollowList() - const { followings } = useFetchFollowings(pubkey) + const { followings } = useFetchFollowings(profile?.pubkey) const isFollowingYou = useMemo( - () => !!accountPubkey && accountPubkey !== pubkey && followings.includes(accountPubkey), - [followings, pubkey] + () => + !!accountPubkey && accountPubkey !== profile?.pubkey && followings.includes(accountPubkey), + [followings, profile] ) - const defaultImage = useMemo(() => (pubkey ? generateImageByPubkey(pubkey) : ''), [pubkey]) - const isSelf = accountPubkey === pubkey + const defaultImage = useMemo( + () => (profile?.pubkey ? generateImageByPubkey(profile?.pubkey) : ''), + [profile] + ) + const isSelf = accountPubkey === profile?.pubkey - if (!pubkey && isFetching) return - if (!pubkey) return + if (!profile && isFetching) { + return ( + +
+ + +
+ + +
+ ) + } + if (!profile) return + const { banner, username, nip05, about, avatar, pubkey } = profile return (
diff --git a/src/renderer/src/types.ts b/src/renderer/src/types.ts index 330abe7..22c0967 100644 --- a/src/renderer/src/types.ts +++ b/src/renderer/src/types.ts @@ -1,6 +1,6 @@ export type TProfile = { username: string - pubkey?: string + pubkey: string banner?: string avatar?: string nip05?: string