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

View file

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