diff --git a/src/components/Input/index.tsx b/src/components/Input/index.tsx index 453c742..a647831 100644 --- a/src/components/Input/index.tsx +++ b/src/components/Input/index.tsx @@ -2,6 +2,7 @@ import "./input.scss"; import { fetchData } from "../../utils/fetch-data"; import { debounce } from "../../utils/deboucne"; import Loader from "../Loader"; +import { useEffect, useState } from "react"; export interface InputProps { /** Placeholder of the input */ @@ -10,14 +11,128 @@ export interface InputProps { onSelectItem: (item: string) => void; } +export interface IListItemProps { + onSelectItem: (item: string) => void; + searchValue: string; +} + +const SearchItem = ({ onSelectItem, searchValue }: IListItemProps) => { + return ( +
  • + +
  • + ); +}; + const Input = ({ placeholder, onSelectItem }: InputProps) => { // DO NOT remove this log - console.log('input re-render') + console.log("input re-render"); // Your code start here - return + const [inputValue, setInputValue] = useState(''); + const [searchResults, setSearchReullt] = useState<{ + searchResults: string[]; + errorMessage: string; + }>({ + searchResults: [], + errorMessage: '', + }); + const [isLoading, setIsLoading] = useState(false); + const handleInputChange = debounce( + async (event: React.ChangeEvent) => { + setInputValue(event.target.value); + }, + 100 + ); + + useEffect(() => { + if (!inputValue) return; + + setIsLoading(true); + let isMounted = true; + const getSearchResults = async () => { + try { + const response = await fetchData(inputValue); + + if (!isMounted) return; + + if (response && response.length > 0) { + setSearchReullt({ + searchResults: response, + errorMessage: '' + }); + return; + } + + setSearchReullt({ + searchResults: [], + errorMessage: 'No result found', + }); + } catch(error) { + setSearchReullt({ + searchResults: [], + errorMessage: error as unknown as string + }); + } finally { + if (isMounted) { + setIsLoading(false) + } + } + + } + + getSearchResults(); + + return () => { + isMounted = false; + } + }, [inputValue]) + + return ( +
    + + {inputValue && ( +
    + {isLoading && } + {!isLoading && searchResults.searchResults && searchResults.searchResults.length > 0 && ( +
    +
      + {searchResults.searchResults && + searchResults.searchResults.map((results, index) => { + return ( + + ); + })} +
    +
    + )} + { + !isLoading && searchResults.searchResults && searchResults.searchResults.length === 0 && ( +
    + {searchResults.errorMessage} +
    + ) + } +
    + )} +
    + ); // Your code end here }; export default Input; - diff --git a/src/components/Input/input.scss b/src/components/Input/input.scss index 1dafbe7..d175b51 100644 --- a/src/components/Input/input.scss +++ b/src/components/Input/input.scss @@ -4,3 +4,51 @@ html{ font-size: 16px; } + +.input-search { + &__input { + border-radius: 4px; + line-height: 1.5em; + font-size: 16px; + padding: .5em 1em; + width: 100%; + } + + &__search-results-wrapper { + width: 100%; + position: relative; + border-radius: 4px; + min-height: 100px; + border: solid 1px #ddd; + margin-top: 4px; + } + + &__error-message { + color: red; + font-style: italic; + padding: .5em 1em; + } + + &__search-item { + list-style-type: none; + font-size: 16px; + text-align: center; + padding: 1em 2em; + cursor: pointer; + + &:hover { + background-color: #eee; + } + } + + &__item { + background-color: inherit; + outline: none; + border: none + } + + &__list-item { + padding: 0; + margin: 0 + } +}