@@ -4,7 +4,7 @@ import { H1 } from "@/components/shared/dashboard";
44import { ExperienceRanges , NewApplicantType } from "../_service/types" ;
55import ApplicantFiltersComponent from "./applicantFilters" ;
66import ApplicantFiltersBadge from "./applicantFiltersBadge" ;
7- import ApplicantSorters from "./applicantSorters" ;
7+ import ApplicantSorters , { SortOption } from "./applicantSorters" ;
88
99export type ApplicantFilters = {
1010 hasPortfolio : boolean ;
@@ -63,8 +63,35 @@ export default function ApplicantFilterHeaders({
6363
6464 const [ sortField , setSortField ] = useState < string | null > ( null ) ;
6565 const [ sortDirection , setSortDirection ] = useState < "asc" | "desc" > ( "desc" ) ;
66+ const [ sortOptions , setSortOptions ] = useState < SortOption [ ] > ( [ ] ) ;
67+
68+ // Add a new sort option
69+ const addSort = useCallback ( ( field : string , label : string ) => {
70+ setSortOptions ( prev => [ ...prev , { field, direction : "desc" , label } ] ) ;
71+ } , [ ] ) ;
72+
73+ // Remove a sort option
74+ const removeSort = useCallback ( ( field : string ) => {
75+ setSortOptions ( prev => prev . filter ( option => option . field !== field ) ) ;
76+ } , [ ] ) ;
77+
78+ // Toggle sort direction for a specific field
79+ const toggleSortDirection = useCallback ( ( field : string ) => {
80+ setSortOptions ( prev =>
81+ prev . map ( option =>
82+ option . field === field
83+ ? { ...option , direction : option . direction === "asc" ? "desc" : "asc" }
84+ : option
85+ )
86+ ) ;
87+ } , [ ] ) ;
88+
89+ // Reorder sort options (for priority)
90+ const reorderSorts = useCallback ( ( newSortOptions : SortOption [ ] ) => {
91+ setSortOptions ( newSortOptions ) ;
92+ } , [ ] ) ;
6693
67- // Toggle sort
94+ // Legacy toggle sort function (for backward compatibility)
6895 const toggleSort = useCallback (
6996 ( field : string ) => {
7097 if ( sortField === field ) {
@@ -240,7 +267,65 @@ export default function ApplicantFilterHeaders({
240267 } ) ;
241268
242269 // Apply sorting
243- if ( sortField ) {
270+ if ( sortOptions . length > 0 ) {
271+ filteredApplicants . sort ( ( a , b ) => {
272+ // Apply multiple sorts in priority order
273+ for ( const sortOption of sortOptions ) {
274+ let valueA : any , valueB : any ;
275+
276+ switch ( sortOption . field ) {
277+ case "name" :
278+ valueA = `${ a . first_name || "" } ${ a . last_name || "" } ` . toLowerCase ( ) ;
279+ valueB = `${ b . first_name || "" } ${ b . last_name || "" } ` . toLowerCase ( ) ;
280+ break ;
281+ case "position" :
282+ valueA = ( a . display_position || "" ) . toLowerCase ( ) ;
283+ valueB = ( b . display_position || "" ) . toLowerCase ( ) ;
284+ break ;
285+ case "experience" :
286+ valueA = a . years_of_experience || 0 ;
287+ valueB = b . years_of_experience || 0 ;
288+ break ;
289+ case "dateApplied" :
290+ valueA = a . date_applied ? new Date ( a . date_applied ) . getTime ( ) : 0 ;
291+ valueB = b . date_applied ? new Date ( b . date_applied ) . getTime ( ) : 0 ;
292+ break ;
293+ case "testTaken" :
294+ valueA = a . applicant ?. test_taken ? new Date ( a . applicant . test_taken ) . getTime ( ) : 0 ;
295+ valueB = b . applicant ?. test_taken ? new Date ( b . applicant . test_taken ) . getTime ( ) : 0 ;
296+ break ;
297+ case "reminderCount" :
298+ valueA = a . applicant ?. reminded_count || 0 ;
299+ valueB = b . applicant ?. reminded_count || 0 ;
300+ break ;
301+ case "techStackCount" :
302+ valueA = a . tech_stacks ?. length || 0 ;
303+ valueB = b . tech_stacks ?. length || 0 ;
304+ break ;
305+ default :
306+ continue ; // Skip unknown fields
307+ }
308+
309+ let comparison = 0 ;
310+
311+ // For numeric values
312+ if ( typeof valueA === "number" && typeof valueB === "number" ) {
313+ comparison = sortOption . direction === "asc" ? valueA - valueB : valueB - valueA ;
314+ } else {
315+ // For string values
316+ if ( valueA < valueB ) comparison = sortOption . direction === "asc" ? - 1 : 1 ;
317+ else if ( valueA > valueB ) comparison = sortOption . direction === "asc" ? 1 : - 1 ;
318+ }
319+
320+ // If this sort criteria produces a difference, return it
321+ if ( comparison !== 0 ) return comparison ;
322+ }
323+
324+ // If all sort criteria are equal, maintain original order
325+ return 0 ;
326+ } ) ;
327+ } else if ( sortField ) {
328+ // Legacy single sort fallback
244329 filteredApplicants . sort ( ( a , b ) => {
245330 let valueA : any , valueB : any ;
246331
@@ -295,7 +380,7 @@ export default function ApplicantFilterHeaders({
295380 }
296381
297382 setApplicants ( filteredApplicants ) ;
298- } , [ filters , sortField , sortDirection , searchTerm , applicants ] ) ;
383+ } , [ filters , sortOptions , sortField , sortDirection , searchTerm , applicants ] ) ;
299384
300385 const activeFilterCount = useMemo ( ( ) => {
301386 let count = 0 ;
@@ -473,6 +558,7 @@ export default function ApplicantFilterHeaders({
473558 const resetSort = ( ) => {
474559 setSortField ( null ) ;
475560 setSortDirection ( "desc" ) ;
561+ setSortOptions ( [ ] ) ;
476562 } ;
477563
478564 return (
@@ -493,9 +579,11 @@ export default function ApplicantFilterHeaders({
493579 />
494580 < div className = "flex items-center justify-center gap-3" >
495581 < ApplicantSorters
496- sortField = { sortField }
497- sortDirection = { sortDirection }
498- onToggleSort = { toggleSort }
582+ sortOptions = { sortOptions }
583+ onAddSort = { addSort }
584+ onRemoveSort = { removeSort }
585+ onToggleSortDirection = { toggleSortDirection }
586+ onReorderSorts = { reorderSorts }
499587 resetSort = { resetSort }
500588 />
501589 < ApplicantFiltersComponent
@@ -525,9 +613,11 @@ export default function ApplicantFilterHeaders({
525613 className = "h-11 w-full max-w-80 rounded-lg border border-gray-300 bg-gray-50 px-4 text-sm text-gray-900 placeholder-gray-500 focus:border-customBlue-500 focus:outline-none focus:ring-1 focus:ring-customBlue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-customBlue-400 dark:focus:ring-customBlue-400"
526614 />
527615 < ApplicantSorters
528- sortField = { sortField }
529- sortDirection = { sortDirection }
530- onToggleSort = { toggleSort }
616+ sortOptions = { sortOptions }
617+ onAddSort = { addSort }
618+ onRemoveSort = { removeSort }
619+ onToggleSortDirection = { toggleSortDirection }
620+ onReorderSorts = { reorderSorts }
531621 resetSort = { resetSort }
532622 />
533623 < ApplicantFiltersComponent
0 commit comments