import React from 'react'
import {
ViewStyle,
TextInput,
View,
StyleSheet,
TouchableOpacity,
ActivityIndicator,
} from 'react-native'
import {useNavigation, StackActions} from '@react-navigation/native'
import {
AppBskyActorDefs,
moderateProfile,
ModerationDecision,
} from '@atproto/api'
import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {s} from '#/lib/styles'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
import {makeProfileLink} from '#/lib/routes/links'
import {Link} from '#/view/com/util/Link'
import {usePalette} from 'lib/hooks/usePalette'
import {MagnifyingGlassIcon2} from 'lib/icons'
import {NavigationProp} from 'lib/routes/types'
import {Text} from 'view/com/util/text/Text'
import {UserAvatar} from '#/view/com/util/UserAvatar'
import {useActorAutocompleteFn} from '#/state/queries/actor-autocomplete'
import {useModerationOpts} from '#/state/queries/preferences'
export const MATCH_HANDLE =
/@?([a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*(?:\.[a-zA-Z]{2,}))/
export function SearchLinkCard({
label,
to,
onPress,
style,
}: {
label: string
to?: string
onPress?: () => void
style?: ViewStyle
}) {
const pal = usePalette('default')
const inner = (
{label}
)
if (onPress) {
return (
{inner}
)
}
return (
{label}
)
}
export function SearchProfileCard({
profile,
moderation,
}: {
profile: AppBskyActorDefs.ProfileViewBasic
moderation: ModerationDecision
}) {
const pal = usePalette('default')
return (
{sanitizeDisplayName(
profile.displayName || sanitizeHandle(profile.handle),
moderation.ui('displayName'),
)}
{sanitizeHandle(profile.handle, '@')}
)
}
export function DesktopSearch() {
const {_} = useLingui()
const pal = usePalette('default')
const navigation = useNavigation()
const searchDebounceTimeout = React.useRef(
undefined,
)
const [isActive, setIsActive] = React.useState(false)
const [isFetching, setIsFetching] = React.useState(false)
const [query, setQuery] = React.useState('')
const [searchResults, setSearchResults] = React.useState<
AppBskyActorDefs.ProfileViewBasic[]
>([])
const moderationOpts = useModerationOpts()
const search = useActorAutocompleteFn()
const onChangeText = React.useCallback(
async (text: string) => {
setQuery(text)
if (text.length > 0) {
setIsFetching(true)
setIsActive(true)
if (searchDebounceTimeout.current)
clearTimeout(searchDebounceTimeout.current)
searchDebounceTimeout.current = setTimeout(async () => {
const results = await search({query: text})
if (results) {
setSearchResults(results)
setIsFetching(false)
}
}, 300)
} else {
if (searchDebounceTimeout.current)
clearTimeout(searchDebounceTimeout.current)
setSearchResults([])
setIsFetching(false)
setIsActive(false)
}
},
[setQuery, search, setSearchResults],
)
const onPressCancelSearch = React.useCallback(() => {
setQuery('')
setIsActive(false)
if (searchDebounceTimeout.current)
clearTimeout(searchDebounceTimeout.current)
}, [setQuery])
const onSubmit = React.useCallback(() => {
setIsActive(false)
if (!query.length) return
setSearchResults([])
if (searchDebounceTimeout.current)
clearTimeout(searchDebounceTimeout.current)
navigation.dispatch(StackActions.push('Search', {q: query}))
}, [query, navigation, setSearchResults])
const queryMaybeHandle = React.useMemo(() => {
const match = MATCH_HANDLE.exec(query)
return match && match[1]
}, [query])
return (
{query ? (
Cancel
) : undefined}
{query !== '' && isActive && moderationOpts && (
{isFetching ? (
) : (
<>
{queryMaybeHandle ? (
) : null}
{searchResults.map(item => (
))}
>
)}
)}
)
}
const styles = StyleSheet.create({
container: {
position: 'relative',
width: 300,
},
search: {
paddingHorizontal: 16,
paddingVertical: 2,
width: 300,
borderRadius: 20,
},
inputContainer: {
flexDirection: 'row',
},
iconWrapper: {
position: 'relative',
top: 2,
paddingVertical: 7,
marginRight: 8,
},
input: {
flex: 1,
fontSize: 18,
width: '100%',
paddingTop: 7,
paddingBottom: 7,
},
cancelBtn: {
paddingRight: 4,
paddingLeft: 10,
paddingVertical: 7,
},
resultsContainer: {
marginTop: 10,
flexDirection: 'column',
width: 300,
borderWidth: 1,
borderRadius: 6,
},
noResults: {
textAlign: 'center',
paddingVertical: 10,
},
})