@@ -4,10 +4,11 @@ import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, Pagi
44import { Select , SelectContent , SelectGroup , SelectItem , SelectTrigger , SelectValue } from '@/components/ui/select'
55import { Badge } from '@/components/ui/badge'
66import { Popover , PopoverContent , PopoverTrigger } from '@/components/ui/popover'
7+ import { DropdownMenu , DropdownMenuContent , DropdownMenuItem , DropdownMenuTrigger , DropdownMenuSeparator , DropdownMenuLabel } from '@/components/ui/dropdown-menu'
78import useDirDetection from '@/hooks/use-dir-detection'
89import { cn } from '@/lib/utils'
910import { debounce } from 'es-toolkit'
10- import { RefreshCw , SearchIcon , Filter , X } from 'lucide-react'
11+ import { RefreshCw , SearchIcon , Filter , X , ArrowUpDown , User , Calendar , ChartPie , ChevronDown } from 'lucide-react'
1112import { useCallback , useState } from 'react'
1213import { useTranslation } from 'react-i18next'
1314import { useGetUsers , UserStatus } from '@/service/api'
@@ -29,9 +30,10 @@ interface FiltersProps {
2930 advanceSearchOnOpen : ( status : boolean ) => void
3031 advanceSearchForm ?: UseFormReturn < any >
3132 onClearAdvanceSearch ?: ( ) => void
33+ handleSort ?: ( column : string ) => void
3234}
3335
34- export const Filters = ( { filters, onFilterChange, refetch, advanceSearchOnOpen, advanceSearchForm, onClearAdvanceSearch } : FiltersProps ) => {
36+ export const Filters = ( { filters, onFilterChange, refetch, advanceSearchOnOpen, advanceSearchForm, onClearAdvanceSearch, handleSort } : FiltersProps ) => {
3537 const { t } = useTranslation ( )
3638 const dir = useDirDetection ( )
3739 const [ search , setSearch ] = useState ( filters . search || '' )
@@ -132,6 +134,97 @@ export const Filters = ({ filters, onFilterChange, refetch, advanceSearchOnOpen,
132134 </ Popover >
133135 ) }
134136 </ div >
137+ { /* Sort Button */ }
138+ { handleSort && (
139+ < div className = "flex h-full items-center gap-1" >
140+ < DropdownMenu >
141+ < DropdownMenuTrigger asChild >
142+ < Button
143+ size = "icon-md"
144+ variant = "ghost"
145+ className = "relative flex items-center gap-2 border"
146+ aria-label = { t ( 'sortOptions' , { defaultValue : 'Sort Options' } ) }
147+ >
148+ < ArrowUpDown className = "h-4 w-4" />
149+ { filters . sort && filters . sort !== '-created_at' && (
150+ < div className = "absolute -right-1 -top-1 h-2 w-2 rounded-full bg-primary" />
151+ ) }
152+ </ Button >
153+ </ DropdownMenuTrigger >
154+ < DropdownMenuContent align = "end" className = "w-56" >
155+ { /* Username Section */ }
156+ < DropdownMenuLabel className = "flex items-center gap-2 text-xs text-muted-foreground" >
157+ < User className = "h-3 w-3" />
158+ { t ( 'username' ) }
159+ </ DropdownMenuLabel >
160+ < DropdownMenuItem
161+ onClick = { ( ) => handleSort && handleSort ( 'username' ) }
162+ className = { filters . sort === 'username' ? 'bg-accent' : '' }
163+ >
164+ < User className = "mr-2 h-4 w-4" />
165+ { t ( 'sort.username.asc' ) }
166+ { filters . sort === 'username' && < ChevronDown className = "ml-auto h-4 w-4 rotate-180" /> }
167+ </ DropdownMenuItem >
168+ < DropdownMenuItem
169+ onClick = { ( ) => handleSort && handleSort ( '-username' ) }
170+ className = { filters . sort === '-username' ? 'bg-accent' : '' }
171+ >
172+ < User className = "mr-2 h-4 w-4" />
173+ { t ( 'sort.username.desc' ) }
174+ { filters . sort === '-username' && < ChevronDown className = "ml-auto h-4 w-4" /> }
175+ </ DropdownMenuItem >
176+
177+ < DropdownMenuSeparator />
178+
179+ { /* Expire Date Section */ }
180+ < DropdownMenuLabel className = "flex items-center gap-2 text-xs text-muted-foreground" >
181+ < Calendar className = "h-3 w-3" />
182+ { t ( 'expireDate' ) }
183+ </ DropdownMenuLabel >
184+ < DropdownMenuItem
185+ onClick = { ( ) => handleSort && handleSort ( 'expire' ) }
186+ className = { filters . sort === 'expire' ? 'bg-accent' : '' }
187+ >
188+ < Calendar className = "mr-2 h-4 w-4" />
189+ { t ( 'sort.expire.oldest' ) }
190+ { filters . sort === 'expire' && < ChevronDown className = "ml-auto h-4 w-4 rotate-180" /> }
191+ </ DropdownMenuItem >
192+ < DropdownMenuItem
193+ onClick = { ( ) => handleSort && handleSort ( '-expire' ) }
194+ className = { filters . sort === '-expire' ? 'bg-accent' : '' }
195+ >
196+ < Calendar className = "mr-2 h-4 w-4" />
197+ { t ( 'sort.expire.newest' ) }
198+ { filters . sort === '-expire' && < ChevronDown className = "ml-auto h-4 w-4" /> }
199+ </ DropdownMenuItem >
200+
201+ < DropdownMenuSeparator />
202+
203+ { /* Data Usage Section */ }
204+ < DropdownMenuLabel className = "flex items-center gap-2 text-xs text-muted-foreground" >
205+ < ChartPie className = "h-3 w-3" />
206+ { t ( 'dataUsage' ) }
207+ </ DropdownMenuLabel >
208+ < DropdownMenuItem
209+ onClick = { ( ) => handleSort && handleSort ( 'used_traffic' ) }
210+ className = { filters . sort === 'used_traffic' ? 'bg-accent' : '' }
211+ >
212+ < ChartPie className = "mr-2 h-4 w-4" />
213+ { t ( 'sort.usage.low' ) }
214+ { filters . sort === 'used_traffic' && < ChevronDown className = "ml-auto h-4 w-4 rotate-180" /> }
215+ </ DropdownMenuItem >
216+ < DropdownMenuItem
217+ onClick = { ( ) => handleSort && handleSort ( '-used_traffic' ) }
218+ className = { filters . sort === '-used_traffic' ? 'bg-accent' : '' }
219+ >
220+ < ChartPie className = "mr-2 h-4 w-4" />
221+ { t ( 'sort.usage.high' ) }
222+ { filters . sort === '-used_traffic' && < ChevronDown className = "ml-auto h-4 w-4" /> }
223+ </ DropdownMenuItem >
224+ </ DropdownMenuContent >
225+ </ DropdownMenu >
226+ </ div >
227+ ) }
135228 { /* Refresh Button */ }
136229 < div className = "flex h-full items-center gap-2" >
137230 < Button size = "icon-md" onClick = { handleRefreshClick } variant = "ghost" className = "flex items-center gap-2 border" disabled = { isRefreshing } >
0 commit comments