frontend/app/components/home/index.tsx
Nathan Lamy 052e59f1ac
All checks were successful
Deploy to Netlify / Deploy to Netlify (push) Successful in 1m54s
feat: add menus (repas)
2025-08-24 00:34:09 +02:00

268 lines
8 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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";
import { MainLayout } from "~/layout";
import { forceReload } from "~/lib/utils";
import { SyncButton } from "../sync-status";
import WeekNavigation from "./week-navigation";
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()!);
// Fetch colles from API
const {
studentColles,
classColles,
favoriteColles,
healthyUntil,
lastSync,
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 (
<MainLayout
header={
<>
<h1 className="text-2xl font-bold" onClick={forceReload}>
Khollis&eacute; - {user.className}
</h1>
<SyncButton healthyUntil={healthyUntil} lastSync={lastSync} />
</>
}
>
<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 */}
<WeekNavigation startDate={startDate} setStartDate={setStartDate} />
{/* Filter component */}
<div className="flex gap-2 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>
</MainLayout>
);
}