@@ -7,9 +7,9 @@ import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover
77import { DropdownMenu , DropdownMenuContent , DropdownMenuItem , DropdownMenuTrigger , DropdownMenuSeparator , DropdownMenuLabel } from '@/components/ui/dropdown-menu'
88import useDirDetection from '@/hooks/use-dir-detection'
99import { cn } from '@/lib/utils'
10- import { debounce } from 'es-toolkit '
10+ import { useDebouncedSearch } from '@/hooks/use-debounced-search '
1111import { RefreshCw , SearchIcon , Filter , X , ArrowUpDown , User , Calendar , ChartPie , ChevronDown , Check , Clock } from 'lucide-react'
12- import { useState , useRef , useEffect , useCallback } from 'react'
12+ import { useState , useEffect , useCallback } from 'react'
1313import { useTranslation } from 'react-i18next'
1414import { useGetUsers , UserStatus } from '@/service/api'
1515import { RefetchOptions } from '@tanstack/react-query'
@@ -86,10 +86,11 @@ interface FiltersProps {
8686export const Filters = ( { filters, onFilterChange, refetch, autoRefetch, advanceSearchOnOpen, onClearAdvanceSearch, handleSort } : FiltersProps ) => {
8787 const { t } = useTranslation ( )
8888 const dir = useDirDetection ( )
89- const [ search , setSearch ] = useState ( filters . search || '' )
9089 const [ isRefreshing , setIsRefreshing ] = useState ( false )
9190 const [ autoRefreshInterval , setAutoRefreshInterval ] = useState < number > ( ( ) => getUsersAutoRefreshIntervalSeconds ( ) )
9291 const { refetch : queryRefetch , isFetching } = useGetUsers ( filters )
92+ const { search, debouncedSearch, setSearch } = useDebouncedSearch ( filters . search || '' , 300 )
93+
9394 const refetchUsers = useCallback (
9495 async ( showLoading = false , isAutoRefresh = false ) => {
9596 if ( showLoading ) {
@@ -138,39 +139,23 @@ export const Filters = ({ filters, onFilterChange, refetch, autoRefetch, advance
138139 ? t ( 'autoRefresh.shortSeconds' , { count : autoRefreshInterval } )
139140 : t ( 'autoRefresh.shortMinutes' , { count : Math . round ( autoRefreshInterval / 60 ) } )
140141 const currentAutoRefreshDescription = t ( currentAutoRefreshOption . labelKey )
141- const onFilterChangeRef = useRef ( onFilterChange )
142142
143- // Keep the ref in sync with the prop
144- onFilterChangeRef . current = onFilterChange
145-
146- // Create debounced function using es-toolkit, stored in ref to avoid recreation
147- const debouncedFilterChangeRef = useRef (
148- debounce ( ( value : string ) => {
149- onFilterChangeRef . current ( {
150- search : value ,
151- offset : 0 ,
152- } )
153- } , 300 ) ,
154- )
155-
156- // Cleanup on unmount
143+ // Update filters when debounced search changes
157144 useEffect ( ( ) => {
158- return ( ) => {
159- debouncedFilterChangeRef . current . cancel ( )
160- }
161- } , [ ] )
145+ onFilterChange ( {
146+ search : debouncedSearch || '' ,
147+ offset : 0 ,
148+ } )
149+ } , [ debouncedSearch , onFilterChange ] )
162150
163151 // Handle input change
164152 const handleSearchChange = ( e : React . ChangeEvent < HTMLInputElement > ) => {
165- const value = e . target . value
166- setSearch ( value )
167- debouncedFilterChangeRef . current ( value )
153+ setSearch ( e . target . value )
168154 }
169155
170156 // Clear search field
171157 const clearSearch = ( ) => {
172158 setSearch ( '' )
173- debouncedFilterChangeRef . current . cancel ( )
174159 onFilterChange ( {
175160 search : '' ,
176161 offset : 0 ,
0 commit comments