Spaces:
Sleeping
Sleeping
| 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" /> | |
| <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> | |
| ); | |
| } | |