import { useEffect, useState } from 'react' import { isAbortError } from '../lib/api' import { searchUsers } from '../services/userService' import type { UserSearchItem } from '../types/user' import styles from './UserSearchInput.module.css' const DEFAULT_MIN_CHARS = 2 export interface UserSearchInputProps { id?: string label?: string placeholder?: string disabled?: boolean minChars?: number selectedUser: UserSearchItem | null onSelect: (user: UserSearchItem | null) => void } export function UserSearchInput({ id = 'user-search', label = 'User', placeholder = 'Search by name, email, or phone', disabled = false, minChars = DEFAULT_MIN_CHARS, selectedUser, onSelect, }: UserSearchInputProps) { const [query, setQuery] = useState(selectedUser?.label ?? '') const [results, setResults] = useState([]) const [searching, setSearching] = useState(false) useEffect(() => { setQuery(selectedUser?.label ?? '') }, [selectedUser]) useEffect(() => { if (query.trim().length < minChars || selectedUser) { setResults([]) setSearching(false) return } const controller = new AbortController() const timer = setTimeout(() => { setSearching(true) void searchUsers(query.trim(), 20, controller.signal) .then((result) => { if (!controller.signal.aborted) setResults(result.items) }) .catch((err) => { if (!isAbortError(err) && !controller.signal.aborted) { setResults([]) } }) .finally(() => { if (!controller.signal.aborted) setSearching(false) }) }, 300) return () => { clearTimeout(timer) controller.abort() } }, [query, minChars, selectedUser]) const showDropdown = query.trim().length >= minChars && !selectedUser function handleQueryChange(value: string) { setQuery(value) if (selectedUser && value !== selectedUser.label) { onSelect(null) } } function pickUser(user: UserSearchItem) { onSelect(user) setQuery(user.label) setResults([]) } return (
handleQueryChange(e.target.value)} placeholder={placeholder} autoComplete="off" disabled={disabled} /> {showDropdown && (
{searching ? (
Searching...
) : results.length === 0 ? (
No users found.
) : ( results.map((user) => ( )) )}
)}
{query.trim().length > 0 && query.trim().length < minChars && (
Type at least {minChars} characters to search.
)} {selectedUser &&
Selected: {selectedUser.label}
}
) }