import { css, cx } from '@emotion/css' import Icon from '../../Icon' import { breakpoint as bp } from '@/web/utils/const' import { useNavigate } from 'react-router-dom' import { useMemo, useState, useEffect, useRef } from 'react' import { useQuery } from '@tanstack/react-query' import { fetchSearchSuggestions } from '@/web/api/search' import { SearchApiNames } from '@/shared/api/Search' import { useClickAway, useDebounce } from 'react-use' import { AnimatePresence, motion } from 'framer-motion' const SearchSuggestions = ({ searchText }: { searchText: string }) => { const navigate = useNavigate() const [debouncedSearchText, setDebouncedSearchText] = useState('') useDebounce(() => setDebouncedSearchText(searchText), 500, [searchText]) const { data: suggestions } = useQuery( [SearchApiNames.FetchSearchSuggestions, debouncedSearchText], () => fetchSearchSuggestions({ keywords: debouncedSearchText }), { enabled: debouncedSearchText.length > 0, keepPreviousData: true, } ) const suggestionsArray = useMemo(() => { if (suggestions?.code !== 200) { return [] } const suggestionsArray: { name: string type: 'album' | 'artist' | 'track' id: number }[] = [] const rawItems = [ ...(suggestions.result.artists || []), ...(suggestions.result.albums || []), ...(suggestions.result.songs || []), ] rawItems.forEach(item => { const type = (item as Artist).albumSize ? 'artist' : (item as Track).duration ? 'track' : 'album' suggestionsArray.push({ name: item.name, type, id: item.id, }) }) return suggestionsArray }, [suggestions]) const [clickedSearchText, setClickedSearchText] = useState('') useEffect(() => { if (clickedSearchText !== searchText) { setClickedSearchText('') } }, [clickedSearchText, searchText]) const panelRef = useRef(null) useClickAway(panelRef, () => setClickedSearchText(searchText)) return ( {searchText.length > 0 && suggestionsArray.length > 0 && !clickedSearchText && searchText === debouncedSearchText && ( {suggestionsArray?.map(suggestion => (
{ setClickedSearchText(searchText) if (['album', 'artist'].includes(suggestion.type)) { navigate(`${suggestion.type}/${suggestion.id}`) } if (suggestion.type === 'track') { // TODO: play song } }} > {suggestion.type} -{suggestion.name}
))}
)}
) } const SearchBox = () => { const navigate = useNavigate() const [searchText, setSearchText] = useState('') return (
{/* Input */}
setSearchText(e.target.value)} onKeyDown={e => { if (e.key !== 'Enter') return e.preventDefault() navigate(`/search/${searchText}`) }} />
) } export default SearchBox