diff --git a/Front-End/src/app/[locale]/admin/planning/page.js b/Front-End/src/app/[locale]/admin/planning/page.js index cff8307..22703a9 100644 --- a/Front-End/src/app/[locale]/admin/planning/page.js +++ b/Front-End/src/app/[locale]/admin/planning/page.js @@ -9,6 +9,7 @@ import EventModal from '@/components/Calendar/EventModal'; import ScheduleNavigation from '@/components/Calendar/ScheduleNavigation'; import { useState } from 'react'; import { useEstablishment } from '@/context/EstablishmentContext'; +import { usePlanning } from '@/context/PlanningContext'; export default function Page() { const [isModalOpen, setIsModalOpen] = useState(false); @@ -29,33 +30,36 @@ export default function Page() { }); const { selectedEstablishmentId } = useEstablishment(); - const initializeNewEvent = (date = new Date()) => { - // S'assurer que date est un objet Date valide - const eventDate = date instanceof Date ? date : new Date(); + const PlanningContent = ({ isDrawerOpen, setIsDrawerOpen, isModalOpen, setIsModalOpen, eventData, setEventData }) => { + const { selectedSchedule, schedules } = usePlanning(); - setEventData({ - title: '', - description: '', - start: eventDate.toISOString(), - end: new Date(eventDate.getTime() + 2 * 60 * 60 * 1000).toISOString(), - location: '', - planning: '', // Ne pas définir de valeur par défaut ici non plus - recursionType: RecurrenceType.NONE, - selectedDays: [], - recursionEnd: new Date( - eventDate.getTime() + 2 * 60 * 60 * 1000 - ).toISOString(), - customInterval: 1, - customUnit: 'days', - }); - setIsModalOpen(true); - }; + const initializeNewEvent = (date = new Date()) => { + const eventDate = date instanceof Date ? date : new Date(); - return ( - + const selected = + schedules.find((schedule) => Number(schedule.id) === Number(selectedSchedule)) || + schedules[0]; + + setEventData({ + title: '', + description: '', + start: eventDate.toISOString(), + end: new Date(eventDate.getTime() + 2 * 60 * 60 * 1000).toISOString(), + location: '', + planning: selected?.id || '', + color: selected?.color || '', + recursionType: RecurrenceType.NONE, + selectedDays: [], + recursionEnd: new Date( + eventDate.getTime() + 2 * 60 * 60 * 1000 + ).toISOString(), + customInterval: 1, + customUnit: 'days', + }); + setIsModalOpen(true); + }; + + return (
+ ); + }; + + return ( + + ); } diff --git a/Front-End/src/components/Calendar/DayView.js b/Front-End/src/components/Calendar/DayView.js index 2e16f1b..1ae62e1 100644 --- a/Front-End/src/components/Calendar/DayView.js +++ b/Front-End/src/components/Calendar/DayView.js @@ -13,7 +13,7 @@ import { getWeekEvents } from '@/utils/events'; import { CalendarDays, ChevronLeft, ChevronRight, Plus } from 'lucide-react'; const DayView = ({ onDateClick, onEventClick, events, onOpenDrawer }) => { - const { currentDate, setCurrentDate, parentView } = usePlanning(); + const { currentDate, setCurrentDate, parentView, schedules } = usePlanning(); const [currentTime, setCurrentTime] = useState(new Date()); const scrollRef = useRef(null); @@ -43,11 +43,28 @@ const DayView = ({ onDateClick, onEventClick, events, onOpenDrawer }) => { return `${(hours + minutes / 60) * 5}rem`; }; + const getScheduleColor = (event) => { + const schedule = schedules?.find( + (item) => Number(item.id) === Number(event.planning) + ); + return schedule?.color || event.color || '#6B7280'; + }; + + const getScheduleClassLevelLabel = (event) => { + const schedule = schedules?.find( + (item) => Number(item.id) === Number(event.planning) + ); + const scheduleName = schedule?.name || ''; + if (!scheduleName) return ''; + return scheduleName; + }; + const calculateEventStyle = (event, allDayEvents) => { const start = new Date(event.start); const end = new Date(event.end); const startMinutes = (start.getMinutes() / 60) * 5; const duration = ((end - start) / (1000 * 60 * 60)) * 5; + const scheduleColor = getScheduleColor(event); const overlapping = allDayEvents.filter((other) => { if (other.id === event.id) return false; @@ -179,8 +196,11 @@ const DayView = ({ onDateClick, onEventClick, events, onOpenDrawer }) => { > {dayEvents .filter((e) => new Date(e.start).getHours() === hour) - .map((event) => ( -
{ + const scheduleColor = getScheduleColor(event); + const classLevelLabel = getScheduleClassLevelLabel(event); + return ( +
{ onEventClick(event); } } - > -
-
- {event.title} -
-
- {format(new Date(event.start), 'HH:mm')} –{' '} - {format(new Date(event.end), 'HH:mm')} -
- {event.location && ( + > + {classLevelLabel && (
- {event.location} + + {classLevelLabel} +
)} +
+
+ + {event.title} +
+
+ {format(new Date(event.start), 'HH:mm')} –{' '} + {format(new Date(event.end), 'HH:mm')} +
+ {event.location && ( +
+ {event.location} +
+ )} +
-
- ))} + ); + })}
))} diff --git a/Front-End/src/components/Calendar/EventModal.js b/Front-End/src/components/Calendar/EventModal.js index 04d8e22..2bc5cf0 100644 --- a/Front-End/src/components/Calendar/EventModal.js +++ b/Front-End/src/components/Calendar/EventModal.js @@ -10,20 +10,31 @@ export default function EventModal({ eventData, setEventData, }) { - const { addEvent, handleUpdateEvent, handleDeleteEvent, schedules } = + const { + addEvent, + handleUpdateEvent, + handleDeleteEvent, + schedules, + selectedSchedule, + } = usePlanning(); const { showNotification } = useNotification(); // S'assurer que planning est défini lors du premier rendu React.useEffect(() => { if (!eventData?.planning && schedules.length > 0) { + const defaultSchedule = + schedules.find( + (schedule) => Number(schedule.id) === Number(selectedSchedule) + ) || schedules[0]; + setEventData((prev) => ({ ...prev, - planning: schedules[0].id, - color: schedules[0].color, + planning: defaultSchedule.id, + color: defaultSchedule.color, })); } - }, [schedules, eventData?.planning]); + }, [schedules, selectedSchedule, eventData?.planning]); if (!isOpen) return null; diff --git a/Front-End/src/components/Calendar/MonthView.js b/Front-End/src/components/Calendar/MonthView.js index 9eb3205..8333f21 100644 --- a/Front-End/src/components/Calendar/MonthView.js +++ b/Front-End/src/components/Calendar/MonthView.js @@ -14,7 +14,24 @@ import { fr } from 'date-fns/locale'; import { getEventsForDate } from '@/utils/events'; const MonthView = ({ onDateClick, onEventClick }) => { - const { currentDate, setViewType, setCurrentDate, events } = usePlanning(); + const { currentDate, setViewType, setCurrentDate, events, schedules } = + usePlanning(); + + const getScheduleColor = (event) => { + const schedule = schedules?.find( + (item) => Number(item.id) === Number(event.planning) + ); + return schedule?.color || event.color || '#6B7280'; + }; + + const getScheduleClassLevelLabel = (event) => { + const schedule = schedules?.find( + (item) => Number(item.id) === Number(event.planning) + ); + const scheduleName = schedule?.name || ''; + if (!scheduleName) return ''; + return scheduleName; + }; // Obtenir tous les jours du mois actuel const monthStart = startOfMonth(currentDate); @@ -53,8 +70,11 @@ const MonthView = ({ onDateClick, onEventClick }) => {
- {dayEvents.map((event, index) => ( -
{ + const scheduleColor = getScheduleColor(event); + const classLevelLabel = getScheduleClassLevelLabel(event); + return ( +
{ onEventClick(event); }} > - {event.title} + {classLevelLabel && ( +
+ + {classLevelLabel} + +
+ )} + + + {event.title} +
- ))} + ); + })}
); diff --git a/Front-End/src/components/Calendar/WeekView.js b/Front-End/src/components/Calendar/WeekView.js index 5f3d1d2..679289f 100644 --- a/Front-End/src/components/Calendar/WeekView.js +++ b/Front-End/src/components/Calendar/WeekView.js @@ -7,7 +7,7 @@ import { isToday } from 'date-fns'; const WeekView = ({ onDateClick, onEventClick, events }) => { - const { currentDate, planningMode, parentView } = usePlanning(); + const { currentDate, planningMode, parentView, schedules } = usePlanning(); const [currentTime, setCurrentTime] = useState(new Date()); const scrollContainerRef = useRef(null); // Ajouter cette référence @@ -71,11 +71,28 @@ const WeekView = ({ onDateClick, onEventClick, events }) => { }); }; + const getScheduleColor = (event) => { + const schedule = schedules?.find( + (item) => Number(item.id) === Number(event.planning) + ); + return schedule?.color || event.color || '#6B7280'; + }; + + const getScheduleClassLevelLabel = (event) => { + const schedule = schedules?.find( + (item) => Number(item.id) === Number(event.planning) + ); + const scheduleName = schedule?.name || ''; + if (!scheduleName) return ''; + return scheduleName; + }; + const calculateEventStyle = (event, dayEvents) => { const start = new Date(event.start); const end = new Date(event.end); const startMinutes = (start.getMinutes() / 60) * 5; const duration = ((end - start) / (1000 * 60 * 60)) * 5; + const scheduleColor = getScheduleColor(event); // Trouver les événements qui se chevauchent const overlappingEvents = findOverlappingEvents(event, dayEvents); @@ -101,6 +118,8 @@ const WeekView = ({ onDateClick, onEventClick, events }) => { const renderEventInCell = (event, dayEvents) => { const eventStyle = calculateEventStyle(event, dayEvents); + const scheduleColor = getScheduleColor(event); + const classLevelLabel = getScheduleClassLevelLabel(event); return (
{ } } > + {classLevelLabel && ( +
+ + {classLevelLabel} + +
+ )}
- {event.title} + + {event.title}
{ + const numericId = Number(schoolClass?.id); + if (!Number.isFinite(numericId) || numericId <= 0) { + return CLASS_PLANNING_COLORS[0]; + } + + const index = (numericId - 1) % CLASS_PLANNING_COLORS.length; + return CLASS_PLANNING_COLORS[index]; +}; + const TeachersDropZone = ({ classe, handleTeachersChange, @@ -245,13 +268,14 @@ const ClassesSection = ({ setNewClass(null); setLocalErrors({}); // Creation des plannings associé à la classe + const classPlanningColor = getClassPlanningColor(createdClass); createdClass.levels.forEach((level) => { const levelName = allNiveaux.find((lvl) => lvl.id === level)?.name; const planningName = `${createdClass.atmosphere_name} - ${levelName}`; const newPlanning = { name: planningName, - color: '#FF5733', // Couleur par défaut + color: classPlanningColor, school_class: createdClass.id, }; addSchedule(newPlanning); diff --git a/Front-End/src/components/Structure/Planning/ScheduleEventModal.js b/Front-End/src/components/Structure/Planning/ScheduleEventModal.js index 7d7dd4e..26267e1 100644 --- a/Front-End/src/components/Structure/Planning/ScheduleEventModal.js +++ b/Front-End/src/components/Structure/Planning/ScheduleEventModal.js @@ -12,13 +12,22 @@ export default function ScheduleEventModal({ teachers, classes, }) { - const { addEvent, handleUpdateEvent, handleDeleteEvent, schedules } = + const { + addEvent, + handleUpdateEvent, + handleDeleteEvent, + schedules, + selectedSchedule, + } = usePlanning(); const { showNotification } = useNotification(); React.useEffect(() => { if (!eventData?.planning && schedules.length > 0) { - const defaultSchedule = schedules[0]; + const defaultSchedule = + schedules.find( + (schedule) => Number(schedule.id) === Number(selectedSchedule) + ) || schedules[0]; if (eventData?.planning !== defaultSchedule.id) { setEventData((prev) => ({ ...prev, @@ -26,7 +35,7 @@ export default function ScheduleEventModal({ })); } } - }, [schedules, eventData?.planning]); + }, [schedules, selectedSchedule, eventData?.planning]); const handleSpecialityChange = (specialityId) => { const selectedSpeciality = specialities.find( diff --git a/Front-End/src/components/Structure/Planning/ScheduleManagement.js b/Front-End/src/components/Structure/Planning/ScheduleManagement.js index 2e31485..9acc1b9 100644 --- a/Front-End/src/components/Structure/Planning/ScheduleManagement.js +++ b/Front-End/src/components/Structure/Planning/ScheduleManagement.js @@ -2,7 +2,7 @@ import React, { useState } from 'react'; -import { RecurrenceType } from '@/context/PlanningContext'; +import { RecurrenceType, usePlanning } from '@/context/PlanningContext'; import Calendar from '@/components/Calendar/Calendar'; import ScheduleEventModal from '@/components/Structure/Planning/ScheduleEventModal'; import ScheduleNavigation from '@/components/Calendar/ScheduleNavigation'; @@ -12,6 +12,7 @@ export default function ScheduleManagement({ specialities, teachers, }) { + const { selectedSchedule, schedules } = usePlanning(); const [isModalOpen, setIsModalOpen] = useState(false); const [eventData, setEventData] = useState({ title: '', @@ -32,13 +33,18 @@ export default function ScheduleManagement({ // S'assurer que date est un objet Date valide const eventDate = date instanceof Date ? date : new Date(); + const selected = + schedules.find((schedule) => Number(schedule.id) === Number(selectedSchedule)) || + schedules[0]; + setEventData({ title: '', description: '', start: eventDate.toISOString(), end: new Date(eventDate.getTime() + 2 * 60 * 60 * 1000).toISOString(), location: '', - planning: '', // Ne pas définir de valeur par défaut ici non plus + planning: selected?.id || '', + color: selected?.color || '', recursionType: RecurrenceType.NONE, selectedDays: [], recursionEnd: new Date( diff --git a/Front-End/src/context/PlanningContext.js b/Front-End/src/context/PlanningContext.js index 4a1e42d..651cc7a 100644 --- a/Front-End/src/context/PlanningContext.js +++ b/Front-End/src/context/PlanningContext.js @@ -36,6 +36,29 @@ export const PlanningModes = Object.freeze({ PLANNING: 'planning' }); +const CLASS_SCHEDULE_COLORS = [ + '#EF4444', + '#3B82F6', + '#F59E0B', + '#8B5CF6', + '#EC4899', + '#14B8A6', + '#F97316', + '#6366F1', + '#06B6D4', + '#84CC16', +]; + +const getClassScheduleColor = (schoolClassId) => { + const numericId = Number(schoolClassId); + if (!Number.isFinite(numericId) || numericId <= 0) { + return '#10b981'; + } + + const index = (numericId - 1) % CLASS_SCHEDULE_COLORS.length; + return CLASS_SCHEDULE_COLORS[index]; +}; + export function PlanningProvider({ children, modeSet = PlanningModes.PLANNING, @@ -65,7 +88,15 @@ export function PlanningProvider({ const reloadPlanning = () => { fetchPlannings(selectedEstablishmentId, planningMode).then((data) => { - setSchedules(data); + const normalizedSchedules = + planningMode === PlanningModes.CLASS_SCHEDULE + ? data.map((schedule) => ({ + ...schedule, + color: getClassScheduleColor(schedule.school_class), + })) + : data; + + setSchedules(normalizedSchedules); if (data.length > 0) { setSelectedSchedule(data[0].id); }