diff --git a/src/components/common/SearchUserInput.tsx b/src/components/common/SearchUserInput.tsx index 2315c8aa..06ed0583 100644 --- a/src/components/common/SearchUserInput.tsx +++ b/src/components/common/SearchUserInput.tsx @@ -1,29 +1,85 @@ +import { useCallback, useEffect, useRef } from 'react'; import { IoSearch } from 'react-icons/io5'; +import { findUser } from '@services/userService'; +import { findUserByTeam } from '@services/teamService'; +import { findUserByProject } from '@services/projectService'; + import type { SearchUser } from '@/types/UserType'; +type FetchCallback = T extends (...arg: infer P) => void ? (...arg: P) => Promise : never; + +type AllSearchCallback = { + type: 'ALL'; + searchCallback: FetchCallback; +}; + +type TeamSearchCallback = { + type: 'TEAM'; + searchCallback: FetchCallback; +}; + +type ProjectSearchCallback = { + type: 'PROJECT'; + searchCallback: FetchCallback; +}; + +type SearchCallback = AllSearchCallback | TeamSearchCallback | ProjectSearchCallback; + type SearchInputProps = { id: string; label: string; keyword: string; + searchId: number; loading: boolean; userList: SearchUser[]; + searchCallbackInfo: SearchCallback; onKeywordChange: (event: React.ChangeEvent) => void; - onSearchKeyup: (event: React.KeyboardEvent) => void; - onSearchClick: () => void; onUserClick: (user: SearchUser) => void; }; export default function SearchUserInput({ id, label, + searchId, keyword, loading, userList, + searchCallbackInfo, onKeywordChange: handleKeywordChange, - onSearchKeyup: handleSearchKeyUp, - onSearchClick: handleSearchClick, onUserClick: handleUserClick, }: SearchInputProps) { + const debounceRef = useRef(null); + const abortControllerRef = useRef(null); + + const searchUsers = useCallback(() => { + if (debounceRef.current) clearTimeout(debounceRef.current); + if (abortControllerRef.current) abortControllerRef.current.abort(); + + abortControllerRef.current = new AbortController(); + const { signal } = abortControllerRef.current; + + const { type, searchCallback } = searchCallbackInfo; + + if (type === 'ALL') searchCallback(keyword, { signal }); + else searchCallback(searchId, keyword, { signal }); + }, [searchCallbackInfo, searchId, keyword]); + + useEffect(() => { + if (keyword) debounceRef.current = setTimeout(() => searchUsers(), 500); + return () => { + if (debounceRef.current) clearTimeout(debounceRef.current); + if (abortControllerRef.current) abortControllerRef.current.abort(); + }; + }, [searchUsers, keyword]); + + const handleSearchClick = () => searchUsers(); + const handleSearchKeyUp = (e: React.KeyboardEvent) => { + if (e.key.toLowerCase() === 'enter') { + e.preventDefault(); + searchUsers(); + } + }; + return (