Skip to content

Commit f90db51

Browse files
committed
improve applicant sorting
1 parent 91b04e3 commit f90db51

2 files changed

Lines changed: 303 additions & 124 deletions

File tree

‎apps/codebility/app/home/applicants/_components/applicantHeaders.tsx‎

Lines changed: 100 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { H1 } from "@/components/shared/dashboard";
44
import { ExperienceRanges, NewApplicantType } from "../_service/types";
55
import ApplicantFiltersComponent from "./applicantFilters";
66
import ApplicantFiltersBadge from "./applicantFiltersBadge";
7-
import ApplicantSorters from "./applicantSorters";
7+
import ApplicantSorters, { SortOption } from "./applicantSorters";
88

99
export 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

Comments
 (0)