From bcafbcc48c35e9ef0b508aa8f1e36a53ae60bb07 Mon Sep 17 00:00:00 2001 From: codytseng Date: Fri, 14 Nov 2025 22:51:37 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=F0=9F=92=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ImageWithLightbox/index.tsx | 5 +- src/components/Profile/AvatarWithLightbox.tsx | 32 ++++++++ src/components/Profile/BannerWithLightbox.tsx | 33 ++++++++ src/components/Profile/index.tsx | 19 ++--- src/components/ProfileBanner/index.tsx | 80 ------------------- src/components/UserAvatar/index.tsx | 75 +---------------- src/services/lightning.service.ts | 11 ++- 7 files changed, 87 insertions(+), 168 deletions(-) create mode 100644 src/components/Profile/AvatarWithLightbox.tsx create mode 100644 src/components/Profile/BannerWithLightbox.tsx diff --git a/src/components/ImageWithLightbox/index.tsx b/src/components/ImageWithLightbox/index.tsx index dd96f2ac..c9871072 100644 --- a/src/components/ImageWithLightbox/index.tsx +++ b/src/components/ImageWithLightbox/index.tsx @@ -13,13 +13,15 @@ import Image from '../Image' export default function ImageWithLightbox({ image, className, - classNames = {} + classNames = {}, + errorPlaceholder }: { image: TImetaInfo className?: string classNames?: { wrapper?: string } + errorPlaceholder?: string }) { const id = useMemo(() => `image-with-lightbox-${randomString()}`, []) const { t } = useTranslation() @@ -67,6 +69,7 @@ export default function ImageWithLightbox({ }} image={image} onClick={(e) => handlePhotoClick(e)} + errorPlaceholder={errorPlaceholder} /> {index >= 0 && createPortal( diff --git a/src/components/Profile/AvatarWithLightbox.tsx b/src/components/Profile/AvatarWithLightbox.tsx new file mode 100644 index 00000000..7685f7d0 --- /dev/null +++ b/src/components/Profile/AvatarWithLightbox.tsx @@ -0,0 +1,32 @@ +import { Skeleton } from '@/components/ui/skeleton' +import { useFetchProfile } from '@/hooks' +import { generateImageByPubkey } from '@/lib/pubkey' +import { useMemo } from 'react' +import ImageWithLightbox from '../ImageWithLightbox' + +export default function AvatarWithLightbox({ userId }: { userId: string }) { + const { profile } = useFetchProfile(userId) + const defaultAvatar = useMemo( + () => (profile?.pubkey ? generateImageByPubkey(profile.pubkey) : ''), + [profile] + ) + + if (!profile) { + return ( + + ) + } + const { avatar, pubkey } = profile || {} + + return ( + + ) +} diff --git a/src/components/Profile/BannerWithLightbox.tsx b/src/components/Profile/BannerWithLightbox.tsx new file mode 100644 index 00000000..4beda1da --- /dev/null +++ b/src/components/Profile/BannerWithLightbox.tsx @@ -0,0 +1,33 @@ +import { generateImageByPubkey } from '@/lib/pubkey' +import { useEffect, useMemo, useState } from 'react' +import ImageWithLightbox from '../ImageWithLightbox' + +export default function BannerWithLightbox({ + pubkey, + banner +}: { + pubkey: string + banner?: string +}) { + const defaultBanner = useMemo(() => generateImageByPubkey(pubkey), [pubkey]) + const [bannerUrl, setBannerUrl] = useState(banner ?? defaultBanner) + + useEffect(() => { + if (banner) { + setBannerUrl(banner) + } else { + setBannerUrl(defaultBanner) + } + }, [defaultBanner, banner]) + + return ( + + ) +} diff --git a/src/components/Profile/index.tsx b/src/components/Profile/index.tsx index 3aa05439..6d98f7d0 100644 --- a/src/components/Profile/index.tsx +++ b/src/components/Profile/index.tsx @@ -3,13 +3,11 @@ import FollowButton from '@/components/FollowButton' import Nip05 from '@/components/Nip05' import NpubQrCode from '@/components/NpubQrCode' import ProfileAbout from '@/components/ProfileAbout' -import { BannerWithLightbox } from '@/components/ProfileBanner' import ProfileOptions from '@/components/ProfileOptions' import ProfileZapButton from '@/components/ProfileZapButton' import PubkeyCopy from '@/components/PubkeyCopy' import { Button } from '@/components/ui/button' import { Skeleton } from '@/components/ui/skeleton' -import { AvatarWithLightbox } from '@/components/UserAvatar' import { useFetchFollowings, useFetchProfile } from '@/hooks' import { toMuteList, toProfileEditor } from '@/lib/link' import { SecondaryPageLink, useSecondaryPage } from '@/PageManager' @@ -25,6 +23,9 @@ import FollowedBy from './FollowedBy' import Followings from './Followings' import ProfileFeed from './ProfileFeed' import Relays from './Relays' +import TextWithEmojis from '../TextWithEmojis' +import AvatarWithLightbox from './AvatarWithLightbox' +import BannerWithLightbox from './BannerWithLightbox' export default function Profile({ id }: { id?: string }) { const { t } = useTranslation() @@ -114,12 +115,8 @@ export default function Profile({ id }: { id?: string }) { <>
- - + +
@@ -141,7 +138,11 @@ export default function Profile({ id }: { id?: string }) {
-
{username}
+ {isFollowingYou && (
{t('Follows you')} diff --git a/src/components/ProfileBanner/index.tsx b/src/components/ProfileBanner/index.tsx index 04d40802..dbf025d6 100644 --- a/src/components/ProfileBanner/index.tsx +++ b/src/components/ProfileBanner/index.tsx @@ -1,11 +1,6 @@ import { generateImageByPubkey } from '@/lib/pubkey' -import { randomString } from '@/lib/random' import { cn } from '@/lib/utils' -import modalManager from '@/services/modal-manager.service' import { useEffect, useMemo, useState } from 'react' -import { createPortal } from 'react-dom' -import Lightbox from 'yet-another-react-lightbox' -import Zoom from 'yet-another-react-lightbox/plugins/zoom' import Image from '../Image' export default function ProfileBanner({ @@ -37,78 +32,3 @@ export default function ProfileBanner({ /> ) } - -export function BannerWithLightbox({ - pubkey, - banner, - className -}: { - pubkey: string - banner?: string - className?: string -}) { - const id = useMemo(() => `profile-banner-lightbox-${randomString()}`, []) - const defaultBanner = useMemo(() => generateImageByPubkey(pubkey), [pubkey]) - const [bannerUrl, setBannerUrl] = useState(banner ?? defaultBanner) - const [index, setIndex] = useState(-1) - - useEffect(() => { - if (banner) { - setBannerUrl(banner) - } else { - setBannerUrl(defaultBanner) - } - }, [defaultBanner, banner]) - - useEffect(() => { - if (index >= 0) { - modalManager.register(id, () => { - setIndex(-1) - }) - } else { - modalManager.unregister(id) - } - }, [index, id]) - - const handleBannerClick = (event: React.MouseEvent) => { - event.stopPropagation() - event.preventDefault() - setIndex(0) - } - - return ( - <> - {`${pubkey} - {index >= 0 && - createPortal( -
e.stopPropagation()}> - = 0} - close={() => setIndex(-1)} - controller={{ - closeOnBackdropClick: true, - closeOnPullUp: true, - closeOnPullDown: true - }} - styles={{ - toolbar: { paddingTop: '2.25rem' } - }} - /> -
, - document.body - )} - - ) -} diff --git a/src/components/UserAvatar/index.tsx b/src/components/UserAvatar/index.tsx index 47820917..38fa3934 100644 --- a/src/components/UserAvatar/index.tsx +++ b/src/components/UserAvatar/index.tsx @@ -3,14 +3,9 @@ import { Skeleton } from '@/components/ui/skeleton' import { useFetchProfile } from '@/hooks' import { toProfile } from '@/lib/link' import { generateImageByPubkey } from '@/lib/pubkey' -import { randomString } from '@/lib/random' import { cn } from '@/lib/utils' import { SecondaryPageLink } from '@/PageManager' -import modalManager from '@/services/modal-manager.service' -import { useEffect, useMemo, useState } from 'react' -import { createPortal } from 'react-dom' -import Lightbox from 'yet-another-react-lightbox' -import Zoom from 'yet-another-react-lightbox/plugins/zoom' +import { useMemo } from 'react' import Image from '../Image' import ProfileCard from '../ProfileCard' @@ -84,71 +79,3 @@ export function SimpleUserAvatar({ /> ) } - -export function AvatarWithLightbox({ - userId, - size = 'normal', - className -}: { - userId: string - size?: 'large' | 'big' | 'semiBig' | 'normal' | 'medium' | 'small' | 'xSmall' | 'tiny' - className?: string -}) { - const id = useMemo(() => `user-avatar-lightbox-${randomString()}`, []) - const { profile } = useFetchProfile(userId) - const defaultAvatar = useMemo( - () => (profile?.pubkey ? generateImageByPubkey(profile.pubkey) : ''), - [profile] - ) - const [index, setIndex] = useState(-1) - - useEffect(() => { - if (index >= 0) { - modalManager.register(id, () => { - setIndex(-1) - }) - } else { - modalManager.unregister(id) - } - }, [index, id]) - - const handleClick = (e: React.MouseEvent) => { - e.stopPropagation() - e.preventDefault() - setIndex(0) - } - - const imageUrl = profile?.avatar ?? defaultAvatar - - return ( - <> - - {index >= 0 && - createPortal( -
e.stopPropagation()}> - = 0} - close={() => setIndex(-1)} - controller={{ - closeOnBackdropClick: true, - closeOnPullUp: true, - closeOnPullDown: true - }} - styles={{ - toolbar: { paddingTop: '2.25rem' } - }} - /> -
, - document.body - )} - - ) -} diff --git a/src/services/lightning.service.ts b/src/services/lightning.service.ts index 0306231b..779cbcfe 100644 --- a/src/services/lightning.service.ts +++ b/src/services/lightning.service.ts @@ -73,10 +73,13 @@ class LightningService { comment }) const zapRequest = await client.signer.signEvent(zapRequestDraft) - const separator = callback.includes('?') ? '&' : '?' - const zapRequestRes = await fetch( - `${callback}${separator}amount=${amount}&nostr=${encodeURI(JSON.stringify(zapRequest))}&lnurl=${lnurl}` - ) + + const zapRequestUrl = new URL(callback) + zapRequestUrl.searchParams.append('amount', amount.toString()) + zapRequestUrl.searchParams.append('nostr', JSON.stringify(zapRequest)) + zapRequestUrl.searchParams.append('lnurl', lnurl) + + const zapRequestRes = await fetch(zapRequestUrl.toString()) const zapRequestResBody = await zapRequestRes.json() if (zapRequestResBody.error) { throw new Error(zapRequestResBody.message)