From 72d43cceec56574b8012b0ff5d1c5929c599cd50 Mon Sep 17 00:00:00 2001 From: codytseng Date: Wed, 15 Oct 2025 22:35:24 +0800 Subject: [PATCH] feat: add note search to profile page --- src/components/Profile/ProfileFeed.tsx | 40 +++++++++++++++++++------- src/components/Profile/index.tsx | 22 +++++++++++++- 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/components/Profile/ProfileFeed.tsx b/src/components/Profile/ProfileFeed.tsx index f4afd61..74fbab3 100644 --- a/src/components/Profile/ProfileFeed.tsx +++ b/src/components/Profile/ProfileFeed.tsx @@ -1,13 +1,14 @@ import KindFilter from '@/components/KindFilter' import NoteList, { TNoteListRef } from '@/components/NoteList' import Tabs from '@/components/Tabs' -import { BIG_RELAY_URLS, MAX_PINNED_NOTES } from '@/constants' +import { BIG_RELAY_URLS, MAX_PINNED_NOTES, SEARCHABLE_RELAY_URLS } from '@/constants' import { generateBech32IdFromETag } from '@/lib/tag' import { isTouchDevice } from '@/lib/utils' import { useKindFilter } from '@/providers/KindFilterProvider' import { useNostr } from '@/providers/NostrProvider' import client from '@/services/client.service' import storage from '@/services/local-storage.service' +import relayInfoService from '@/services/relay-info.service' import { TFeedSubRequest, TNoteListMode } from '@/types' import { NostrEvent } from 'nostr-tools' import { useEffect, useMemo, useRef, useState } from 'react' @@ -15,10 +16,12 @@ import { RefreshButton } from '../RefreshButton' export default function ProfileFeed({ pubkey, - topSpace = 0 + topSpace = 0, + search = '' }: { pubkey: string topSpace?: number + search?: string }) { const { pubkey: myPubkey, pinListEvent: myPinListEvent } = useNostr() const { showKinds } = useKindFilter() @@ -106,17 +109,32 @@ export default function ProfileFeed({ } const relayList = await client.fetchRelayList(pubkey) - setSubRequests([ - { - urls: relayList.write.concat(BIG_RELAY_URLS).slice(0, 8), - filter: { - authors: [pubkey] + + if (search) { + const writeRelays = relayList.write.slice(0, 8) + const relayInfos = await relayInfoService.getRelayInfos(writeRelays) + const searchableRelays = writeRelays.filter((_, index) => + relayInfos[index]?.supported_nips?.includes(50) + ) + setSubRequests([ + { + urls: searchableRelays.concat(SEARCHABLE_RELAY_URLS).slice(0, 8), + filter: { authors: [pubkey], search } } - } - ]) + ]) + } else { + setSubRequests([ + { + urls: relayList.write.concat(BIG_RELAY_URLS).slice(0, 8), + filter: { + authors: [pubkey] + } + } + ]) + } } init() - }, [pubkey, listMode]) + }, [pubkey, listMode, search]) const handleListModeChange = (mode: TNoteListMode) => { setListMode(mode) @@ -150,7 +168,7 @@ export default function ProfileFeed({ showKinds={temporaryShowKinds} hideReplies={listMode === 'posts'} filterMutedNotes={false} - pinnedEventIds={listMode === 'you' ? [] : pinnedEventIds} + pinnedEventIds={listMode === 'you' || !!search ? [] : pinnedEventIds} /> ) diff --git a/src/components/Profile/index.tsx b/src/components/Profile/index.tsx index fbab966..12dbb52 100644 --- a/src/components/Profile/index.tsx +++ b/src/components/Profile/index.tsx @@ -21,6 +21,7 @@ import { Link, Zap } from 'lucide-react' import { useCallback, useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import NotFound from '../NotFound' +import SearchInput from '../SearchInput' import FollowedBy from './FollowedBy' import Followings from './Followings' import ProfileFeed from './ProfileFeed' @@ -32,6 +33,8 @@ export default function Profile({ id }: { id?: string }) { const { profile, isFetching } = useFetchProfile(id) const { pubkey: accountPubkey } = useNostr() const { mutePubkeySet } = useMuteList() + const [searchInput, setSearchInput] = useState('') + const [debouncedInput, setDebouncedInput] = useState(searchInput) const { followings } = useFetchFollowings(profile?.pubkey) const isFollowingYou = useMemo(() => { return ( @@ -51,6 +54,16 @@ export default function Profile({ id }: { id?: string }) { } }, []) + useEffect(() => { + const handler = setTimeout(() => { + setDebouncedInput(searchInput.trim()) + }, 1000) + + return () => { + clearTimeout(handler) + } + }, [searchInput]) + useEffect(() => { if (!profile?.pubkey) return @@ -185,8 +198,15 @@ export default function Profile({ id }: { id?: string }) { +
+ setSearchInput(e.target.value)} + placeholder={t('Search')} + /> +
- + ) }