import { Bot, ResponseProps, Server } from '@types' import Fetch from '@utils/Fetch' import { makeBotURL, makeServerURL, redirectTo } from '@utils/Tools' import dynamic from 'next/dynamic' import Link from 'next/link' import { useRouter } from 'next/router' import { useEffect, useRef, useState } from 'react' import Day from '@utils/Day' import useOutsideClick from '@utils/useOutsideClick' const DiscordAvatar = dynamic(() => import('@components/DiscordAvatar')) const ServerIcon = dynamic(() => import('@components/ServerIcon')) interface SearchProps { compact?: boolean } const Search: React.FC = ({ compact = false }) => { const router = useRouter() const ref = useRef() const [query, setQuery] = useState('') const [recentSearch, setRecentSearch] = useState([]) const [data, setData] = useState>(null) const [loading, setLoading] = useState(false) const abortController = useRef(null) const [hidden, setHidden] = useState(true) useEffect(() => { setQuery('') setData(null) setLoading(false) try { setRecentSearch(JSON.parse(localStorage.recentSearch)) } catch { setRecentSearch([]) } }, [router]) useOutsideClick(ref, () => setHidden(true)) useEffect(() => { if (query.length < 2) { setData(null) return } const timeout = setTimeout(async () => { setData(null) try { if (abortController.current) { abortController.current.abort() } } catch (e) { return null } abortController.current = new AbortController() if (query.length > 1) setLoading(true) const res = await Fetch(`/search/all?q=${encodeURIComponent(query)}`, { signal: abortController.current.signal, }).catch((e) => { if (e.name !== 'AbortError') throw e else return }) abortController.current = null setData(res || {}) setLoading(false) }, 1000) return () => { clearTimeout(timeout) try { abortController.current?.abort() abortController.current = null } catch (e) { return null } } }, [query]) const onSubmit = () => { if (query.length < 2) return if (!localStorage.recentSearch) localStorage.recentSearch = '[]' try { const d = JSON.parse(localStorage.recentSearch).reverse() if (d.findIndex((n) => n.value === query) !== -1) d.splice( d.findIndex((n) => n.value === query), 1 ) d.push({ value: query, date: Date.now(), }) d.reverse() setRecentSearch(d.slice(0, 10)) localStorage.recentSearch = JSON.stringify(d.slice(0, 10)) } catch { setRecentSearch([ { value: query, date: Date.now(), }, ]) localStorage.recentSearch = JSON.stringify(recentSearch) } finally { redirectTo(router, `/search/?q=${encodeURIComponent(query)}`) } } return (
setHidden(false)} ref={ref}>
{ setQuery(e.target.value) }} onKeyDown={(e) => { if (e.key === 'Enter') { onSubmit() } }} />
    {data && data.code === 200 ? (
    • {data.data.bots.length === 0 ? (
    • 검색 결과가 없습니다.
    • ) : ( data.data.bots.map((el) => (
    • {el.name}

      {el.intro}

    • )) )}
    • 서버
    • {data.data.servers.length === 0 ? (
    • 검색 결과가 없습니다.
    • ) : ( data.data.servers.map((el) => (
    • {el.name}

      {el.intro}

    • )) )}
    ) : loading ? (
    • 검색중입니다...
    ) : (
      {query && data ? ( data.message?.includes('문법') ? (
    • 검색 문법이 잘못되었습니다.
      더 알아보기
    • ) : (
    • {(data.errors && data.errors[0]) || data.message || '검색중입니다...'}
    • ) ) : query.length === 0 ? ( !recentSearch || !Array.isArray(recentSearch) || recentSearch.length === 0 ? (
    • 최근 검색 기록이 없습니다.
    • ) : ( <>
    • 최근 검색어
    • {recentSearch.slice(0, 10).map((el, n) => (
    • {el?.value} {Day(el?.date).format('MM.DD.')}
    • ))} ) ) : query.length < 2 ? ( '최소 2글자 이상 입력해주세요.' ) : ( '검색어를 입력해주세요.' )}
    )}
) } export default Search interface ListAll { bots: Bot[] servers: Server[] }