diff --git a/src/components/Input/index.tsx b/src/components/Input/index.tsx
index 453c742..ffd7caf 100644
--- a/src/components/Input/index.tsx
+++ b/src/components/Input/index.tsx
@@ -1,7 +1,8 @@
-import "./input.scss";
-import { fetchData } from "../../utils/fetch-data";
-import { debounce } from "../../utils/deboucne";
-import Loader from "../Loader";
+import './input.scss';
+import { fetchData } from '../../utils/fetch-data';
+import { debounce } from '../../utils/deboucne';
+import Loader from '../Loader';
+import { useRef, useState } from 'react';
export interface InputProps {
/** Placeholder of the input */
@@ -10,14 +11,112 @@ export interface InputProps {
onSelectItem: (item: string) => void;
}
+const Item = ({
+ name,
+ className,
+ onSelectItem
+}: {
+ name: string;
+ className: string;
+ onSelectItem: (item: string) => void;
+}) => (
+
onSelectItem(name)}>
+ {name}
+
+);
+
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 [result, setResult] = useState<{
+ items: string[];
+ error: string | null;
+ }>({
+ items: [],
+ error: null
+ });
+ const [isLoading, setIsLoading] = useState(false);
+ const [isOpen, setIsOpen] = useState(false);
+ const latestQuery = useRef('');
+
+ const handleChange = debounce(
+ async (e: React.ChangeEvent) => {
+ const query = e.target.value;
+ latestQuery.current = query;
+
+ if (query.length === 0) {
+ setIsOpen(false);
+ return;
+ }
+
+ try {
+ setIsOpen(true);
+ setIsLoading(true);
+ const names = await fetchData(query);
+
+ if (latestQuery.current !== query) return;
+
+ setResult({
+ items: names,
+ error: null
+ });
+ } catch (error: unknown) {
+ if (latestQuery.current !== query) return;
+ setResult({
+ items: [],
+ error: String(error).toString()
+ });
+ } finally {
+ if (latestQuery.current == query) {
+ setIsLoading(false);
+ }
+ }
+ },
+ 100
+ );
+ const { items, error } = result;
+
+ return (
+
+
+ {isOpen && (
+
+ {isLoading &&
}
+
+ {!isLoading && !error && items.length > 0 && (
+
+ {items.map((name) => (
+
+ ))}
+
+ )}
+ {!isLoading && items.length === 0 && !error && (
+
+ No results
+
+ )}
+ {!isLoading && error && (
+
+ {error}
+
+ )}
+
+ )}
+
+ );
// Your code end here
};
export default Input;
-
diff --git a/src/components/Input/input.scss b/src/components/Input/input.scss
index 1dafbe7..c2ec58a 100644
--- a/src/components/Input/input.scss
+++ b/src/components/Input/input.scss
@@ -1,6 +1,78 @@
* {
- box-sizing: border-box;
+ box-sizing: border-box;
}
-html{
- font-size: 16px;
+html {
+ font-size: 16px;
+}
+
+@mixin text-styles {
+ font-family: 'Roboto', sans-serif;
+ font-size: 16px;
+ color: #03183f;
+}
+@mixin header-styles {
+ font-family: 'Roboto', sans-serif;
+ font-size: 16px;
+ color: #03183f;
+}
+
+.container {
+ position: relative;
+ @include text-styles;
+}
+
+.input {
+ width: 500px;
+ height: 50px;
+ padding: 16px 24px;
+ border-radius: 5px;
+ color: #03183f;
+ border-color: #03183f6b;
+
+ font: 'Roboto', sans-serif;
+}
+
+.list-container {
+ position: absolute;
+ top: 100%;
+ left: 0;
+
+ margin-top: 8px;
+ border-radius: 5px;
+ border: 1px solid #03183f6b;
+
+ padding: 16px 0;
+ width: 100%;
+ min-height: 150px;
+ max-height: 400px;
+ overflow-y: auto;
+}
+
+.list {
+ @include text-styles;
+ padding: 0;
+ margin: 0;
+ list-style: none;
+}
+
+.item {
+ line-height: 1.6;
+ padding: 4px 24px;
+ &:hover {
+ background-color: rgb(158, 156, 156);
+ color: white;
+ cursor: pointer;
+ }
+}
+
+.no-result {
+ @include header-styles;
+ text-align: center;
+ padding: 4px 24px;
+}
+
+.error {
+ @include text-styles;
+ color: #c92c25;
+ padding: 4px 24px;
}