import { css, cx, keyframes } 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'
import { useTranslation } from 'react-i18next'
const bounce = keyframes`
from { transform: rotate(0deg) translateX(1px) rotate(0deg) }
to { transform: rotate(360deg) translateX(1px) rotate(-360deg) }
`
function SearchIcon({ isSearching }: { isSearching: boolean }) {
return (
)
}
const SearchSuggestions = ({
searchText,
isInputFocused,
}: {
searchText: string
isInputFocused: boolean
}) => {
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 (
{isInputFocused &&
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('')
const [isFocused, setIsFocused] = useState(false)
const { t } = useTranslation()
const inputRef = useRef(null)
return (
)
}
export default SearchBox