mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
186 lines
6.8 KiB
JavaScript
186 lines
6.8 KiB
JavaScript
'use client'
|
|
|
|
import React, { useState, useEffect } from 'react';
|
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
|
import { DndProvider } from 'react-dnd';
|
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
import PlanningClassView from '@/components/Structure/Planning/PlanningClassView';
|
|
import SpecialitiesList from '@/components/Structure/Planning/SpecialitiesList';
|
|
import { BE_SCHOOL_PLANNINGS_URL } from '@/utils/Url';
|
|
import { useClasses } from '@/context/ClassesContext';
|
|
import { ClasseFormProvider } from '@/context/ClasseFormContext';
|
|
import TabsStructure from '@/components/Structure/Configuration/TabsStructure';
|
|
import { Bookmark, Users, BookOpen, Newspaper } from 'lucide-react';
|
|
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 [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 [isModalOpen, setIsModalOpen] = useState(false);
|
|
const handleOpenModal = () => setIsModalOpen(true);
|
|
const handleCloseModal = () => setIsModalOpen(false);
|
|
|
|
useEffect(() => {
|
|
if (selectedClass) {
|
|
const defaultLevel = niveauxLabels.length > 0 ? niveauxLabels[0].id : '';
|
|
const niveau = selectedLevel || defaultLevel;
|
|
|
|
setSelectedLevel(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);
|
|
setSchedule(currentPlanning ? currentPlanning.planning : {});
|
|
}
|
|
}, [selectedClass, selectedLevel]);
|
|
|
|
const handleLevelSelect = (niveau) => {
|
|
setSelectedLevel(niveau);
|
|
};
|
|
|
|
const handleClassSelect = (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 || {} };
|
|
|
|
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 newCourse = {
|
|
duree: '1',
|
|
heure: courseTime,
|
|
matiere: name,
|
|
teachers: teachers,
|
|
color: color,
|
|
};
|
|
|
|
if (existingCourseIndex !== -1) {
|
|
newSchedule.emploiDuTemps[day][existingCourseIndex] = newCourse;
|
|
} else {
|
|
newSchedule.emploiDuTemps[day].push(newCourse);
|
|
}
|
|
|
|
// Mettre à jour scheduleRef
|
|
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;
|
|
if (planningId) {
|
|
logger.debug('newSchedule : ', newSchedule)
|
|
handleUpdatePlanning(BE_SCHOOL_PLANNINGS_URL, planningId, newSchedule);
|
|
}
|
|
};
|
|
|
|
const categorizedClasses = classes.reduce((acc, classe) => {
|
|
const { school_year } = classe;
|
|
const [startYear] = school_year.split('-').map(Number);
|
|
const category = startYear >= currentSchoolYearStart ? 'Actives' : 'Anciennes';
|
|
|
|
if (!acc[category]) {
|
|
acc[category] = [];
|
|
}
|
|
acc[category].push(classe);
|
|
return acc;
|
|
}, {});
|
|
|
|
return (
|
|
<div className="flex flex-col h-full">
|
|
<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">
|
|
<h2 className="text-3xl text-gray-800 flex items-center">
|
|
<Users className="w-8 h-8 mr-2" />
|
|
Classes
|
|
</h2>
|
|
</div>
|
|
{categorizedClasses['Actives'] &&
|
|
<TabsStructure
|
|
activeTab={selectedClass?.id}
|
|
setActiveTab={handleClassSelect}
|
|
tabs={categorizedClasses['Actives'].map(classe => ({
|
|
id: classe.id,
|
|
title: classe.atmosphere_name,
|
|
icon: Users
|
|
}))}
|
|
/>
|
|
}
|
|
</div>
|
|
|
|
{/* Colonne Niveaux */}
|
|
<div className="p-4 bg-gray-50 rounded-lg shadow-inner">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<h2 className="text-3xl text-gray-800 flex items-center">
|
|
<Bookmark className="w-8 h-8 mr-2" />
|
|
Niveaux
|
|
</h2>
|
|
</div>
|
|
{niveauxLabels &&
|
|
<TabsStructure activeTab={selectedLevel} setActiveTab={handleLevelSelect} tabs={niveauxLabels} />
|
|
}
|
|
</div>
|
|
|
|
{/* Colonne Spécialités */}
|
|
<div className="p-4 bg-gray-50 rounded-lg shadow-inner">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<h2 className="text-3xl text-gray-800 flex items-center">
|
|
<BookOpen className="w-8 h-8 mr-2" />
|
|
Spécialités
|
|
</h2>
|
|
</div>
|
|
<SpecialitiesList teachers={selectedClass ? selectedClass.teachers : []} />
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex-1 p-4 overflow-y-auto">
|
|
<AnimatePresence mode="wait">
|
|
<motion.div
|
|
key="year"
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
exit={{ opacity: 0, y: -20 }}
|
|
transition={{ duration: 0.2 }}
|
|
className="flex-1 relative"
|
|
>
|
|
<ClasseFormProvider initialClasse={selectedClass || {}}>
|
|
<PlanningClassView schedule={schedule} onDrop={onDrop} selectedLevel={selectedLevel} handleUpdatePlanning={handleUpdatePlanning} classe={selectedClass} />
|
|
</ClasseFormProvider>
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
</div>
|
|
</DndProvider>
|
|
</div>
|
|
);
|
|
|
|
};
|
|
|
|
export default ScheduleManagement;
|