mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 16:03:21 +00:00
chore: application prettier
This commit is contained in:
@ -7,17 +7,27 @@ const ClassesInformation = ({ selectedClass, isPastYear }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`w-full p-6 shadow-lg rounded-full border relative ${isPastYear ? 'bg-gray-200 border-gray-600' : 'bg-emerald-200 border-emerald-500'}`}>
|
||||
<div className={`border-b pb-4 ${isPastYear ? 'border-gray-600' : 'border-emerald-500'}`}>
|
||||
<p className="text-gray-700 text-center"><strong>{selectedClass.age_range} ans</strong></p>
|
||||
<div
|
||||
className={`w-full p-6 shadow-lg rounded-full border relative ${isPastYear ? 'bg-gray-200 border-gray-600' : 'bg-emerald-200 border-emerald-500'}`}
|
||||
>
|
||||
<div
|
||||
className={`border-b pb-4 ${isPastYear ? 'border-gray-600' : 'border-emerald-500'}`}
|
||||
>
|
||||
<p className="text-gray-700 text-center">
|
||||
<strong>{selectedClass.age_range} ans</strong>
|
||||
</p>
|
||||
</div>
|
||||
<div className={`border-b pb-4 ${isPastYear ? 'border-gray-600' : 'border-emerald-500'}`}>
|
||||
<div
|
||||
className={`border-b pb-4 ${isPastYear ? 'border-gray-600' : 'border-emerald-500'}`}
|
||||
>
|
||||
<div className="flex flex-wrap justify-center space-x-4">
|
||||
{selectedClass.teachers.map((teacher) => (
|
||||
<div key={teacher.id} className="relative group mt-4">
|
||||
<TeacherLabel nom={teacher.nom} prenom={teacher.prenom} />
|
||||
<div className="absolute left-1/2 transform -translate-x-1/2 bottom-full mb-2 w-max px-4 py-2 text-white bg-gray-800 rounded-lg opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||
<p className="text-sm">{teacher.nom} {teacher.prenom}</p>
|
||||
<p className="text-sm">
|
||||
{teacher.nom} {teacher.prenom}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@ -5,17 +5,21 @@ import logger from '@/utils/logger';
|
||||
const ClassesList = ({ classes, onClassSelect, selectedClassId }) => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const currentMonth = new Date().getMonth();
|
||||
const currentSchoolYearStart = currentMonth >= 8 ? currentYear : currentYear - 1;
|
||||
const currentSchoolYearStart =
|
||||
currentMonth >= 8 ? currentYear : currentYear - 1;
|
||||
|
||||
const handleClassClick = (classe) => {
|
||||
logger.debug(`Classe sélectionnée: ${classe.atmosphere_name}, Année scolaire: ${classe.school_year}`);
|
||||
logger.debug(
|
||||
`Classe sélectionnée: ${classe.atmosphere_name}, Année scolaire: ${classe.school_year}`
|
||||
);
|
||||
onClassSelect(classe);
|
||||
};
|
||||
|
||||
const categorizedClasses = classes.reduce((acc, classe) => {
|
||||
const { school_year } = classe;
|
||||
const [startYear] = school_year.split('-').map(Number);
|
||||
const category = startYear >= currentSchoolYearStart ? 'Actives' : 'Anciennes';
|
||||
const category =
|
||||
startYear >= currentSchoolYearStart ? 'Actives' : 'Anciennes';
|
||||
|
||||
if (!acc[category]) {
|
||||
acc[category] = [];
|
||||
@ -45,8 +49,12 @@ const ClassesList = ({ classes, onClassSelect, selectedClassId }) => {
|
||||
onClick={() => handleClassClick(classe)}
|
||||
style={{ maxWidth: '400px' }}
|
||||
>
|
||||
<div className="flex-1 text-sm font-medium">{classe.atmosphere_name}</div>
|
||||
<div className="flex-1 text-sm font-medium">{classe.school_year}</div>
|
||||
<div className="flex-1 text-sm font-medium">
|
||||
{classe.atmosphere_name}
|
||||
</div>
|
||||
<div className="flex-1 text-sm font-medium">
|
||||
{classe.school_year}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@ -63,8 +71,12 @@ const ClassesList = ({ classes, onClassSelect, selectedClassId }) => {
|
||||
onClick={() => handleClassClick(classe)}
|
||||
style={{ maxWidth: '400px' }}
|
||||
>
|
||||
<div className="flex-1 text-sm font-medium">{classe.atmosphere_name}</div>
|
||||
<div className="flex-1 text-sm font-medium">{classe.school_year}</div>
|
||||
<div className="flex-1 text-sm font-medium">
|
||||
{classe.atmosphere_name}
|
||||
</div>
|
||||
<div className="flex-1 text-sm font-medium">
|
||||
{classe.school_year}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@ -5,11 +5,11 @@ import { UserIcon } from 'lucide-react'; // Assure-toi d'importer l'icône que t
|
||||
const DraggableSpeciality = ({ speciality }) => {
|
||||
const [{ isDragging }, drag] = useDrag(() => ({
|
||||
type: 'SPECIALITY',
|
||||
item: {
|
||||
id: speciality.id,
|
||||
name: speciality.nom,
|
||||
color: speciality.codeCouleur,
|
||||
teachers: speciality.teachers
|
||||
item: {
|
||||
id: speciality.id,
|
||||
name: speciality.nom,
|
||||
color: speciality.codeCouleur,
|
||||
teachers: speciality.teachers,
|
||||
},
|
||||
collect: (monitor) => ({
|
||||
isDragging: !!monitor.isDragging(),
|
||||
@ -21,7 +21,11 @@ const DraggableSpeciality = ({ speciality }) => {
|
||||
ref={drag}
|
||||
key={speciality.id}
|
||||
className={`relative flex items-center px-4 py-2 rounded-full font-bold text-white text-center shadow-lg cursor-pointer transition-transform duration-200 ease-in-out transform ${isDragging ? 'opacity-50 scale-95' : 'scale-100 hover:scale-105 hover:shadow-xl'}`}
|
||||
style={{ backgroundColor: speciality.codeCouleur, minWidth: '200px', maxWidth: '400px' }}
|
||||
style={{
|
||||
backgroundColor: speciality.codeCouleur,
|
||||
minWidth: '200px',
|
||||
maxWidth: '400px',
|
||||
}}
|
||||
title={speciality.nom}
|
||||
>
|
||||
{speciality.nom}
|
||||
|
||||
@ -4,28 +4,33 @@ import PropTypes from 'prop-types';
|
||||
|
||||
// Définition du composant DropTargetCell
|
||||
const DropTargetCell = ({ day, hour, courses, onDrop, onClick }) => {
|
||||
const [{ isOver, canDrop }, drop] = useDrop(() => ({
|
||||
accept: 'SPECIALITY',
|
||||
drop: (item) => onDrop(item, hour, day),
|
||||
collect: (monitor) => ({
|
||||
isOver: monitor.isOver(),
|
||||
canDrop: monitor.canDrop(),
|
||||
const [{ isOver, canDrop }, drop] = useDrop(
|
||||
() => ({
|
||||
accept: 'SPECIALITY',
|
||||
drop: (item) => onDrop(item, hour, day),
|
||||
collect: (monitor) => ({
|
||||
isOver: monitor.isOver(),
|
||||
canDrop: monitor.canDrop(),
|
||||
}),
|
||||
}),
|
||||
}), [hour, day]);
|
||||
[hour, day]
|
||||
);
|
||||
|
||||
const isColorDark = (color) => {
|
||||
if (!color) return false;
|
||||
const r = parseInt(color.slice(1, 3), 16);
|
||||
const g = parseInt(color.slice(3, 5), 16);
|
||||
const b = parseInt(color.slice(5, 7), 16);
|
||||
return (r * 0.299 + g * 0.587 + b * 0.114) < 150;
|
||||
return r * 0.299 + g * 0.587 + b * 0.114 < 150;
|
||||
};
|
||||
|
||||
const isToday = (someDate) => {
|
||||
const today = new Date();
|
||||
return someDate.getDate() === today.getDate() &&
|
||||
someDate.getMonth() === today.getMonth() &&
|
||||
someDate.getFullYear() === today.getFullYear();
|
||||
return (
|
||||
someDate.getDate() === today.getDate() &&
|
||||
someDate.getMonth() === today.getMonth() &&
|
||||
someDate.getFullYear() === today.getFullYear()
|
||||
);
|
||||
};
|
||||
|
||||
// Vérifie si c'est une heure pleine
|
||||
@ -38,19 +43,32 @@ const DropTargetCell = ({ day, hour, courses, onDrop, onClick }) => {
|
||||
${isToday(new Date(day)) ? 'bg-emerald-100/50 border-x border-emerald-600' : ''}
|
||||
hover:bg-emerald-100 h-10 border-b
|
||||
${isFullHour ? 'border-emerald-200' : 'border-gray-300'}
|
||||
${isOver && canDrop ? 'bg-emerald-200' : ''}`} // Ajouté pour indiquer le drop
|
||||
style={{ display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
width: '100%' }}
|
||||
${isOver && canDrop ? 'bg-emerald-200' : ''}`} // Ajouté pour indiquer le drop
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
{courses.map(course => (
|
||||
<div key={course.matiere}
|
||||
className="flex flex-row items-center justify-center gap-2"
|
||||
style={{ backgroundColor: course.color, color: isColorDark(course.color) ? '#E5E5E5' : '#333333', width: '100%', height: '100%' }}>
|
||||
<div style={{ textAlign: 'center', fontWeight: 'bold' }}>{course.matiere}</div>
|
||||
<div style={{ fontStyle: 'italic', textAlign: 'center' }}>{course.teachers.join(', ')}</div>
|
||||
{courses.map((course) => (
|
||||
<div
|
||||
key={course.matiere}
|
||||
className="flex flex-row items-center justify-center gap-2"
|
||||
style={{
|
||||
backgroundColor: course.color,
|
||||
color: isColorDark(course.color) ? '#E5E5E5' : '#333333',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<div style={{ textAlign: 'center', fontWeight: 'bold' }}>
|
||||
{course.matiere}
|
||||
</div>
|
||||
<div style={{ fontStyle: 'italic', textAlign: 'center' }}>
|
||||
{course.teachers.join(', ')}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@ -8,11 +8,21 @@ import { useClasses } from '@/context/ClassesContext';
|
||||
import { Calendar } from 'lucide-react';
|
||||
import SpecialityEventModal from '@/components/Structure/Planning/SpecialityEventModal'; // Assurez-vous du bon chemin d'importation
|
||||
|
||||
const PlanningClassView = ({ schedule, onDrop, selectedLevel, handleUpdatePlanning, classe }) => {
|
||||
const PlanningClassView = ({
|
||||
schedule,
|
||||
onDrop,
|
||||
selectedLevel,
|
||||
handleUpdatePlanning,
|
||||
classe,
|
||||
}) => {
|
||||
const { formData } = useClasseForm();
|
||||
const { determineInitialPeriod } = useClasses();
|
||||
|
||||
const [currentPeriod, setCurrentPeriod] = useState(schedule?.emploiDuTemps ? determineInitialPeriod(schedule.emploiDuTemps) : null);
|
||||
const [currentPeriod, setCurrentPeriod] = useState(
|
||||
schedule?.emploiDuTemps
|
||||
? determineInitialPeriod(schedule.emploiDuTemps)
|
||||
: null
|
||||
);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [selectedCell, setSelectedCell] = useState(null);
|
||||
const [existingEvent, setExistingEvent] = useState(null);
|
||||
@ -36,36 +46,53 @@ const PlanningClassView = ({ schedule, onDrop, selectedLevel, handleUpdatePlanni
|
||||
);
|
||||
}
|
||||
|
||||
const emploiDuTemps = schedule.emploiDuTemps[currentPeriod] || schedule.emploiDuTemps;
|
||||
const emploiDuTemps =
|
||||
schedule.emploiDuTemps[currentPeriod] || schedule.emploiDuTemps;
|
||||
const joursOuverture = Object.keys(emploiDuTemps);
|
||||
const currentWeekDays = joursOuverture
|
||||
.map(day => {
|
||||
switch(day.toLowerCase()) {
|
||||
case 'lundi': return 1;
|
||||
case 'mardi': return 2;
|
||||
case 'mercredi': return 3;
|
||||
case 'jeudi': return 4;
|
||||
case 'vendredi': return 5;
|
||||
case 'samedi': return 6;
|
||||
case 'dimanche': return 7;
|
||||
default: return 0;
|
||||
}
|
||||
.map((day) => {
|
||||
switch (day.toLowerCase()) {
|
||||
case 'lundi':
|
||||
return 1;
|
||||
case 'mardi':
|
||||
return 2;
|
||||
case 'mercredi':
|
||||
return 3;
|
||||
case 'jeudi':
|
||||
return 4;
|
||||
case 'vendredi':
|
||||
return 5;
|
||||
case 'samedi':
|
||||
return 6;
|
||||
case 'dimanche':
|
||||
return 7;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
})
|
||||
.sort((a, b) => a - b) // Trier les jours dans l'ordre croissant
|
||||
.map(day => addDays(startOfWeek(new Date(), { weekStartsOn: 1 }), day - 1)); // Calculer les dates à partir du lundi
|
||||
.map((day) =>
|
||||
addDays(startOfWeek(new Date(), { weekStartsOn: 1 }), day - 1)
|
||||
); // Calculer les dates à partir du lundi
|
||||
|
||||
const getFilteredEvents = (day, time, level) => {
|
||||
const [hour, minute] = time.split(':').map(Number);
|
||||
const startTime = hour + minute / 60; // Convertir l'heure en fraction d'heure
|
||||
|
||||
return emploiDuTemps[day.toLowerCase()]?.filter(event => {
|
||||
return (
|
||||
emploiDuTemps[day.toLowerCase()]?.filter((event) => {
|
||||
const [eventHour, eventMinute] = event.heure.split(':').map(Number);
|
||||
const eventStartTime = eventHour + eventMinute / 60;
|
||||
const eventEndTime = eventStartTime + parseFloat(event.duree);
|
||||
|
||||
|
||||
// Filtrer en fonction du selectedLevel
|
||||
return schedule.niveau === level && startTime >= eventStartTime && startTime < eventEndTime;
|
||||
}) || [];
|
||||
return (
|
||||
schedule.niveau === level &&
|
||||
startTime >= eventStartTime &&
|
||||
startTime < eventEndTime
|
||||
);
|
||||
}) || []
|
||||
);
|
||||
};
|
||||
|
||||
const handleCellClick = (hour, day) => {
|
||||
@ -78,10 +105,14 @@ const PlanningClassView = ({ schedule, onDrop, selectedLevel, handleUpdatePlanni
|
||||
|
||||
const renderTimeSlots = () => {
|
||||
const timeSlots = [];
|
||||
|
||||
for (let hour = parseInt(formData.time_range[0], 10); hour <= parseInt(formData.time_range[1], 10); hour++) {
|
||||
|
||||
for (
|
||||
let hour = parseInt(formData.time_range[0], 10);
|
||||
hour <= parseInt(formData.time_range[1], 10);
|
||||
hour++
|
||||
) {
|
||||
const hourString = hour.toString().padStart(2, '0');
|
||||
|
||||
|
||||
timeSlots.push(
|
||||
<React.Fragment key={`${hourString}:00-${Math.random()}`}>
|
||||
<div className="h-20 p-1 text-right text-sm text-gray-500 bg-gray-100 font-medium">
|
||||
@ -95,14 +126,22 @@ const PlanningClassView = ({ schedule, onDrop, selectedLevel, handleUpdatePlanni
|
||||
<DropTargetCell
|
||||
hour={`${hourString}:00`}
|
||||
day={day}
|
||||
courses={getFilteredEvents(day, `${hourString}:00`, selectedLevel)}
|
||||
courses={getFilteredEvents(
|
||||
day,
|
||||
`${hourString}:00`,
|
||||
selectedLevel
|
||||
)}
|
||||
onDrop={onDrop}
|
||||
onClick={(hour, day) => handleCellClick(hour, day)}
|
||||
/>
|
||||
<DropTargetCell
|
||||
hour={`${hourString}:30`}
|
||||
day={day}
|
||||
courses={getFilteredEvents(day, `${hourString}:30`, selectedLevel)}
|
||||
courses={getFilteredEvents(
|
||||
day,
|
||||
`${hourString}:30`,
|
||||
selectedLevel
|
||||
)}
|
||||
onDrop={onDrop}
|
||||
onClick={(hour, day) => handleCellClick(hour, day)}
|
||||
/>
|
||||
@ -124,46 +163,77 @@ const PlanningClassView = ({ schedule, onDrop, selectedLevel, handleUpdatePlanni
|
||||
</h2>
|
||||
{schedule.emploiDuTemps.S1 && schedule.emploiDuTemps.S2 && (
|
||||
<div>
|
||||
<button onClick={() => setCurrentPeriod('S1')} className={`px-4 py-2 ${currentPeriod === 'S1' ? 'bg-emerald-600 text-white' : 'bg-gray-200 text-gray-800'}`}>
|
||||
<button
|
||||
onClick={() => setCurrentPeriod('S1')}
|
||||
className={`px-4 py-2 ${currentPeriod === 'S1' ? 'bg-emerald-600 text-white' : 'bg-gray-200 text-gray-800'}`}
|
||||
>
|
||||
Semestre 1
|
||||
</button>
|
||||
<button onClick={() => setCurrentPeriod('S2')} className={`px-4 py-2 ${currentPeriod === 'S2' ? 'bg-emerald-600 text-white' : 'bg-gray-200 text-gray-800'}`}>
|
||||
<button
|
||||
onClick={() => setCurrentPeriod('S2')}
|
||||
className={`px-4 py-2 ${currentPeriod === 'S2' ? 'bg-emerald-600 text-white' : 'bg-gray-200 text-gray-800'}`}
|
||||
>
|
||||
Semestre 2
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{schedule.emploiDuTemps.T1 && schedule.emploiDuTemps.T2 && schedule.emploiDuTemps.T3 && (
|
||||
<div>
|
||||
<button onClick={() => setCurrentPeriod('T1')} className={`px-4 py-2 ${currentPeriod === 'T1' ? 'bg-emerald-600 text-white' : 'bg-gray-200 text-gray-800'}`}>
|
||||
Trimestre 1
|
||||
</button>
|
||||
<button onClick={() => setCurrentPeriod('T2')} className={`px-4 py-2 ${currentPeriod === 'T2' ? 'bg-emerald-600 text-white' : 'bg-gray-200 text-gray-800'}`}>
|
||||
Trimestre 2
|
||||
</button>
|
||||
<button onClick={() => setCurrentPeriod('T3')} className={`px-4 py-2 ${currentPeriod === 'T3' ? 'bg-emerald-600 text-white' : 'bg-gray-200 text-gray-800'}`}>
|
||||
Trimestre 3
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{schedule.emploiDuTemps.T1 &&
|
||||
schedule.emploiDuTemps.T2 &&
|
||||
schedule.emploiDuTemps.T3 && (
|
||||
<div>
|
||||
<button
|
||||
onClick={() => setCurrentPeriod('T1')}
|
||||
className={`px-4 py-2 ${currentPeriod === 'T1' ? 'bg-emerald-600 text-white' : 'bg-gray-200 text-gray-800'}`}
|
||||
>
|
||||
Trimestre 1
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCurrentPeriod('T2')}
|
||||
className={`px-4 py-2 ${currentPeriod === 'T2' ? 'bg-emerald-600 text-white' : 'bg-gray-200 text-gray-800'}`}
|
||||
>
|
||||
Trimestre 2
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCurrentPeriod('T3')}
|
||||
className={`px-4 py-2 ${currentPeriod === 'T3' ? 'bg-emerald-600 text-white' : 'bg-gray-200 text-gray-800'}`}
|
||||
>
|
||||
Trimestre 3
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 max-h-[calc(100vh-192px)] overflow-hidden">
|
||||
{/* En-tête des jours */}
|
||||
<div className="grid w-full" style={{ gridTemplateColumns: `2.5rem repeat(${currentWeekDays.length}, 1fr)` }}>
|
||||
<div
|
||||
className="grid w-full"
|
||||
style={{
|
||||
gridTemplateColumns: `2.5rem repeat(${currentWeekDays.length}, 1fr)`,
|
||||
}}
|
||||
>
|
||||
<div className="bg-gray-50 h-14"></div>
|
||||
{currentWeekDays.map((date, index) => (
|
||||
<div
|
||||
key={`${date}-${index}`}
|
||||
className="p-3 text-center bg-emerald-100 text-emerald-800 border-r border-emerald-200">
|
||||
className="p-3 text-center bg-emerald-100 text-emerald-800 border-r border-emerald-200"
|
||||
>
|
||||
<div className="text font-semibold">
|
||||
{format(date, 'EEEE', { locale: fr })}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
||||
{/* Contenu du planning */}
|
||||
<div className="flex-1 overflow-y-auto relative" style={{ maxHeight: 'calc(100vh - 300px)' }}>
|
||||
<div className="grid bg-white relative" style={{ gridTemplateColumns: `2.5rem repeat(${currentWeekDays.length}, 1fr)` }}>
|
||||
<div
|
||||
className="flex-1 overflow-y-auto relative"
|
||||
style={{ maxHeight: 'calc(100vh - 300px)' }}
|
||||
>
|
||||
<div
|
||||
className="grid bg-white relative"
|
||||
style={{
|
||||
gridTemplateColumns: `2.5rem repeat(${currentWeekDays.length}, 1fr)`,
|
||||
}}
|
||||
>
|
||||
{renderTimeSlots()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
'use client'
|
||||
'use client';
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
@ -16,14 +16,17 @@ import logger from '@/utils/logger';
|
||||
const ScheduleManagement = ({ handleUpdatePlanning, classes }) => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const currentMonth = new Date().getMonth();
|
||||
const currentSchoolYearStart = currentMonth >= 8 ? currentYear : currentYear - 1;
|
||||
const currentSchoolYearStart =
|
||||
currentMonth >= 8 ? currentYear : currentYear - 1;
|
||||
|
||||
const [selectedClass, setSelectedClass] = useState(null);
|
||||
const [selectedLevel, setSelectedLevel] = useState('');
|
||||
const [schedule, setSchedule] = useState(null);
|
||||
|
||||
const { getNiveauxTabs } = useClasses();
|
||||
const niveauxLabels = Array.isArray(selectedClass?.levels) ? getNiveauxTabs(selectedClass.levels) : [];
|
||||
const niveauxLabels = Array.isArray(selectedClass?.levels)
|
||||
? getNiveauxTabs(selectedClass.levels)
|
||||
: [];
|
||||
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const handleOpenModal = () => setIsModalOpen(true);
|
||||
@ -36,14 +39,18 @@ const ScheduleManagement = ({ handleUpdatePlanning, classes }) => {
|
||||
|
||||
setSelectedLevel(niveau);
|
||||
|
||||
const currentPlanning = selectedClass.plannings_read?.find(planning => planning.niveau === niveau);
|
||||
const currentPlanning = selectedClass.plannings_read?.find(
|
||||
(planning) => planning.niveau === niveau
|
||||
);
|
||||
setSchedule(currentPlanning ? currentPlanning.planning : {});
|
||||
}
|
||||
}, [selectedClass, niveauxLabels]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedClass && selectedLevel) {
|
||||
const currentPlanning = selectedClass.plannings_read?.find(planning => planning.niveau === selectedLevel);
|
||||
const currentPlanning = selectedClass.plannings_read?.find(
|
||||
(planning) => planning.niveau === selectedLevel
|
||||
);
|
||||
setSchedule(currentPlanning ? currentPlanning.planning : {});
|
||||
}
|
||||
}, [selectedClass, selectedLevel]);
|
||||
@ -53,21 +60,28 @@ const ScheduleManagement = ({ handleUpdatePlanning, classes }) => {
|
||||
};
|
||||
|
||||
const handleClassSelect = (classId) => {
|
||||
const selectedClasse = categorizedClasses['Actives'].find(classe => classe.id === classId);
|
||||
const selectedClasse = categorizedClasses['Actives'].find(
|
||||
(classe) => classe.id === classId
|
||||
);
|
||||
setSelectedClass(selectedClasse);
|
||||
setSelectedLevel('');
|
||||
};
|
||||
|
||||
const onDrop = (item, hour, day) => {
|
||||
const { id, name, color, teachers } = item;
|
||||
const newSchedule = { ...schedule, emploiDuTemps: schedule.emploiDuTemps || {} };
|
||||
const newSchedule = {
|
||||
...schedule,
|
||||
emploiDuTemps: schedule.emploiDuTemps || {},
|
||||
};
|
||||
|
||||
if (!newSchedule.emploiDuTemps[day]) {
|
||||
newSchedule.emploiDuTemps[day] = [];
|
||||
}
|
||||
const courseTime = `${hour.toString().padStart(2, '0')}:00`;
|
||||
|
||||
const existingCourseIndex = newSchedule.emploiDuTemps[day].findIndex(course => course.heure === courseTime);
|
||||
const existingCourseIndex = newSchedule.emploiDuTemps[day].findIndex(
|
||||
(course) => course.heure === courseTime
|
||||
);
|
||||
|
||||
const newCourse = {
|
||||
duree: '1',
|
||||
@ -84,12 +98,14 @@ const ScheduleManagement = ({ handleUpdatePlanning, classes }) => {
|
||||
}
|
||||
|
||||
// Mettre à jour scheduleRef
|
||||
setSchedule(newSchedule)
|
||||
setSchedule(newSchedule);
|
||||
|
||||
// Utiliser `handleUpdatePlanning` pour mettre à jour le planning du niveau de la classe
|
||||
const planningId = selectedClass.plannings_read.find(planning => planning.niveau === selectedLevel)?.planning.id;
|
||||
const planningId = selectedClass.plannings_read.find(
|
||||
(planning) => planning.niveau === selectedLevel
|
||||
)?.planning.id;
|
||||
if (planningId) {
|
||||
logger.debug('newSchedule : ', newSchedule)
|
||||
logger.debug('newSchedule : ', newSchedule);
|
||||
handleUpdatePlanning(BE_SCHOOL_PLANNINGS_URL, planningId, newSchedule);
|
||||
}
|
||||
};
|
||||
@ -97,7 +113,8 @@ const ScheduleManagement = ({ handleUpdatePlanning, classes }) => {
|
||||
const categorizedClasses = classes.reduce((acc, classe) => {
|
||||
const { school_year } = classe;
|
||||
const [startYear] = school_year.split('-').map(Number);
|
||||
const category = startYear >= currentSchoolYearStart ? 'Actives' : 'Anciennes';
|
||||
const category =
|
||||
startYear >= currentSchoolYearStart ? 'Actives' : 'Anciennes';
|
||||
|
||||
if (!acc[category]) {
|
||||
acc[category] = [];
|
||||
@ -111,7 +128,6 @@ const ScheduleManagement = ({ handleUpdatePlanning, classes }) => {
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<div className="p-4 bg-gray-100 border-b">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
|
||||
{/* Colonne Classes */}
|
||||
<div className="p-4 bg-gray-50 rounded-lg shadow-inner">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
@ -120,17 +136,17 @@ const ScheduleManagement = ({ handleUpdatePlanning, classes }) => {
|
||||
Classes
|
||||
</h2>
|
||||
</div>
|
||||
{categorizedClasses['Actives'] &&
|
||||
{categorizedClasses['Actives'] && (
|
||||
<TabsStructure
|
||||
activeTab={selectedClass?.id}
|
||||
setActiveTab={handleClassSelect}
|
||||
tabs={categorizedClasses['Actives'].map(classe => ({
|
||||
tabs={categorizedClasses['Actives'].map((classe) => ({
|
||||
id: classe.id,
|
||||
title: classe.atmosphere_name,
|
||||
icon: Users
|
||||
icon: Users,
|
||||
}))}
|
||||
/>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Colonne Niveaux */}
|
||||
@ -141,9 +157,13 @@ const ScheduleManagement = ({ handleUpdatePlanning, classes }) => {
|
||||
Niveaux
|
||||
</h2>
|
||||
</div>
|
||||
{niveauxLabels &&
|
||||
<TabsStructure activeTab={selectedLevel} setActiveTab={handleLevelSelect} tabs={niveauxLabels} />
|
||||
}
|
||||
{niveauxLabels && (
|
||||
<TabsStructure
|
||||
activeTab={selectedLevel}
|
||||
setActiveTab={handleLevelSelect}
|
||||
tabs={niveauxLabels}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Colonne Spécialités */}
|
||||
@ -154,9 +174,10 @@ const ScheduleManagement = ({ handleUpdatePlanning, classes }) => {
|
||||
Spécialités
|
||||
</h2>
|
||||
</div>
|
||||
<SpecialitiesList teachers={selectedClass ? selectedClass.teachers : []} />
|
||||
<SpecialitiesList
|
||||
teachers={selectedClass ? selectedClass.teachers : []}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -171,7 +192,13 @@ const ScheduleManagement = ({ handleUpdatePlanning, classes }) => {
|
||||
className="flex-1 relative"
|
||||
>
|
||||
<ClasseFormProvider initialClasse={selectedClass || {}}>
|
||||
<PlanningClassView schedule={schedule} onDrop={onDrop} selectedLevel={selectedLevel} handleUpdatePlanning={handleUpdatePlanning} classe={selectedClass} />
|
||||
<PlanningClassView
|
||||
schedule={schedule}
|
||||
onDrop={onDrop}
|
||||
selectedLevel={selectedLevel}
|
||||
handleUpdatePlanning={handleUpdatePlanning}
|
||||
classe={selectedClass}
|
||||
/>
|
||||
</ClasseFormProvider>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
@ -179,7 +206,6 @@ const ScheduleManagement = ({ handleUpdatePlanning, classes }) => {
|
||||
</DndProvider>
|
||||
</div>
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
export default ScheduleManagement;
|
||||
|
||||
@ -17,5 +17,3 @@ const SpecialitiesList = ({ teachers }) => {
|
||||
};
|
||||
|
||||
export default SpecialitiesList;
|
||||
|
||||
|
||||
|
||||
@ -6,7 +6,14 @@ import { BE_SCHOOL_PLANNINGS_URL } from '@/utils/Url';
|
||||
import { BookOpen, Users } from 'lucide-react';
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
const SpecialityEventModal = ({ isOpen, onClose, selectedCell, existingEvent, handleUpdatePlanning, classe }) => {
|
||||
const SpecialityEventModal = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
selectedCell,
|
||||
existingEvent,
|
||||
handleUpdatePlanning,
|
||||
classe,
|
||||
}) => {
|
||||
const { formData, setFormData } = useClasseForm();
|
||||
const { groupSpecialitiesBySubject } = useClasses();
|
||||
const [selectedSpeciality, setSelectedSpeciality] = useState('');
|
||||
@ -15,7 +22,7 @@ const SpecialityEventModal = ({ isOpen, onClose, selectedCell, existingEvent, ha
|
||||
specialiteId: '',
|
||||
teacherId: '',
|
||||
start: '',
|
||||
duration: '1h'
|
||||
duration: '1h',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@ -25,7 +32,7 @@ const SpecialityEventModal = ({ isOpen, onClose, selectedCell, existingEvent, ha
|
||||
specialiteId: '',
|
||||
teacherId: '',
|
||||
start: '',
|
||||
duration: '1h'
|
||||
duration: '1h',
|
||||
});
|
||||
setSelectedSpeciality('');
|
||||
setSelectedTeacher('');
|
||||
@ -42,10 +49,10 @@ const SpecialityEventModal = ({ isOpen, onClose, selectedCell, existingEvent, ha
|
||||
setSelectedTeacher(existingEvent.teacherId);
|
||||
} else {
|
||||
// Mode création
|
||||
setEventData(prev => ({
|
||||
setEventData((prev) => ({
|
||||
...prev,
|
||||
start: selectedCell.hour,
|
||||
duration: '1h'
|
||||
duration: '1h',
|
||||
}));
|
||||
setSelectedSpeciality('');
|
||||
setSelectedTeacher('');
|
||||
@ -69,17 +76,21 @@ const SpecialityEventModal = ({ isOpen, onClose, selectedCell, existingEvent, ha
|
||||
}
|
||||
|
||||
// Transformer eventData pour correspondre au format du planning
|
||||
const selectedTeacherData = formData.teachers.find(teacher => teacher.id === parseInt(eventData.teacherId, 10));
|
||||
const selectedTeacherData = formData.teachers.find(
|
||||
(teacher) => teacher.id === parseInt(eventData.teacherId, 10)
|
||||
);
|
||||
const newCourse = {
|
||||
color: '#FF0000', // Vous pouvez définir la couleur de manière dynamique si nécessaire
|
||||
teachers: selectedTeacherData ? [`${selectedTeacherData.nom} ${selectedTeacherData.prenom}`] : [],
|
||||
teachers: selectedTeacherData
|
||||
? [`${selectedTeacherData.nom} ${selectedTeacherData.prenom}`]
|
||||
: [],
|
||||
heure: `${eventData.start}:00`,
|
||||
duree: eventData.duration.replace('h', ''), // Supposons que '1h' signifie 1
|
||||
matiere: 'GROUPE'
|
||||
matiere: 'GROUPE',
|
||||
};
|
||||
|
||||
// Mettre à jour le planning
|
||||
const updatedPlannings = classe.plannings_read.map(planning => {
|
||||
const updatedPlannings = classe.plannings_read.map((planning) => {
|
||||
if (planning.niveau === selectedCell.selectedLevel) {
|
||||
const newEmploiDuTemps = { ...planning.emploiDuTemps };
|
||||
|
||||
@ -88,7 +99,9 @@ const SpecialityEventModal = ({ isOpen, onClose, selectedCell, existingEvent, ha
|
||||
}
|
||||
|
||||
const courseTime = newCourse.heure;
|
||||
const existingCourseIndex = newEmploiDuTemps[selectedCell.day].findIndex(course => course.heure === courseTime);
|
||||
const existingCourseIndex = newEmploiDuTemps[
|
||||
selectedCell.day
|
||||
].findIndex((course) => course.heure === courseTime);
|
||||
|
||||
if (existingCourseIndex !== -1) {
|
||||
newEmploiDuTemps[selectedCell.day][existingCourseIndex] = newCourse;
|
||||
@ -98,31 +111,37 @@ const SpecialityEventModal = ({ isOpen, onClose, selectedCell, existingEvent, ha
|
||||
|
||||
return {
|
||||
...planning,
|
||||
emploiDuTemps: newEmploiDuTemps
|
||||
emploiDuTemps: newEmploiDuTemps,
|
||||
};
|
||||
}
|
||||
return planning;
|
||||
});
|
||||
|
||||
const updatedPlanning = updatedPlannings.find(planning => planning.niveau === selectedCell.selectedLevel);
|
||||
const updatedPlanning = updatedPlannings.find(
|
||||
(planning) => planning.niveau === selectedCell.selectedLevel
|
||||
);
|
||||
|
||||
setFormData(prevFormData => ({
|
||||
setFormData((prevFormData) => ({
|
||||
...prevFormData,
|
||||
plannings: updatedPlannings
|
||||
plannings: updatedPlannings,
|
||||
}));
|
||||
|
||||
// Appeler handleUpdatePlanning avec les arguments appropriés
|
||||
const planningId = updatedPlanning ? updatedPlanning.planning.id : null;
|
||||
logger.debug("id : ", planningId)
|
||||
logger.debug('id : ', planningId);
|
||||
if (planningId) {
|
||||
handleUpdatePlanning(BE_SCHOOL_PLANNINGS_URL, planningId, updatedPlanning.emploiDuTemps);
|
||||
handleUpdatePlanning(
|
||||
BE_SCHOOL_PLANNINGS_URL,
|
||||
planningId,
|
||||
updatedPlanning.emploiDuTemps
|
||||
);
|
||||
}
|
||||
|
||||
onClose();
|
||||
};
|
||||
|
||||
const filteredTeachers = selectedSpeciality
|
||||
? formData.teachers.filter(teacher =>
|
||||
? formData.teachers.filter((teacher) =>
|
||||
teacher.specialites.includes(parseInt(selectedSpeciality, 10))
|
||||
)
|
||||
: formData.teachers;
|
||||
@ -132,9 +151,9 @@ const SpecialityEventModal = ({ isOpen, onClose, selectedCell, existingEvent, ha
|
||||
setSelectedSpeciality(specialityId);
|
||||
|
||||
// Mettre à jour eventData
|
||||
setEventData(prev => ({
|
||||
setEventData((prev) => ({
|
||||
...prev,
|
||||
specialiteId: specialityId
|
||||
specialiteId: specialityId,
|
||||
}));
|
||||
};
|
||||
|
||||
@ -143,9 +162,9 @@ const SpecialityEventModal = ({ isOpen, onClose, selectedCell, existingEvent, ha
|
||||
setSelectedTeacher(teacherId);
|
||||
|
||||
// Mettre à jour eventData
|
||||
setEventData(prev => ({
|
||||
setEventData((prev) => ({
|
||||
...prev,
|
||||
teacherId: teacherId
|
||||
teacherId: teacherId,
|
||||
}));
|
||||
};
|
||||
|
||||
@ -153,7 +172,7 @@ const SpecialityEventModal = ({ isOpen, onClose, selectedCell, existingEvent, ha
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div className="bg-white p-6 rounded-lg w-full max-w-md">
|
||||
<h2 className="text-xl font-semibold mb-4">
|
||||
{eventData.id ? 'Modifier l\'événement' : 'Nouvel événement'}
|
||||
{eventData.id ? "Modifier l'événement" : 'Nouvel événement'}
|
||||
</h2>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
@ -165,10 +184,12 @@ const SpecialityEventModal = ({ isOpen, onClose, selectedCell, existingEvent, ha
|
||||
selected={selectedSpeciality}
|
||||
choices={[
|
||||
{ value: '', label: 'Sélectionner une spécialité' },
|
||||
...groupSpecialitiesBySubject(formData.teachers).map((speciality) => ({
|
||||
value: speciality.id,
|
||||
label: speciality.nom
|
||||
}))
|
||||
...groupSpecialitiesBySubject(formData.teachers).map(
|
||||
(speciality) => ({
|
||||
value: speciality.id,
|
||||
label: speciality.nom,
|
||||
})
|
||||
),
|
||||
]}
|
||||
callback={handleSpecialityChange}
|
||||
IconItem={BookOpen}
|
||||
@ -182,11 +203,11 @@ const SpecialityEventModal = ({ isOpen, onClose, selectedCell, existingEvent, ha
|
||||
placeHolder="Enseignants"
|
||||
selected={selectedTeacher}
|
||||
choices={[
|
||||
{ value: '', label: 'Sélectionner un enseignant'},
|
||||
...filteredTeachers.map(teacher => ({
|
||||
{ value: '', label: 'Sélectionner un enseignant' },
|
||||
...filteredTeachers.map((teacher) => ({
|
||||
value: teacher.id,
|
||||
label: `${teacher.nom} ${teacher.prenom}`
|
||||
}))
|
||||
label: `${teacher.nom} ${teacher.prenom}`,
|
||||
})),
|
||||
]}
|
||||
callback={handleTeacherChange}
|
||||
IconItem={Users}
|
||||
@ -202,10 +223,12 @@ const SpecialityEventModal = ({ isOpen, onClose, selectedCell, existingEvent, ha
|
||||
<input
|
||||
type="text"
|
||||
value={eventData.duration}
|
||||
onChange={(e) => setEventData(prev => ({
|
||||
...prev,
|
||||
duration: e.target.value
|
||||
}))}
|
||||
onChange={(e) =>
|
||||
setEventData((prev) => ({
|
||||
...prev,
|
||||
duration: e.target.value,
|
||||
}))
|
||||
}
|
||||
className="w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-emerald-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user