diff --git a/components/CollapsibleSearch.tsx b/components/CollapsibleSearch.tsx index de3edac..c964e46 100644 --- a/components/CollapsibleSearch.tsx +++ b/components/CollapsibleSearch.tsx @@ -1,65 +1,125 @@ -import { FormEvent, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import Image from "next/image"; import Router from "next/router"; import styles from "../styles/CollapsibleSearch.module.css"; +import { ReceivedArticle } from "../ts_types/db_types"; const CollapsibleSearch = () => { - const [searchValue, setSearchValue] = useState(""); - const [searchBar, setSearchBar] = useState(false); - const textInput = useRef(null); - - const onSearchBlur = () => { - setSearchBar(false); - }; - - const onSearchFocus = () => { - setSearchBar(true); - - // Set timeout for 1ms to focus text input AFTER it renders - setTimeout(() => { - textInput.current?.focus(); - }, 1); - }; - function submitSearchRequest(e: FormEvent) { - e.preventDefault(); - Router.push(String("/search?query=" + searchValue)); - } - - return ( -
-
-
- Search -
- setSearchValue(e.target.value)} - onBlur={onSearchBlur} - ref={textInput} - /> -
-
- ); + const [searchValue, setSearchValue] = useState(""); + const [searchBar, setSearchBar] = useState(false); + const [suggestions, setSuggestions] = useState([]); + const textInput = useRef(null); + + const onSearchBlur = () => { + setSearchBar(false); + setSuggestions([]); + }; + + const onSearchFocus = () => { + setSearchBar(true); + }; + + const onInputChange = async (e: React.ChangeEvent) => { + const value = e.target.value; + setSearchValue(value); + + const newSuggestions = await getSuggestions(value); + setSuggestions(newSuggestions); + }; + + const onSuggestionClick = (suggestion: ReceivedArticle) => { + setSearchValue(suggestion.title); + setSuggestions([]); + setSearchBar(true); + textInput.current?.focus(); + + Router.push(`/article/`); + }; + + + const submitSearchRequest = (e: React.FormEvent) => { + e.preventDefault(); + Router.push(`/search?query=${searchValue}`); + }; + + const getSuggestionList = () => { + return ( +
+ {suggestions.map((suggestion, index) => ( +
onSuggestionClick(suggestion)} + > + {suggestion.title} +
+ ))} +
+ ); + }; + + useEffect(() => { + const handleRouteChange = () => { + setSearchBar(false); + setSuggestions([]); + }; + + Router.events.on("routeChangeComplete", handleRouteChange); + + return () => { + Router.events.off("routeChangeComplete", handleRouteChange); + }; + }, []); + + const getSuggestions = async (input: string) => { + if (!input){ + return []; + } + + const request = await fetch(`/api/articles/search?q=${input}&max=5`); + const rjson = await request.json() + if (!rjson.articles){ + throw new Error("Articles were not returned from search"); + } + const articles = rjson.articles as ReceivedArticle[]; + + return articles; + }; + + return ( +
+
+
+ Search +
+
+ + {suggestions.length > 0 && getSuggestionList()} +
+
+
+ ); }; export default CollapsibleSearch;