From 1992443b4ef8a05888d890751c2a137fb53a6a59 Mon Sep 17 00:00:00 2001 From: Nam Le Date: Sat, 5 Oct 2024 08:06:13 +0700 Subject: [PATCH 1/3] add input search component --- src/components/Input/index.tsx | 55 +++++++++++++++++++++++++++++++-- src/components/Input/input.scss | 29 +++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/components/Input/index.tsx b/src/components/Input/index.tsx index 453c742..69e5fef 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 { useRef, useState } from "react"; export interface InputProps { /** Placeholder of the input */ @@ -9,13 +10,63 @@ export interface InputProps { /** On click item handler */ onSelectItem: (item: string) => void; } - +export enum InputState { + INITITAL = 'initital', + FETCHING = 'fetching', + SUCCESS = 'success', + ERROR = 'error', +} const Input = ({ placeholder, onSelectItem }: InputProps) => { // DO NOT remove this log console.log('input re-render') // Your code start here - return + const [status, setStatus] = useState(InputState.INITITAL); + const [data, setData] = useState(); + const [error, setError] = useState(''); + + const lastTimeID = useRef(0); + + const searchText = async (query: string) => { + if(!query) { + setStatus(InputState.INITITAL); + setData([]); + setError(''); + lastTimeID.current = 0; + return; + } + const currentTime = new Date().getTime(); + lastTimeID.current = currentTime; + try { + if(status !== InputState.FETCHING) { + setStatus(InputState.FETCHING); + } + const response = await fetchData(query); + + if(lastTimeID.current !== currentTime) return; + + setData(response); + setStatus(InputState.SUCCESS); + + } catch (error) { + if(lastTimeID.current !== currentTime) return; + + setStatus(InputState.ERROR); + setError(error as string) + } + } + const handleChange = (event: React.ChangeEvent) => debounce(searchText(event.target.value), 100) + + return
+ + {status !== InputState.INITITAL &&
+ {status === InputState.FETCHING && } + {status === InputState.ERROR &&
{error}
} + {status === InputState.SUCCESS &&
+ {!!data?.length ? data.map((item, index) =>
onSelectItem(item)}>{item}
) : 'No results'} +
} +
} +
// Your code end here }; diff --git a/src/components/Input/input.scss b/src/components/Input/input.scss index 1dafbe7..884f750 100644 --- a/src/components/Input/input.scss +++ b/src/components/Input/input.scss @@ -4,3 +4,32 @@ html{ font-size: 16px; } +.search-container { + width: 320px; + &__input { + width: 100%; + font-size: 16px; + padding: 12px; + border-radius: 4px; + border: 1px solid #2d3436; + } + &__content { + padding: 12px; + margin-top: 8px; + position: relative; + border: 1px solid #dfe6e9; + border-radius: 4px; + min-height: 80px; + text-align: left; + } + &__result { + display: flex; + flex-direction: column; + gap: 8px; + justify-content: center; + } + &__error { + color: #d63031; + } + +} From 5bb94e65d7a7dea8f4089aa1b24a9765d5c2210f Mon Sep 17 00:00:00 2001 From: Nam Le Date: Mon, 7 Oct 2024 09:51:57 +0700 Subject: [PATCH 2/3] update typescript --- src/components/Input/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Input/index.tsx b/src/components/Input/index.tsx index 69e5fef..3b3db12 100644 --- a/src/components/Input/index.tsx +++ b/src/components/Input/index.tsx @@ -27,7 +27,8 @@ const Input = ({ placeholder, onSelectItem }: InputProps) => { const lastTimeID = useRef(0); - const searchText = async (query: string) => { + const handleChange = debounce(async (event: React.ChangeEvent) => { + const query = event.target.value; if(!query) { setStatus(InputState.INITITAL); setData([]); @@ -54,8 +55,7 @@ const Input = ({ placeholder, onSelectItem }: InputProps) => { setStatus(InputState.ERROR); setError(error as string) } - } - const handleChange = (event: React.ChangeEvent) => debounce(searchText(event.target.value), 100) + }, 100) return
From f23a97020f2ae4b1f1dfbcae8a22a56e2c1207d8 Mon Sep 17 00:00:00 2001 From: Nam Le Date: Mon, 7 Oct 2024 14:03:39 +0700 Subject: [PATCH 3/3] add style list items --- src/components/Input/index.tsx | 2 +- src/components/Input/input.scss | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/Input/index.tsx b/src/components/Input/index.tsx index 3b3db12..aad9ecd 100644 --- a/src/components/Input/index.tsx +++ b/src/components/Input/index.tsx @@ -63,7 +63,7 @@ const Input = ({ placeholder, onSelectItem }: InputProps) => { {status === InputState.FETCHING && } {status === InputState.ERROR &&
{error}
} {status === InputState.SUCCESS &&
- {!!data?.length ? data.map((item, index) =>
onSelectItem(item)}>{item}
) : 'No results'} + {!!data?.length ? data.map((item, index) =>
onSelectItem(item)}>{item}
) : 'No results'}
}
} diff --git a/src/components/Input/input.scss b/src/components/Input/input.scss index 884f750..92e905f 100644 --- a/src/components/Input/input.scss +++ b/src/components/Input/input.scss @@ -14,7 +14,6 @@ html{ border: 1px solid #2d3436; } &__content { - padding: 12px; margin-top: 8px; position: relative; border: 1px solid #dfe6e9; @@ -31,5 +30,13 @@ html{ &__error { color: #d63031; } + &__item { + cursor: pointer; + padding: 12px; + &:hover { + background: #34495e; + color: white; + } + } }