All checks were successful
Deploy to Netlify / Deploy to Netlify (push) Successful in 2m2s
271 lines
8.1 KiB
TypeScript
271 lines
8.1 KiB
TypeScript
import { DateTime } from "luxon";
|
|
import { useState } from "react";
|
|
import { Button } from "~/components/ui/button";
|
|
import {
|
|
ChevronLeft,
|
|
ChevronRight,
|
|
Star,
|
|
Users,
|
|
UserIcon,
|
|
SortAsc,
|
|
SortDesc,
|
|
} from "lucide-react";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "~/components/ui/select";
|
|
import { Tabs, TabsList, tabsStyle, TabsTrigger } from "~/components/ui/tabs";
|
|
import DatePickerWithRange from "~/components/home/date-picker";
|
|
import BottomNavigation from "~/components/bottom-nav";
|
|
import Error from "~/components/error";
|
|
import { useSearchParams } from "react-router";
|
|
import { useColles, type User } from "~/lib/api";
|
|
import TabContent from "~/components/home/tab-content";
|
|
|
|
export default function Home({ user }: { user: User }) {
|
|
// Handle query parameters
|
|
const [query, setQuery] = useSearchParams();
|
|
const updateQuery = (key: string, value: string) => {
|
|
if (query.get(key) !== value) {
|
|
setQuery((prev) => {
|
|
const newQuery = new URLSearchParams(prev);
|
|
newQuery.set(key, value);
|
|
return newQuery;
|
|
});
|
|
}
|
|
};
|
|
|
|
// Tabs
|
|
const activeTab = query.get("view") || "you";
|
|
const setActiveTab = (tab: string) => updateQuery("view", tab);
|
|
|
|
// Date
|
|
const rawStartDate = query.get("start");
|
|
const startDate = rawStartDate
|
|
? DateTime.fromISO(rawStartDate, { zone: "local" })
|
|
: DateTime.now().startOf("week");
|
|
|
|
const setStartDate = (date: DateTime) =>
|
|
updateQuery("start", date.startOf("week").toISODate()!);
|
|
|
|
const handlePreviousWeek = () => {
|
|
const previousWeek = startDate.minus({ weeks: 1 });
|
|
setStartDate(previousWeek);
|
|
};
|
|
|
|
const handleNextWeek = () => {
|
|
const nextWeek = startDate.plus({ weeks: 1 });
|
|
setStartDate(nextWeek);
|
|
};
|
|
|
|
// Fetch colles from API
|
|
const { studentColles, classColles, favoriteColles, error, isLoading } =
|
|
useColles(startDate);
|
|
|
|
// Error handling (after all hooks)
|
|
if (error)
|
|
return (
|
|
<Error
|
|
title="Impossible de charger les colles"
|
|
message={error?.toString()}
|
|
code={500}
|
|
description="Une erreur s'est produite lors du chargement de la liste des colles."
|
|
/>
|
|
);
|
|
|
|
// TODO: FAVORITES
|
|
const useToggleStar = (auth: any) => {};
|
|
|
|
// Filter state
|
|
const rawSubject = query.get("subject");
|
|
const [subjectFilter, setSubjectFilter] = useState<string>(
|
|
rawSubject === "all" ? "" : rawSubject || ""
|
|
);
|
|
const setSubject = (subject: string) => {
|
|
updateQuery("subject", subject);
|
|
setSubjectFilter(subject);
|
|
};
|
|
const rawExaminer = query.get("examiner");
|
|
const [examinerFilter, setExaminerFilter] = useState<string>(
|
|
rawExaminer === "all" ? "" : rawExaminer || ""
|
|
);
|
|
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 generateFilter = (arr: string[], value: string) => {
|
|
const unique = [...new Set(arr)];
|
|
if (value && !unique.includes(value)) {
|
|
unique.push(value);
|
|
}
|
|
unique.sort((a, b) => a.localeCompare(b));
|
|
return unique;
|
|
};
|
|
const subjects = generateFilter(
|
|
classColles.map((colle) => colle.subject?.name),
|
|
subjectFilter
|
|
);
|
|
const examiners = generateFilter(
|
|
classColles.map((colle) => colle.examiner?.name),
|
|
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">
|
|
{/* Tabs */}
|
|
<Tabs
|
|
defaultValue="all"
|
|
value={activeTab}
|
|
onValueChange={setActiveTab}
|
|
className="max-w-md w-full"
|
|
>
|
|
<TabsList className="w-full p-0 bg-background justify-start border-b rounded-none">
|
|
<TabsTrigger value="you" className={tabsStyle}>
|
|
<UserIcon className="h-4 w-4" />
|
|
Vous
|
|
</TabsTrigger>
|
|
{/* <TabsTrigger value="favorites" className={tabsStyle}>
|
|
<Star className="h-4 w-4" />
|
|
Favoris
|
|
</TabsTrigger> */}
|
|
<TabsTrigger value="class" className={tabsStyle}>
|
|
<Users className="h-4 w-4" />
|
|
Classe
|
|
</TabsTrigger>
|
|
</TabsList>
|
|
</Tabs>
|
|
|
|
{/* Week Navigation */}
|
|
<div className="mb-0">
|
|
<div className="flex flex-row items-center justify-between gap-2">
|
|
<Button variant="outline" size="sm" onClick={handlePreviousWeek}>
|
|
<ChevronLeft className="h-10 w-10" />
|
|
</Button>
|
|
<div className="flex-1">
|
|
<DatePickerWithRange
|
|
startDate={startDate}
|
|
setStartDate={setStartDate}
|
|
/>
|
|
</div>
|
|
<Button variant="outline" size="sm" onClick={handleNextWeek}>
|
|
<ChevronRight className="h-10 w-10" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Filter component */}
|
|
<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>
|
|
|
|
<Select value={examinerFilter} onValueChange={setExaminer}>
|
|
<SelectTrigger className="rounded-full data-[placeholder]:text-primary">
|
|
<SelectValue placeholder="Colleur" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="all">Tous</SelectItem>
|
|
{examiners.map((examiner) => (
|
|
<SelectItem key={examiner} value={examiner}>
|
|
{examiner}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
|
|
<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>
|
|
|
|
{/* Your Colles Tab */}
|
|
{activeTab === "you" && (
|
|
<TabContent
|
|
tabTitle="Vos colles"
|
|
emptyCollesText="Vous n'avez pas encore de colle cette semaine."
|
|
isLoading={isLoading}
|
|
isSorted={sorted === "desc"}
|
|
colles={applyFilters(studentColles)}
|
|
preferences={user.preferences}
|
|
/>
|
|
)}
|
|
|
|
{/* Favorites Tab
|
|
{activeTab === "favorites" && (
|
|
<TabContent
|
|
tabTitle="Vos favoris"
|
|
emptyCollesText="Vous n'avez pas encore de colle favorite, cliquez sur l'étoile pour ajouter une colle à vos favoris."
|
|
isLoading={isLoading}
|
|
colles={favoriteColles}
|
|
/>
|
|
)} */}
|
|
|
|
{/* Class Colles Tab */}
|
|
{activeTab === "class" && (
|
|
<TabContent
|
|
tabTitle="Les colles de la classe"
|
|
emptyCollesText="Aucune colle trouvée."
|
|
isLoading={isLoading}
|
|
isSorted={sorted === "desc"}
|
|
colles={applyFilters(classColles)}
|
|
preferences={user.preferences}
|
|
/>
|
|
)}
|
|
|
|
{/* Bottom Navigation for Mobile */}
|
|
<BottomNavigation activeId="colles" />
|
|
</div>
|
|
);
|
|
}
|