diff --git a/src/components/FollowButton/index.tsx b/src/components/FollowButton/index.tsx
index d48dd324..9f63676f 100644
--- a/src/components/FollowButton/index.tsx
+++ b/src/components/FollowButton/index.tsx
@@ -20,10 +20,10 @@ import { toast } from 'sonner'
export default function FollowButton({ pubkey }: { pubkey: string }) {
const { t } = useTranslation()
const { pubkey: accountPubkey, checkLogin } = useNostr()
- const { followings, follow, unfollow } = useFollowList()
+ const { followingSet, follow, unfollow } = useFollowList()
const [updating, setUpdating] = useState(false)
const [hover, setHover] = useState(false)
- const isFollowing = useMemo(() => followings.includes(pubkey), [followings, pubkey])
+ const isFollowing = useMemo(() => followingSet.has(pubkey), [followingSet, pubkey])
if (!accountPubkey || (pubkey && pubkey === accountPubkey)) return null
diff --git a/src/components/FollowingBadge/index.tsx b/src/components/FollowingBadge/index.tsx
new file mode 100644
index 00000000..d6d00c93
--- /dev/null
+++ b/src/components/FollowingBadge/index.tsx
@@ -0,0 +1,23 @@
+import { userIdToPubkey } from '@/lib/pubkey'
+import { useFollowList } from '@/providers/FollowListProvider'
+import { UserRoundCheck } from 'lucide-react'
+import { useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+
+export default function FollowingBadge({ pubkey, userId }: { pubkey?: string; userId?: string }) {
+ const { t } = useTranslation()
+ const { followingSet } = useFollowList()
+ const isFollowing = useMemo(() => {
+ if (pubkey) return followingSet.has(pubkey)
+
+ return userId ? followingSet.has(userIdToPubkey(userId)) : false
+ }, [followingSet, pubkey, userId])
+
+ if (!isFollowing) return null
+
+ return (
+
+
+
+ )
+}
diff --git a/src/components/Note/index.tsx b/src/components/Note/index.tsx
index b094ae50..56086259 100644
--- a/src/components/Note/index.tsx
+++ b/src/components/Note/index.tsx
@@ -10,6 +10,7 @@ import { useMemo, useState } from 'react'
import AudioPlayer from '../AudioPlayer'
import ClientTag from '../ClientTag'
import Content from '../Content'
+import FollowingBadge from '../FollowingBadge'
import { FormattedTimestamp } from '../FormattedTimestamp'
import Nip05 from '../Nip05'
import NoteOptions from '../NoteOptions'
@@ -28,9 +29,9 @@ import MutedNote from './MutedNote'
import NsfwNote from './NsfwNote'
import PictureNote from './PictureNote'
import Poll from './Poll'
+import RelayReview from './RelayReview'
import UnknownNote from './UnknownNote'
import VideoNote from './VideoNote'
-import RelayReview from './RelayReview'
export default function Note({
event,
@@ -117,6 +118,7 @@ export default function Note({
className={`font-semibold flex truncate ${size === 'small' ? 'text-sm' : ''}`}
skeletonClassName={size === 'small' ? 'h-3' : 'h-4'}
/>
+
diff --git a/src/components/PostEditor/PostTextarea/Mention/MentionList.tsx b/src/components/PostEditor/PostTextarea/Mention/MentionList.tsx
index 536429fa..b0ed0d96 100644
--- a/src/components/PostEditor/PostTextarea/Mention/MentionList.tsx
+++ b/src/components/PostEditor/PostTextarea/Mention/MentionList.tsx
@@ -1,3 +1,4 @@
+import FollowingBadge from '@/components/FollowingBadge'
import { ScrollArea } from '@/components/ui/scroll-area'
import { formatNpub, userIdToPubkey } from '@/lib/pubkey'
import { cn } from '@/lib/utils'
@@ -87,7 +88,10 @@ const MentionList = forwardRef
((props, ref)
diff --git a/src/components/Profile/Followings.tsx b/src/components/Profile/Followings.tsx
index 07dca48b..95382017 100644
--- a/src/components/Profile/Followings.tsx
+++ b/src/components/Profile/Followings.tsx
@@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next'
export default function Followings({ pubkey }: { pubkey: string }) {
const { t } = useTranslation()
const { pubkey: accountPubkey } = useNostr()
- const { followings: selfFollowings } = useFollowList()
+ const { followingSet: selfFollowingSet } = useFollowList()
const { followings, isFetching } = useFetchFollowings(pubkey)
return (
@@ -18,7 +18,7 @@ export default function Followings({ pubkey }: { pubkey: string }) {
className="flex gap-1 hover:underline w-fit items-center"
>
{accountPubkey === pubkey ? (
- selfFollowings.length
+ selfFollowingSet.size
) : isFetching ? (
) : (
diff --git a/src/components/ProfileList/index.tsx b/src/components/ProfileList/index.tsx
index 2d288893..6a255c9a 100644
--- a/src/components/ProfileList/index.tsx
+++ b/src/components/ProfileList/index.tsx
@@ -37,7 +37,7 @@ export default function ProfileList({ pubkeys }: { pubkeys: string[] }) {
return (
{visiblePubkeys.map((pubkey, index) => (
-
+
))}
{pubkeys.length > visiblePubkeys.length &&
}
diff --git a/src/components/ProfileListBySearch/index.tsx b/src/components/ProfileListBySearch/index.tsx
index 9c74bd2c..9f84a027 100644
--- a/src/components/ProfileListBySearch/index.tsx
+++ b/src/components/ProfileListBySearch/index.tsx
@@ -67,7 +67,7 @@ export function ProfileListBySearch({ search }: { search: string }) {
return (
{Array.from(pubkeySet).map((pubkey, index) => (
-
+
))}
{hasMore &&
}
{hasMore &&
}
diff --git a/src/components/SearchBar/index.tsx b/src/components/SearchBar/index.tsx
index e14e6568..dde72a5a 100644
--- a/src/components/SearchBar/index.tsx
+++ b/src/components/SearchBar/index.tsx
@@ -378,7 +378,12 @@ function ProfileItem({
className={cn('px-2 hover:bg-accent rounded-md cursor-pointer', selected && 'bg-accent')}
onClick={onClick}
>
-
+
)
}
diff --git a/src/components/UserItem/index.tsx b/src/components/UserItem/index.tsx
index 785655ff..7dfc6280 100644
--- a/src/components/UserItem/index.tsx
+++ b/src/components/UserItem/index.tsx
@@ -3,29 +3,39 @@ import Nip05 from '@/components/Nip05'
import UserAvatar from '@/components/UserAvatar'
import Username from '@/components/Username'
import { Skeleton } from '@/components/ui/skeleton'
+import { userIdToPubkey } from '@/lib/pubkey'
import { cn } from '@/lib/utils'
+import { useMemo } from 'react'
+import FollowingBadge from '../FollowingBadge'
export default function UserItem({
- pubkey,
+ userId,
hideFollowButton,
+ showFollowingBadge = false,
className
}: {
- pubkey: string
+ userId: string
hideFollowButton?: boolean
+ showFollowingBadge?: boolean
className?: string
}) {
+ const pubkey = useMemo(() => userIdToPubkey(userId), [userId])
+
return (
-
+
-
-
+
+
+ {showFollowingBadge && }
+
+
- {!hideFollowButton &&
}
+ {!hideFollowButton &&
}
)
}
diff --git a/src/providers/FollowListProvider.tsx b/src/providers/FollowListProvider.tsx
index cb8c7053..b321098a 100644
--- a/src/providers/FollowListProvider.tsx
+++ b/src/providers/FollowListProvider.tsx
@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'
import { useNostr } from './NostrProvider'
type TFollowListContext = {
- followings: string[]
+ followingSet: Set
follow: (pubkey: string) => Promise
unfollow: (pubkey: string) => Promise
}
@@ -24,8 +24,8 @@ export const useFollowList = () => {
export function FollowListProvider({ children }: { children: React.ReactNode }) {
const { t } = useTranslation()
const { pubkey: accountPubkey, followListEvent, publish, updateFollowListEvent } = useNostr()
- const followings = useMemo(
- () => (followListEvent ? getPubkeysFromPTags(followListEvent.tags) : []),
+ const followingSet = useMemo(
+ () => new Set(followListEvent ? getPubkeysFromPTags(followListEvent.tags) : []),
[followListEvent]
)
@@ -65,7 +65,7 @@ export function FollowListProvider({ children }: { children: React.ReactNode })
return (