Spaces:
Running
Running
import { useState } from "react"; | |
import { ChevronDown, Filter, Calendar } from "lucide-react"; | |
interface SemesterFilterProps { | |
dates: string[]; | |
onFilterChange?: (semesterId: string) => void; | |
} | |
interface SemesterOption { | |
id: string; | |
label: string; | |
description: string; | |
} | |
export default function SemesterFilter({ | |
dates, | |
onFilterChange, | |
}: SemesterFilterProps) { | |
const [semesterFilter, setSemesterFilter] = useState("all"); | |
const [isFilterOpen, setIsFilterOpen] = useState(false); | |
// Extract unique academic years from dates | |
const extractAcademicYears = (dates: string[]): string[] => { | |
const yearSet = new Set<string>(); | |
dates.forEach((dateStr) => { | |
const date = new Date(dateStr); | |
const year = date.getFullYear(); | |
const month = date.getMonth() + 1; | |
let startYear: number; | |
if (month >= 9) { | |
// Odd semester: starts in September | |
startYear = year; | |
} else { | |
// Even semester: January–August of next year | |
startYear = year - 1; | |
} | |
const academicYear = `${startYear}/${startYear + 1}`; | |
yearSet.add(academicYear); | |
}); | |
if (yearSet.size === 0) { | |
const currentYear = new Date().getFullYear(); | |
yearSet.add(`${currentYear - 2}/${currentYear - 1}`); | |
yearSet.add(`${currentYear - 1}/${currentYear}`); | |
yearSet.add(`${currentYear}/${currentYear + 1}`); | |
} | |
return Array.from(yearSet).sort((a, b) => (a > b ? -1 : 1)); | |
}; | |
const academicYears = extractAcademicYears(dates); | |
// Generate semester options | |
const semesterOptions: SemesterOption[] = []; | |
academicYears.forEach((academicYear) => { | |
const [startYear, endYear] = academicYear.split("/"); | |
semesterOptions.push({ | |
id: `odd-${academicYear}`, | |
label: `Ganjil ${academicYear}`, | |
description: `September ${startYear} - January ${endYear}`, | |
}); | |
semesterOptions.push({ | |
id: `even-${academicYear}`, | |
label: `Genap ${academicYear}`, | |
description: `February - August ${endYear}`, | |
}); | |
}); | |
const handleFilterClick = () => { | |
setIsFilterOpen(!isFilterOpen); | |
}; | |
const handleSemesterSelect = (semesterId: string) => { | |
setSemesterFilter(semesterId); | |
setIsFilterOpen(false); | |
if (onFilterChange) { | |
onFilterChange(semesterId); | |
} | |
}; | |
const getCurrentFilterText = () => { | |
if (semesterFilter === "all") return "All Semesters"; | |
const selectedSemester = semesterOptions.find( | |
(option) => option.id === semesterFilter, | |
); | |
return selectedSemester ? selectedSemester.label : "All Semesters"; | |
}; | |
return ( | |
<div className="relative"> | |
{/* Filter Button */} | |
<button | |
onClick={handleFilterClick} | |
className="flex items-center gap-2 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm hover:bg-gray-50" | |
> | |
<Filter className="h-4 w-4" /> | |
<Calendar className="h-4 w-4" /> | |
<span>{getCurrentFilterText()}</span> | |
<ChevronDown className="h-4 w-4" /> | |
</button> | |
{/* Dropdown Menu */} | |
{isFilterOpen && ( | |
<div className="absolute z-50 mt-2 min-w-[240px] rounded-md border border-gray-200 bg-white shadow-lg"> | |
<div className="py-1"> | |
{/* All Semesters */} | |
<div | |
onClick={() => handleSemesterSelect("all")} | |
className={`cursor-pointer px-4 py-2 hover:bg-gray-100 ${ | |
semesterFilter === "all" ? "bg-blue-50 text-blue-600" : "" | |
}`} | |
> | |
All Semesters | |
</div> | |
<div className="my-1 border-t border-gray-200" /> | |
{/* Semester Options Grouped by Academic Year */} | |
{academicYears.map((year, yearIndex) => ( | |
<div key={year}> | |
{yearIndex > 0 && ( | |
<div className="my-1 border-t border-gray-200" /> | |
)} | |
<div className="px-4 py-2 text-xs font-semibold text-gray-500"> | |
Academic Year {year} | |
</div> | |
{/* Odd Semester */} | |
<div | |
onClick={() => handleSemesterSelect(`odd-${year}`)} | |
className={`cursor-pointer px-4 py-2 hover:bg-gray-100 ${ | |
semesterFilter === `odd-${year}` | |
? "bg-blue-50 text-blue-600" | |
: "" | |
}`} | |
> | |
<div className="font-medium">Ganjil {year}</div> | |
<div className="text-xs text-gray-500"> | |
September - January | |
</div> | |
</div> | |
{/* Even Semester */} | |
<div | |
onClick={() => handleSemesterSelect(`even-${year}`)} | |
className={`cursor-pointer px-4 py-2 hover:bg-gray-100 ${ | |
semesterFilter === `even-${year}` | |
? "bg-blue-50 text-blue-600" | |
: "" | |
}`} | |
> | |
<div className="font-medium">Genap {year}</div> | |
<div className="text-xs text-gray-500">February - August</div> | |
</div> | |
</div> | |
))} | |
</div> | |
</div> | |
)} | |
</div> | |
); | |
} | |