import Collapsible from '@/components/Collapsible' import FollowButton from '@/components/FollowButton' import Nip05 from '@/components/Nip05' import NoteList from '@/components/NoteList' import ProfileAbout from '@/components/ProfileAbout' import ProfileBanner from '@/components/ProfileBanner' import ProfileOptions from '@/components/ProfileOptions' import ProfileZapButton from '@/components/ProfileZapButton' import PubkeyCopy from '@/components/PubkeyCopy' import QrCodePopover from '@/components/QrCodePopover' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { Button } from '@/components/ui/button' import { Skeleton } from '@/components/ui/skeleton' import { useFetchFollowings, useFetchProfile } from '@/hooks' import SecondaryPageLayout from '@/layouts/SecondaryPageLayout' import { toMuteList, toProfileEditor } from '@/lib/link' import { generateImageByPubkey } from '@/lib/pubkey' import { SecondaryPageLink, useSecondaryPage } from '@/PageManager' import { useMuteList } from '@/providers/MuteListProvider' import { useNostr } from '@/providers/NostrProvider' import { Link, Zap } from 'lucide-react' import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import NotFoundPage from '../NotFoundPage' import Followings from './Followings' import Relays from './Relays' const ProfilePage = forwardRef(({ id, index }: { id?: string; index?: number }, ref) => { const { t } = useTranslation() const { push } = useSecondaryPage() const { profile, isFetching } = useFetchProfile(id) const { pubkey: accountPubkey } = useNostr() const { mutePubkeys } = useMuteList() const { followings } = useFetchFollowings(profile?.pubkey) const isFollowingYou = useMemo(() => { return ( !!accountPubkey && accountPubkey !== profile?.pubkey && followings.includes(accountPubkey) ) }, [followings, profile, accountPubkey]) const defaultImage = useMemo( () => (profile?.pubkey ? generateImageByPubkey(profile?.pubkey) : ''), [profile] ) const [topContainerHeight, setTopContainerHeight] = useState(0) const isSelf = accountPubkey === profile?.pubkey const [topContainer, setTopContainer] = useState(null) const topContainerRef = useCallback((node: HTMLDivElement | null) => { if (node) { setTopContainer(node) } }, []) useEffect(() => { if (!topContainer) return const checkHeight = () => { setTopContainerHeight(topContainer.scrollHeight) } checkHeight() const observer = new ResizeObserver(() => { checkHeight() }) observer.observe(topContainer) return () => { observer.disconnect() } }, [topContainer]) if (!profile && isFetching) { return (
) } if (!profile) return const { banner, username, about, avatar, pubkey, website, lightningAddress } = profile return (
{isSelf ? ( ) : ( <> {!!lightningAddress && } )}
{username}
{isFollowingYou && (
{t('Follows you')}
)}
{lightningAddress && (
{lightningAddress}
)}
{website && ( )}
{isSelf && ( {mutePubkeys.length}
{t('Muted')}
)}
) }) ProfilePage.displayName = 'ProfilePage' export default ProfilePage