fix: use subscription for user search
All checks were successful
Release to Staging / build_and_release (push) Successful in 38s

This commit is contained in:
enes 2024-10-30 14:59:44 +01:00
parent 43c8ae4066
commit 4eb8c7d653

View File

@ -4,11 +4,11 @@ import {
NDKKind, NDKKind,
NDKSubscriptionCacheUsage, NDKSubscriptionCacheUsage,
NDKUserProfile, NDKUserProfile,
NostrEvent,
profileFromEvent profileFromEvent
} from '@nostr-dev-kit/ndk' } from '@nostr-dev-kit/ndk'
import { ErrorBoundary } from 'components/ErrorBoundary' import { ErrorBoundary } from 'components/ErrorBoundary'
import { GameCard } from 'components/GameCard' import { GameCard } from 'components/GameCard'
import { LoadingSpinner } from 'components/LoadingSpinner'
import { ModCard } from 'components/ModCard' import { ModCard } from 'components/ModCard'
import { ModFilter } from 'components/ModsFilter' import { ModFilter } from 'components/ModsFilter'
import { Pagination } from 'components/Pagination' import { Pagination } from 'components/Pagination'
@ -35,10 +35,7 @@ import {
DEFAULT_FILTER_OPTIONS, DEFAULT_FILTER_OPTIONS,
extractModData, extractModData,
isModDataComplete, isModDataComplete,
log, scrollIntoView
LogType,
scrollIntoView,
timeout
} from 'utils' } from 'utils'
enum SearchKindEnum { enum SearchKindEnum {
@ -364,48 +361,70 @@ const UsersResult = ({
moderationFilter, moderationFilter,
muteLists muteLists
}: UsersResultProps) => { }: UsersResultProps) => {
const { fetchEvents } = useNDKContext() const { ndk } = useNDKContext()
const [isFetching, setIsFetching] = useState(false)
const [profiles, setProfiles] = useState<NDKUserProfile[]>([]) const [profiles, setProfiles] = useState<NDKUserProfile[]>([])
const userState = useAppSelector((state) => state.user) const userState = useAppSelector((state) => state.user)
useEffect(() => { useEffect(() => {
if (searchTerm === '') { if (searchTerm === '') {
setProfiles([]) setProfiles([])
} else { } else {
const fetchProfiles = async () => { const sub = ndk.subscribe(
setIsFetching(true) {
const filter: NDKFilter = {
kinds: [NDKKind.Metadata], kinds: [NDKKind.Metadata],
search: searchTerm search: searchTerm
},
{
closeOnEose: true,
cacheUsage: NDKSubscriptionCacheUsage.PARALLEL
},
undefined,
false
)
// Stop the sub after 10 seconds if we are still searching the same term as before
window.setTimeout(() => {
if (sub.filter.search === searchTerm) {
sub.stop()
} }
}, 10000)
const profiles = await Promise.race([ const onEvent = (event: NostrEvent | NDKEvent) => {
fetchEvents(filter), if (!(event instanceof NDKEvent)) event = new NDKEvent(undefined, event)
timeout(10 * 1000) const dedupKey = event.deduplicationKey()
]) const existingEvent = events.get(dedupKey)
.then((events) => { if (existingEvent) {
const results = events.map((event) => { event = dedup(existingEvent, event)
const ndkEvent = new NDKEvent(undefined, event) }
const profile = profileFromEvent(ndkEvent) event.ndk = this
return profile events.set(dedupKey, event)
})
return results
})
.catch((err) => {
log(true, LogType.Error, 'An error occurred in fetching users', err)
return []
})
// We can't rely on the 'eose' to arrive
// Instead we repeat and sort results on each event
const ndkEvents = Array.from(events.values())
const profiles: NDKUserProfile[] = []
ndkEvents.forEach((event) => {
try {
const profile = profileFromEvent(event)
profiles.push(profile)
} catch (error) {
// If we are unable to parse silently skip over the errors
}
})
setProfiles(profiles) setProfiles(profiles)
setIsFetching(false)
} }
fetchProfiles() // Clear previous results
const events = new Map<string, NDKEvent>()
// Bind handler and start the sub
sub.on('event', onEvent)
sub.start()
return () => {
sub.stop()
}
} }
}, [fetchEvents, searchTerm]) }, [ndk, searchTerm])
const filteredProfiles = useMemo(() => { const filteredProfiles = useMemo(() => {
let filtered = [...profiles] let filtered = [...profiles]
@ -430,7 +449,6 @@ const UsersResult = ({
}, [userState.user?.npub, moderationFilter, profiles, muteLists]) }, [userState.user?.npub, moderationFilter, profiles, muteLists])
return ( return (
<> <>
{isFetching && <LoadingSpinner desc='Fetching Profiles' />}
<div className='IBMSecMain IBMSMListWrapper'> <div className='IBMSecMain IBMSMListWrapper'>
<div className='IBMSMList'> <div className='IBMSMList'>
{filteredProfiles.map((profile) => { {filteredProfiles.map((profile) => {
@ -505,3 +523,11 @@ const GamesResult = ({ searchTerm }: GamesResultProps) => {
</> </>
) )
} }
function dedup(event1: NDKEvent, event2: NDKEvent) {
// return the newest of the two
if (event1.created_at! > event2.created_at!) {
return event1
}
return event2
}