feat: add filters

This commit is contained in:
Nathan Lamy 2025-08-19 14:32:55 +02:00
parent cdc41c4a51
commit b4b74155c2
2 changed files with 105 additions and 149 deletions

View file

@ -1,15 +1,14 @@
import { DateTime } from "luxon";
import { useState, useEffect } from "react";
import { useState } from "react";
import { Button } from "~/components/ui/button";
import {
ChevronLeft,
ChevronRight,
Star,
Filter,
X,
Users,
User,
ArrowUpDown,
SortAsc,
SortDesc,
} from "lucide-react";
import {
Select,
@ -18,13 +17,7 @@ import {
SelectTrigger,
SelectValue,
} from "~/components/ui/select";
import { Label } from "~/components/ui/label";
import { Tabs, TabsList, TabsTrigger } from "~/components/ui/tabs";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "~/components/ui/collapsible";
import DatePickerWithRange from "~/components/home/date-picker";
import BottomNavigation from "~/components/home/bottom-nav";
import Error from "~/components/error";
@ -74,13 +67,6 @@ export default function Home() {
// Fetch colles from API
const { studentColles, classColles, favoriteColles, error, isLoading } =
useColles(startDate);
console.log("Colles loaded:", {
studentColles,
classColles,
favoriteColles,
error,
isLoading,
});
// Error handling (after all hooks)
if (error)
@ -95,30 +81,60 @@ export default function Home() {
// TODO: FAVORITES
const useToggleStar = (auth: any) => {};
// TODO: FILTERS
const getSessionFilter = (key: string) => {
const filter = sessionStorage.getItem(key);
if (filter) {
return filter;
}
return "all";
};
// Filter state
const rawSubject = query.get("subject");
const [subjectFilter, setSubjectFilter] = useState<string>(
getSessionFilter("subject")
rawSubject === "all" ? "" : rawSubject || ""
);
const setSubject = (subject: string) => {
updateQuery("subject", subject);
setSubjectFilter(subject);
};
const rawExaminer = query.get("examiner");
const [examinerFilter, setExaminerFilter] = useState<string>(
getSessionFilter("examiner")
rawExaminer === "all" ? "" : rawExaminer || ""
);
// const [studentFilter, setStudentFilter] = useState<string>("all")
const [isFilterOpen, setIsFilterOpen] = useState(
getSessionFilter("subject") !== "all" ||
getSessionFilter("examiner") !== "all"
const setExaminer = (examiner: string) => {
updateQuery("examiner", examiner);
setExaminerFilter(examiner);
};
const [sorted, setSort] = useState<string>(query.get("sort") || "desc");
const toggleSort = () => {
const newSort = sorted === "asc" ? "desc" : "asc";
updateQuery("sort", newSort);
setSort(newSort);
};
const keepUnique = (arr: any[]) => {
return [...new Set(arr)];
};
const subjects = keepUnique(classColles.map((colle) => colle.subject?.name));
const examiners = keepUnique(
classColles.map((colle) => colle.examiner?.name)
);
useEffect(() => {
sessionStorage.setItem("subject", subjectFilter);
sessionStorage.setItem("examiner", examinerFilter);
// sessionStorage.setItem('student', studentFilter)
}, [subjectFilter, examinerFilter]);
const applyFilters = (colles: any[]) => {
return colles
.filter((colle) => {
const subjectMatch =
subjectFilter === "all" || !subjectFilter
? true
: colle.subject?.name === subjectFilter;
const examinerMatch =
examinerFilter === "all" || !examinerFilter
? true
: colle.examiner?.name === examinerFilter;
return subjectMatch && examinerMatch;
})
.sort((a, b) => {
if (sorted === "asc") {
return a.date.localeCompare(b.date);
} else {
return b.date.localeCompare(a.date);
}
});
};
return (
<div className="space-y-6 pb-20 md:pb-0">
@ -164,118 +180,50 @@ export default function Home() {
</div>
{/* TODO: Filter component */}
<Collapsible open={isFilterOpen} onOpenChange={setIsFilterOpen}>
<div className="flex justify-between">
<div className="flex gap-2">
{activeTab === "class" && (
<>
<Button
variant="outline"
size="sm"
// TODO: Implement sorting
onClick={() => {}}
>
<ArrowUpDown className="h-4 w-4" />
</Button>
<div className="flex mb-4">
<CollapsibleTrigger asChild>
<Button variant="outline" size="sm">
{isFilterOpen ? (
<>
<X className="h-4 w-4 mr-2" />
Fermer
</>
) : (
<>
<Filter className="h-4 w-4 mr-2" />
Recherche
</>
)}
</Button>
</CollapsibleTrigger>
</div>
</>
)}
</div>
{/* TODO: DEBUG */}
{/* {activeTab === "all" &&
(getWeekStart().getTime() != startDate.getTime() ? (
<Button variant="outline" size="sm" onClick={resetWeek}>
<CalendarArrowUp className="h-4 w-4 mr-2" />
Cette semaine
</Button>
) : (
<Button variant="outline" size="sm" onClick={goPastYear}>
<CalendarArrowDown className="h-4 w-4 mr-2" />
Colles des spés
</Button>
))} */}
</div>
<div className="flex gap-1 pb-0 pt-2">
<Select value={subjectFilter} onValueChange={setSubject}>
<SelectTrigger className="rounded-full data-[placeholder]:text-primary">
<SelectValue placeholder="Matière" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">Toutes</SelectItem>
{subjects.map((subject) => (
<SelectItem key={subject} value={subject}>
{subject}
</SelectItem>
))}
</SelectContent>
</Select>
<CollapsibleContent className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="space-y-2">
<Label htmlFor="subject-filter">Filtrer par matière</Label>
<Select value={subjectFilter} onValueChange={setSubjectFilter}>
<SelectTrigger id="subject-filter">
<SelectValue placeholder="Toutes les matières" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">Toutes les matières</SelectItem>
{/* TODO: */}
{/* {uniqueTopics.map((subject) => (
<SelectItem key={subject} value={subject}>
{subject}
</SelectItem>
))} */}
</SelectContent>
</Select>
</div>
<Select value={examinerFilter} onValueChange={setExaminer}>
<SelectTrigger className="rounded-full data-[placeholder]:text-primary">
<SelectValue placeholder="Colleur" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">Tous</SelectItem>
{/* TODO: */}
{examiners.map((examiner) => (
<SelectItem key={examiner} value={examiner}>
{examiner}
</SelectItem>
))}
</SelectContent>
</Select>
<div className="space-y-2">
<Label htmlFor="examiner-filter">Filtrer par colleur</Label>
<Select value={examinerFilter} onValueChange={setExaminerFilter}>
<SelectTrigger id="examiner-filter">
<SelectValue placeholder="Tous les colleurs" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">Tous les colleurs</SelectItem>
{/* TODO: */}
{/* {uniqueExaminers.map((examiner) => (
<SelectItem key={examiner} value={examiner}>
{examiner}
</SelectItem>
))} */}
</SelectContent>
</Select>
</div>
{/* <div className="space-y-2">
<Label htmlFor="student-filter">Filtrer par élève</Label>
<Select value={studentFilter} onValueChange={setStudentFilter}>
<SelectTrigger id="student-filter">
<SelectValue placeholder="Tous les élèves" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">Tous les élèves</SelectItem>
{uniqueStudents.map((student) => (
<SelectItem key={student} value={student}>
{student}
</SelectItem>
))}
</SelectContent>
</Select>
</div> */}
</div>
<div className="flex justify-end">
<Button variant="outline" size="sm">
{/* //TODO: onClick={resetFilters} */}
Réinitialiser les filtres
</Button>
</div>
</CollapsibleContent>
</Collapsible>
<Button
variant="outline"
size="sm"
className="rounded-full dark:bg-input/30 text-primary font-normal"
onClick={toggleSort}
>
{sorted == "asc" ? (
<SortAsc className="h-5 w-5" />
) : (
<SortDesc className="h-5 w-5" />
)}
Trier
</Button>
</div>
{/* Tab Content */}
<div>
@ -285,7 +233,8 @@ export default function Home() {
tabTitle="Vos colles"
emptyCollesText="Vous n'avez pas encore de colle cette semaine."
isLoading={isLoading}
colles={studentColles}
isSorted={sorted === "desc"}
colles={applyFilters(studentColles)}
/>
)}
@ -306,7 +255,8 @@ export default function Home() {
tabTitle="Les colles de la classe"
emptyCollesText="Aucune colle trouvée."
isLoading={isLoading}
colles={classColles}
isSorted={sorted === "desc"}
colles={applyFilters(classColles)}
/>
)}

View file

@ -9,7 +9,8 @@ type TabContentProps = {
emptyCollesText: string;
isLoading: boolean;
colles: Colle[];
};
isSorted?: boolean;
}
const WEEK_DAYS = [
"Lundi",
@ -26,6 +27,7 @@ export default function TabContent({
emptyCollesText,
isLoading,
colles,
isSorted
}: TabContentProps) {
const collesByDay: Record<string, Colle[]> = {};
colles.forEach((colle) => {
@ -40,6 +42,10 @@ export default function TabContent({
const days = WEEK_DAYS.filter(
(day) => collesByDay[day] && collesByDay[day].length > 0
);
// If not sorted, reverse the order of days
if (!isSorted) {
days.reverse();
}
return (
<>