wire local sources into useAutocomplete
This commit is contained in:
@@ -46,6 +46,7 @@ export type AutocompleteApi = {
|
|||||||
query: string
|
query: string
|
||||||
items: AutocompleteItem[]
|
items: AutocompleteItem[]
|
||||||
isFetching: boolean
|
isFetching: boolean
|
||||||
|
isError: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,35 +1,31 @@
|
|||||||
import {useCallback, useMemo} from 'react'
|
import {useCallback, useMemo} from 'react'
|
||||||
import {moderateProfile, type ModerationOpts} from '@atproto/api'
|
|
||||||
import {keepPreviousData, useQuery} from '@tanstack/react-query'
|
import {keepPreviousData, useQuery} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {isJustAMute, moduiContainsHideableOffense} from '#/lib/moderation'
|
|
||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {DEFAULT_LOGGED_OUT_PREFERENCES} from '#/state/queries/preferences'
|
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
import {
|
import {
|
||||||
type AutocompleteApi,
|
type AutocompleteApi,
|
||||||
type AutocompleteItem,
|
type AutocompleteItem,
|
||||||
type AutocompleteItemType,
|
type AutocompleteItemType,
|
||||||
type AutocompleteProfile,
|
type LocalSource,
|
||||||
} from '#/components/Autocomplete/types'
|
} from '#/components/Autocomplete/types'
|
||||||
|
import {mergeAutocompleteResults} from './mergeAutocompleteResults'
|
||||||
|
import {DEFAULT_MOD_OPTS, moderateProfileItem} from './moderation'
|
||||||
import {useEmojiSearch} from './useEmojiSearch'
|
import {useEmojiSearch} from './useEmojiSearch'
|
||||||
|
|
||||||
const DEFAULT_MOD_OPTS = {
|
|
||||||
userDid: undefined,
|
|
||||||
prefs: DEFAULT_LOGGED_OUT_PREFERENCES.moderationPrefs,
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useAutocomplete({
|
export function useAutocomplete({
|
||||||
type,
|
type,
|
||||||
query: q,
|
query: q,
|
||||||
limit,
|
limit,
|
||||||
showSearchFallback = false,
|
showSearchFallback = false,
|
||||||
|
sources,
|
||||||
}: {
|
}: {
|
||||||
type: AutocompleteItemType
|
type: AutocompleteItemType
|
||||||
query: string
|
query: string
|
||||||
limit?: number
|
limit?: number
|
||||||
showSearchFallback?: boolean
|
showSearchFallback?: boolean
|
||||||
|
sources?: LocalSource[]
|
||||||
}): AutocompleteApi {
|
}): AutocompleteApi {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const moderationOpts = useModerationOpts()
|
const moderationOpts = useModerationOpts()
|
||||||
@@ -46,7 +42,6 @@ export function useAutocomplete({
|
|||||||
],
|
],
|
||||||
async queryFn() {
|
async queryFn() {
|
||||||
if (type === 'profile') {
|
if (type === 'profile') {
|
||||||
// TODO return recents
|
|
||||||
if (!q) return []
|
if (!q) return []
|
||||||
|
|
||||||
// Going from "foo" to "foo." should not clear matches.
|
// Going from "foo" to "foo." should not clear matches.
|
||||||
@@ -98,11 +93,23 @@ export function useAutocomplete({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const items = useMemo(() => {
|
const items = useMemo(() => {
|
||||||
if (!query.data) {
|
const moderatedSources = sources?.map(source => ({
|
||||||
return []
|
...source,
|
||||||
}
|
items: source.items.filter(item => {
|
||||||
|
if (item.type !== 'profile') return true
|
||||||
|
return !!moderateProfileItem({
|
||||||
|
query: q,
|
||||||
|
item,
|
||||||
|
moderationOpts: moderationOpts || DEFAULT_MOD_OPTS,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
|
||||||
const results = [...query.data]
|
const results = mergeAutocompleteResults({
|
||||||
|
query: q,
|
||||||
|
sources: moderatedSources,
|
||||||
|
remoteItems: query.data ?? [],
|
||||||
|
})
|
||||||
|
|
||||||
if (showSearchFallback && q) {
|
if (showSearchFallback && q) {
|
||||||
results.unshift({
|
results.unshift({
|
||||||
@@ -112,35 +119,13 @@ export function useAutocomplete({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return results
|
return limit ? results.slice(0, limit) : results
|
||||||
}, [query.data, showSearchFallback, q])
|
}, [query.data, showSearchFallback, q, sources, moderationOpts, limit])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
query: q,
|
query: q,
|
||||||
items,
|
items,
|
||||||
isFetching: query.isFetching,
|
isFetching: query.isFetching,
|
||||||
|
isError: query.isError,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function moderateProfileItem({
|
|
||||||
query,
|
|
||||||
item,
|
|
||||||
moderationOpts,
|
|
||||||
}: {
|
|
||||||
query: string
|
|
||||||
item: AutocompleteProfile
|
|
||||||
moderationOpts: ModerationOpts
|
|
||||||
}) {
|
|
||||||
const modui = moderateProfile(item.profile, moderationOpts).ui('profileList')
|
|
||||||
const isExactMatch = query && item.profile.handle.toLowerCase() === query
|
|
||||||
|
|
||||||
if (
|
|
||||||
(isExactMatch && !moduiContainsHideableOffense(modui)) ||
|
|
||||||
!modui.filter ||
|
|
||||||
isJustAMute(modui)
|
|
||||||
) {
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import {moderateProfile, type ModerationOpts} from '@atproto/api'
|
||||||
|
|
||||||
|
import {isJustAMute, moduiContainsHideableOffense} from '#/lib/moderation'
|
||||||
|
import {DEFAULT_LOGGED_OUT_PREFERENCES} from '#/state/queries/preferences'
|
||||||
|
import {type AutocompleteProfile} from '#/components/Autocomplete/types'
|
||||||
|
|
||||||
|
export const DEFAULT_MOD_OPTS = {
|
||||||
|
userDid: undefined,
|
||||||
|
prefs: DEFAULT_LOGGED_OUT_PREFERENCES.moderationPrefs,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function moderateProfileItem({
|
||||||
|
query,
|
||||||
|
item,
|
||||||
|
moderationOpts,
|
||||||
|
}: {
|
||||||
|
query: string
|
||||||
|
item: AutocompleteProfile
|
||||||
|
moderationOpts: ModerationOpts
|
||||||
|
}) {
|
||||||
|
const modui = moderateProfile(item.profile, moderationOpts).ui('profileList')
|
||||||
|
const isExactMatch = query && item.profile.handle.toLowerCase() === query
|
||||||
|
|
||||||
|
if (
|
||||||
|
(isExactMatch && !moduiContainsHideableOffense(modui)) ||
|
||||||
|
!modui.filter ||
|
||||||
|
isJustAMute(modui)
|
||||||
|
) {
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user