diff --git a/Front-End/src/app/[locale]/admin/page.js b/Front-End/src/app/[locale]/admin/page.js
index aadba19..07c4783 100644
--- a/Front-End/src/app/[locale]/admin/page.js
+++ b/Front-End/src/app/[locale]/admin/page.js
@@ -1,9 +1,17 @@
'use client';
import React, { useState, useEffect } from 'react';
import { useTranslations } from 'next-intl';
-import { Users, Clock, CalendarCheck, School, AlertTriangle, CheckCircle2 } from 'lucide-react';
+import {
+ Users,
+ Clock,
+ CalendarCheck,
+ School,
+ AlertTriangle,
+ CheckCircle2,
+} from 'lucide-react';
import Loader from '@/components/Loader';
import StatCard from '@/components/StatCard';
+import EventCard from '@/components/EventCard';
import logger from '@/utils/logger';
import {
fetchRegisterForms,
@@ -15,20 +23,6 @@ import Attendance from '@/components/Grades/Attendance';
import LineChart from '@/components/Charts/LineChart';
import PieChart from '@/components/Charts/PieChart';
-// Composant EventCard pour afficher les événements
-const EventCard = ({ title, date, description, type }) => (
-
-
-
-
-
{title}
-
{date}
-
{description}
-
-
-
-);
-
const mockCompletionRate = 72; // en pourcentage
export default function DashboardPage() {
@@ -39,8 +33,11 @@ export default function DashboardPage() {
const [upcomingEvents, setUpcomingEvents] = useState([]);
const [absencesToday, setAbsencesToday] = useState([]);
- const { selectedEstablishmentId, selectedEstablishmentTotalCapacity, apiDocuseal } =
- useEstablishment();
+ const {
+ selectedEstablishmentId,
+ selectedEstablishmentTotalCapacity,
+ apiDocuseal,
+ } = useEstablishment();
const [statusDistribution, setStatusDistribution] = useState([
{ label: 'Non envoyé', value: 0 },
diff --git a/Front-End/src/app/[locale]/parents/page.js b/Front-End/src/app/[locale]/parents/page.js
index ac61d05..55a160a 100644
--- a/Front-End/src/app/[locale]/parents/page.js
+++ b/Front-End/src/app/[locale]/parents/page.js
@@ -2,7 +2,14 @@
import React, { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import Table from '@/components/Table';
-import { Edit3, Users, Download, Eye, Upload, CalendarDays } from 'lucide-react';
+import {
+ Edit3,
+ Users,
+ Download,
+ Eye,
+ Upload,
+ CalendarDays,
+} from 'lucide-react';
import StatusLabel from '@/components/StatusLabel';
import FileUpload from '@/components/FileUpload';
import { FE_PARENTS_EDIT_SUBSCRIPTION_URL } from '@/utils/Url';
@@ -10,17 +17,16 @@ import {
fetchChildren,
editRegisterForm,
} from '@/app/actions/subscriptionAction';
+import { fetchUpcomingEvents } from '@/app/actions/planningAction';
import logger from '@/utils/logger';
import { BASE_URL } from '@/utils/Url';
import { useEstablishment } from '@/context/EstablishmentContext';
import { useCsrfToken } from '@/context/CsrfContext';
import { useClasses } from '@/context/ClassesContext';
-import {
- PlanningProvider,
- PlanningModes
-} from '@/context/PlanningContext';
+import { PlanningProvider, PlanningModes } from '@/context/PlanningContext';
import SectionHeader from '@/components/SectionHeader';
import ParentPlanningSection from '@/components/ParentPlanningSection';
+import EventCard from '@/components/EventCard';
export default function ParentHomePage() {
const [children, setChildren] = useState([]);
@@ -30,6 +36,7 @@ export default function ParentHomePage() {
const [uploadState, setUploadState] = useState('off'); // État "on" ou "off" pour l'affichage du composant
const [showPlanning, setShowPlanning] = useState(false);
const [planningClassName, setPlanningClassName] = useState(null);
+ const [upcomingEvents, setUpcomingEvents] = useState([]);
const router = useRouter();
const csrfToken = useCsrfToken();
const [reloadFetch, setReloadFetch] = useState(false);
@@ -43,7 +50,20 @@ export default function ParentHomePage() {
});
setReloadFetch(false);
}
- }, [selectedEstablishmentId, reloadFetch]);
+ }, [selectedEstablishmentId, reloadFetch, user]);
+
+ useEffect(() => {
+ if (selectedEstablishmentId) {
+ // Fetch des événements à venir
+ fetchUpcomingEvents(selectedEstablishmentId)
+ .then((data) => {
+ setUpcomingEvents(data);
+ })
+ .catch((error) => {
+ logger.error('Error fetching upcoming events:', error);
+ });
+ }
+ }, [selectedEstablishmentId]);
function handleView(eleveId) {
logger.debug(`View dossier for student id: ${eleveId}`);
@@ -106,7 +126,9 @@ export default function ParentHomePage() {
};
const showClassPlanning = (student) => {
- setPlanningClassName(`${student.associated_class_name} - ${getNiveauLabel(student.level)}`);
+ setPlanningClassName(
+ `${student.associated_class_name} - ${getNiveauLabel(student.level)}`
+ );
setShowPlanning(true);
};
@@ -143,7 +165,7 @@ export default function ParentHomePage() {
{
name: 'Classe',
transform: (row) => (
- {(row.student.associated_class_name)}
+ {row.student.associated_class_name}
),
},
{
@@ -276,25 +298,36 @@ export default function ParentHomePage() {
modeSet={PlanningModes.CLASS_SCHEDULE}
readOnly={true}
>
-
+
>
) : (
// Affichage classique avec le tableau des enfants
+ {/* Section des événements à venir */}
+ {upcomingEvents.length > 0 && (
+
+
+
+ {upcomingEvents.slice(0, 3).map((event, index) => (
+
+ ))}
+
+
+ )}
+
{/* Composant FileUpload et bouton Valider en dessous du tableau */}
{uploadState === 'on' && uploadingStudentId && (
diff --git a/Front-End/src/components/EventCard.js b/Front-End/src/components/EventCard.js
new file mode 100644
index 0000000..ccc2639
--- /dev/null
+++ b/Front-End/src/components/EventCard.js
@@ -0,0 +1,131 @@
+import React from 'react';
+import { CalendarCheck } from 'lucide-react';
+
+/**
+ * Formate une date en format français avec jour de la semaine
+ * @param {string} startDateString - Date de début au format ISO
+ * @param {string} endDateString - Date de fin au format ISO (optionnel)
+ * @returns {object} Objet contenant la date formatée et le jour
+ */
+const formatEventDate = (startDateString, endDateString) => {
+ if (!startDateString)
+ return { formattedDate: '', dayName: '', timeIndicator: '', timeRange: '' };
+
+ try {
+ const startDate = new Date(startDateString);
+ const endDate = endDateString ? new Date(endDateString) : null;
+ const now = new Date();
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
+ const eventDate = new Date(
+ startDate.getFullYear(),
+ startDate.getMonth(),
+ startDate.getDate()
+ );
+
+ // Options pour le formatage de la date
+ const dateOptions = {
+ day: 'numeric',
+ month: 'long',
+ year: 'numeric',
+ };
+
+ const dayOptions = {
+ weekday: 'long',
+ };
+
+ const timeOptions = {
+ hour: '2-digit',
+ minute: '2-digit',
+ };
+
+ const formattedDate = startDate.toLocaleDateString('fr-FR', dateOptions);
+ const dayName = startDate.toLocaleDateString('fr-FR', dayOptions);
+
+ // Formatage de l'heure
+ let timeRange = '';
+ if (endDate) {
+ const startTime = startDate.toLocaleTimeString('fr-FR', timeOptions);
+ const endTime = endDate.toLocaleTimeString('fr-FR', timeOptions);
+ timeRange = `${startTime} - ${endTime}`;
+ } else {
+ timeRange = startDate.toLocaleTimeString('fr-FR', timeOptions);
+ }
+
+ // Calcul des jours restants
+ const diffTime = eventDate - today;
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
+
+ let timeIndicator = '';
+ if (diffDays === 0) {
+ timeIndicator = "Aujourd'hui";
+ } else if (diffDays === 1) {
+ timeIndicator = 'Demain';
+ } else if (diffDays > 0 && diffDays <= 7) {
+ timeIndicator = `Dans ${diffDays} jours`;
+ }
+
+ return {
+ formattedDate,
+ dayName: dayName.charAt(0).toUpperCase() + dayName.slice(1),
+ timeIndicator,
+ timeRange,
+ };
+ } catch (error) {
+ // logger.error('Erreur lors du formatage de la date:', error);
+ return {
+ formattedDate: startDateString,
+ dayName: '',
+ timeIndicator: '',
+ timeRange: '',
+ };
+ }
+};
+
+/**
+ * Composant EventCard pour afficher les événements à venir
+ * @param {string} title - Titre de l'événement
+ * @param {string} start - Date de début de l'événement (format ISO)
+ * @param {string} end - Date de fin de l'événement (format ISO)
+ * @param {string} date - Date de l'événement (pour compatibilité)
+ * @param {string} description - Description de l'événement
+ * @param {string} type - Type d'événement (optionnel)
+ * @returns {JSX.Element} Carte d'événement
+ */
+const EventCard = ({ title, start, end, date, description, type }) => {
+ // Utiliser start si disponible, sinon date pour compatibilité
+ const eventDate = start || date;
+ const { formattedDate, dayName, timeIndicator, timeRange } = formatEventDate(
+ eventDate,
+ end
+ );
+
+ return (
+
+
+
+
+
+
+
{title}
+
+ {dayName}
+ {formattedDate}
+ {timeRange && (
+ {timeRange}
+ )}
+ {timeIndicator && (
+
+ {timeIndicator}
+
+ )}
+
+ {description && (
+
{description}
+ )}
+
+
+
+ );
+};
+
+export default EventCard;