user profile btn in social nav now only is active for current logged in user, added NSFW tag for admin tagged ones, mod search under a specific game, search term and some filters added to url, filter state is saved locally in cache, user search now works #108
@ -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
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user