diff --git a/src/app/board/notifications/components/notifications.table.tsx b/src/app/board/notifications/components/notifications.table.tsx new file mode 100644 index 0000000..b0ce62c --- /dev/null +++ b/src/app/board/notifications/components/notifications.table.tsx @@ -0,0 +1,102 @@ +"use client"; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { Badge } from "@/components/ui/badge"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { Notification } from "@/types/notification.types"; +import { formatDate } from "@/lib/utils"; + +interface NotificationsTableProps { + notifications: Notification[]; + isLoading: boolean; +} + +export function NotificationsTable({ notifications, isLoading }: NotificationsTableProps) { + if (isLoading) { + return ( +
+

Chargement ...

+
+ ); + } + + if (notifications.length === 0) { + return ( +
+

Aucune notification trouvée.

+
+ ); + } + + return ( +
+ + + + Message + Status + Cours + Date + Destinataire + + + + {notifications.map((notification) => ( + + {notification.message} + + + + + + + + {notification.emargement.classSession.course.name} + + +
+

Date: {formatDate(notification.emargement.classSession.date)}

+

Début: {notification.emargement.classSession.heureDebut}

+

Fin: {notification.emargement.classSession.heureFin}

+
+
+
+
+
+ {formatDate(notification.createdAt)} + {notification.recipient.name} +
+ ))} +
+
+
+ ); +} + +function StatusBadge({ status }: { status: Notification["status"] }) { + const variant = { + SENT: "default", + READ: "success", + DELETED: "destructive", + }[status]; + + const label = { + SENT: "Envoyé", + READ: "Lu", + DELETED: "Supprimé", + }[status]; + + return {label}; +} diff --git a/src/app/board/notifications/page.tsx b/src/app/board/notifications/page.tsx new file mode 100644 index 0000000..48afcdd --- /dev/null +++ b/src/app/board/notifications/page.tsx @@ -0,0 +1,80 @@ +"use client"; + +import { AppSidebar } from "@/components/shared/navigation/app.sidebar"; +import UserDropdown from "@/components/shared/navigation/user.dropdown"; +import FeedbackDialog from "@/components/shared/others/feedback.dialog"; +import { ModeToggle } from "@/components/shared/theme/mode-toggle"; +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from "@/components/ui/breadcrumb"; +import { Separator } from "@/components/ui/separator"; +import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; +import { useNotificationsQuery } from "@/hooks/queries/use-notification.query"; +import { RiBellLine, RiScanLine } from "@remixicon/react"; +import { NotificationsTable } from "./components/notifications.table"; +import { PiBellDuotone, PiBuildingsDuotone } from "react-icons/pi"; + + + + +export default function NotificationsPage() { + const { data: notifications = [], isLoading } = useNotificationsQuery(); + + return ( + + + +
+
+ + + + + + + + + + + Notifications + + + +
+
+ + + +
+
+
+ {/* Page intro */} +
+
+

+ + Notifications +

+

Gérez vos notifications liées aux émargements de cours.

+
+
+ + {/* Table */} +
+ + +
+
+
+ + +
+ ); +} diff --git a/src/config/navigation-items.tsx b/src/config/navigation-items.tsx index 651f0b4..5e6b8a3 100644 --- a/src/config/navigation-items.tsx +++ b/src/config/navigation-items.tsx @@ -10,6 +10,7 @@ import { PiGearDuotone, PiHouseDuotone, PiUserDuotone, + PiBellDuotone, } from "react-icons/pi"; import { routes } from "./routes"; diff --git a/src/config/routes.ts b/src/config/routes.ts index a17dc26..b22e2cd 100644 --- a/src/config/routes.ts +++ b/src/config/routes.ts @@ -9,8 +9,7 @@ export const routes = { home: "/board", users: "/board/users", profile: "/board/profile", - settings: "/board/settings", - academicYears: "/board/academic-years", + settings: "/board/settings", academicYears: "/board/academic-years", organizations: "/board/organizations", attendance: "/board/attendance", attendanceAdmin: "/board/attendance-admin", @@ -19,5 +18,6 @@ export const routes = { programs: "/board/programs", universities: "/board/universities", classSessions: "/board/class-sessions", + notifications: "/board/notifications", }, }; diff --git a/src/server/services/notification.service.ts b/src/server/services/notification.service.ts index d872328..1718b4b 100644 --- a/src/server/services/notification.service.ts +++ b/src/server/services/notification.service.ts @@ -49,80 +49,4 @@ export class NotificationService { return data; } catch (error) { console.error(`Erreur lors de la récupération de la notification ${id}:`, error); - throw new Error("Impossible de récupérer les détails de la notification"); - } - } - - /** - * Créer une nouvelle notification - */ - static async createNotification(input: CreateNotificationDto): Promise { - try { - const token = getAuthToken(); - if (!token) { - throw new Error("Vous devez être connecté pour accéder à cette ressource"); - } - - const { data } = await api.post(`/api/v1/notifications`, input, { - headers: { - Authorization: `Bearer ${token}`, - }, - }); - - return data; - } catch (error) { - console.error("Erreur lors de la création de la notification:", error); - throw new Error("Impossible de créer la notification"); - } - } - - /** - * Mettre à jour le statut d'une notification - */ - static async updateNotificationStatus(id: string, status: string): Promise { - try { - const token = getAuthToken(); - if (!token) { - throw new Error("Vous devez être connecté pour accéder à cette ressource"); - } - - await api.put( - `/api/v1/notifications/${id}`, - { status }, - { - headers: { - Authorization: `Bearer ${token}`, - }, - } - ); - - return true; - } catch (error) { - console.error(`Erreur lors de la mise à jour du statut de la notification ${id}:`, error); - throw new Error("Impossible de mettre à jour le statut de la notification"); - } - } - - /** - * Récupérer les notifications non lues pour un utilisateur - */ - static async getUnreadNotifications(): Promise { - try { - const token = getAuthToken(); - if (!token) { - throw new Error("Vous devez être connecté pour accéder à cette ressource"); - } - - const { data } = await api.get(`/api/v1/notifications?status=SENT`, { - headers: { - Authorization: `Bearer ${token}`, - }, - }); - - return data.items || data; - } catch (error) { - console.error("Erreur lors de la récupération des notifications non lues:", error); - throw new Error("Impossible de récupérer les notifications non lues"); - } - } -} + throw new Error("Impossible de récupérer les détails d diff --git a/src/types/attendance.types.ts b/src/types/attendance.types.ts index 8348e77..ca26c51 100644 --- a/src/types/attendance.types.ts +++ b/src/types/attendance.types.ts @@ -1,12 +1,31 @@ import { AcademicYear } from "./academic-year.types"; import { User } from "./user.types"; +import { Course } from "./course.types" +import { AcademicYear } from "./academic-year.types" +import { User } from "./user.types" + +export interface ClassSession { + id: string; + date: string; + heureDebut: string; + heureFin: string; + academicYear: AcademicYear; + course: Course; + professor: User; + classRepresentative: User; + createdAt: string; + updatedAt: string; +} + export interface Attendance { id: string; professorId: string; courseId: string; date: string; status: "PRESENT" | "ABSENT" | "LATE"; + classSession: ClassSession; + professor: User; comments?: string; createdAt: string; updatedAt: string; @@ -31,14 +50,6 @@ export interface UpdateAttendanceInput { comments?: string; } -export interface Course { - id: string; - title: string; - startTime: string; - endTime: string; - location: string; - hasAttendance: boolean; -} export interface ClassSession { id: string; @@ -101,3 +112,4 @@ export interface UpdateEmargementInput { id: string; status?: "PENDING" | "PRESENT" | "ABSENT" | "SUPERVISOR_CONFIRMED" | "CLASS_HEADER_CONFIRMED"; } + \ No newline at end of file diff --git a/src/types/notification.types.ts b/src/types/notification.types.ts index 2751deb..aca3f9a 100644 --- a/src/types/notification.types.ts +++ b/src/types/notification.types.ts @@ -1,10 +1,12 @@ import { Emargement } from "./attendance.types"; import { User } from "./user.types"; +export type NotificationStatus = "SENT" | "CONFIRMED" | "RECEIVED" | "READ" | "DELETED"; + export interface Notification { id: string; message: string; - status: "SENT" | "CONFIRMED" | "RECEIVED" | "READ"; + status: NotificationStatus; emargement?: Emargement; recipient: User; createdAt: string; @@ -13,13 +15,13 @@ export interface Notification { export interface CreateNotificationDto { message: string; - status: "SENT" | "CONFIRMED" | "RECEIVED" | "READ"; + status: NotificationStatus; emargementId: string; recipientId: string; } export interface UpdateNotificationDto { id: string; - status?: "SENT" | "CONFIRMED" | "RECEIVED" | "READ"; + status?: NotificationStatus; message?: string; }