refactor: SpecialitySection + TeacherSection (en cours)

This commit is contained in:
N3WT DE COMPET
2025-01-31 15:41:23 +01:00
parent a248898203
commit 72dd7699d6
6 changed files with 75 additions and 50 deletions

View File

@ -1,7 +1,7 @@
export default function InputText({name, type, label, value, onChange, errorMsg, placeholder, className, required}) { export default function InputText({name, type, label, value, onChange, errorMsg, placeholder, className, required}) {
return ( return (
<> <>
<div className={`mb-4 ${className}`}> <div className={`${className}`}>
<label htmlFor={name} className="block text-sm font-medium text-gray-700"> <label htmlFor={name} className="block text-sm font-medium text-gray-700">
{label} {label}
{required && <span className="text-red-500 ml-1">*</span>} {required && <span className="text-red-500 ml-1">*</span>}

View File

@ -100,7 +100,7 @@ const ClassesSection = ({ classes, teachers, handleCreate, handleEdit, handleDel
transform: (row) => ( transform: (row) => (
<div key={row.id} className="flex flex-wrap justify-center items-center space-x-2"> <div key={row.id} className="flex flex-wrap justify-center items-center space-x-2">
{row.teachers_details.map((teacher, index) => ( {row.teachers_details.map((teacher, index) => (
<TeacherLabel key={teacher.id} nom={teacher.last_name} prenom={teacher.first_name} index={index} /> <TeacherLabel key={`${teacher.id}-${index}`} nom={teacher.last_name} prenom={teacher.first_name} index={index} />
))} ))}
</div> </div>
) )

View File

@ -3,33 +3,9 @@ import { useState } from 'react';
import Table from '@/components/Table'; import Table from '@/components/Table';
import Popup from '@/components/Popup'; import Popup from '@/components/Popup';
import InputTextWithColorIcon from '@/components/InputTextWithColorIcon'; import InputTextWithColorIcon from '@/components/InputTextWithColorIcon';
import { DndProvider, useDrag } from 'react-dnd'; import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend'; import { HTML5Backend } from 'react-dnd-html5-backend';
import SpecialityItem from '@/components/Structure/Configuration/SpecialityItem';
const ItemTypes = {
SPECIALITY: 'speciality',
};
const SpecialityItem = ({ speciality }) => {
const [{ isDragging }, drag] = useDrag(() => ({
type: ItemTypes.SPECIALITY,
item: { id: speciality.id, name: speciality.name },
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
}));
return (
<div
ref={drag}
className="inline-block px-3 py-1 rounded-full font-bold text-white text-center"
style={{ backgroundColor: speciality.color_code, opacity: isDragging ? 0.5 : 1 }}
title={speciality.name}
>
{speciality.name}
</div>
);
};
const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, handleEdit, handleDelete }) => { const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, handleEdit, handleDelete }) => {

View File

@ -0,0 +1,31 @@
import { useDrag } from 'react-dnd';
import React from 'react';
const ItemTypes = {
SPECIALITY: 'speciality',
};
const SpecialityItem = ({ speciality, isDraggable = true }) => {
const [{ isDragging }, drag] = useDrag(() => ({
type: ItemTypes.SPECIALITY,
item: { id: speciality.id, name: speciality.name },
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
canDrag: () => isDraggable,
}), [isDraggable]);
return (
<div
ref={isDraggable ? drag : null}
className={`inline-block px-3 py-1 rounded-lg font-bold text-white text-center ${isDraggable ? 'cursor-pointer' : ''} transition-transform duration-200 ease-in-out ${
isDragging ? 'opacity-30' : 'opacity-100'
} ${isDraggable ? 'hover:shadow-lg hover:scale-125' : ''}`}
style={{ backgroundColor: speciality.color_code }}
>
{speciality.name}
</div>
);
};
export default SpecialityItem;

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, { useState, useEffect } from 'react';
import SpecialitiesSection from '@/components/Structure/Configuration/SpecialitiesSection'; import SpecialitiesSection from '@/components/Structure/Configuration/SpecialitiesSection';
import TeachersSection from '@/components/Structure/Configuration/TeachersSection'; import TeachersSection from '@/components/Structure/Configuration/TeachersSection';
import ClassesSection from '@/components/Structure/Configuration/ClassesSection'; import ClassesSection from '@/components/Structure/Configuration/ClassesSection';
@ -9,7 +9,7 @@ const StructureManagement = ({ specialities, setSpecialities, teachers, setTeach
return ( return (
<div className="max-w-8xl mx-auto p-4 mt-6 space-y-6"> <div className="max-w-8xl mx-auto p-4 mt-6 space-y-6">
<ClassesProvider> <ClassesProvider>
<div className="max-w-4xl p-4 bg-white rounded-lg shadow-md"> <div className="w-2/5 p-4 bg-white rounded-lg shadow-md">
<SpecialitiesSection <SpecialitiesSection
specialities={specialities} specialities={specialities}
setSpecialities={setSpecialities} setSpecialities={setSpecialities}
@ -18,7 +18,7 @@ const StructureManagement = ({ specialities, setSpecialities, teachers, setTeach
handleDelete={(id) => handleDelete(`${BE_SCHOOL_SPECIALITY_URL}`, id, setSpecialities)} handleDelete={(id) => handleDelete(`${BE_SCHOOL_SPECIALITY_URL}`, id, setSpecialities)}
/> />
</div> </div>
<div className="max-w-8xl p-4 bg-white rounded-lg shadow-md"> <div className="w-4/5 p-4 bg-white rounded-lg shadow-md">
<TeachersSection <TeachersSection
teachers={teachers} teachers={teachers}
setTeachers={setTeachers} setTeachers={setTeachers}
@ -28,7 +28,7 @@ const StructureManagement = ({ specialities, setSpecialities, teachers, setTeach
handleDelete={(id) => handleDelete(`${BE_SCHOOL_TEACHER_URL}`, id, setTeachers)} handleDelete={(id) => handleDelete(`${BE_SCHOOL_TEACHER_URL}`, id, setTeachers)}
/> />
</div> </div>
<div className="p-4 bg-white rounded-lg shadow-md"> <div className="w-4/5 p-4 bg-white rounded-lg shadow-md">
<ClassesSection <ClassesSection
classes={classes} classes={classes}
teachers={teachers} teachers={teachers}

View File

@ -1,14 +1,14 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Plus, Edit3, Trash2, GraduationCap, Check, X } from 'lucide-react'; import { Plus, Edit3, Trash2, GraduationCap, Check, X, Hand } from 'lucide-react';
import Table from '@/components/Table'; import Table from '@/components/Table';
import Popup from '@/components/Popup'; import Popup from '@/components/Popup';
import InputTextIcon from '@/components/InputTextIcon';
import ToggleSwitch from '@/components/ToggleSwitch'; import ToggleSwitch from '@/components/ToggleSwitch';
import { createProfile, updateProfile } from '@/app/lib/authAction'; import { createProfile, updateProfile } from '@/app/lib/authAction';
import useCsrfToken from '@/hooks/useCsrfToken'; import useCsrfToken from '@/hooks/useCsrfToken';
import { DndProvider, useDrag, useDrop } from 'react-dnd'; import { DndProvider, useDrag, useDrop } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend'; import { HTML5Backend } from 'react-dnd-html5-backend';
import InputText from '@/components/InputText'; import InputText from '@/components/InputText';
import SpecialityItem from '@/components/Structure/Configuration/SpecialityItem';
const ItemTypes = { const ItemTypes = {
SPECIALITY: 'speciality', SPECIALITY: 'speciality',
@ -17,6 +17,9 @@ const ItemTypes = {
const SpecialitiesDropZone = ({ teacher, handleSpecialitiesChange, specialities, isEditing }) => { const SpecialitiesDropZone = ({ teacher, handleSpecialitiesChange, specialities, isEditing }) => {
const [localSpecialities, setLocalSpecialities] = useState(teacher.specialities_details || []); const [localSpecialities, setLocalSpecialities] = useState(teacher.specialities_details || []);
useEffect(() => {
}, [specialities]);
useEffect(() => { useEffect(() => {
setLocalSpecialities(teacher.specialities_details || []); setLocalSpecialities(teacher.specialities_details || []);
}, [teacher.specialities_details]); }, [teacher.specialities_details]);
@ -25,21 +28,29 @@ const SpecialitiesDropZone = ({ teacher, handleSpecialitiesChange, specialities,
handleSpecialitiesChange(localSpecialities.map(speciality => speciality.id)); handleSpecialitiesChange(localSpecialities.map(speciality => speciality.id));
}, [localSpecialities]); }, [localSpecialities]);
const [{ isOver }, drop] = useDrop(() => ({ const [{ isOver, canDrop }, drop] = useDrop({
accept: ItemTypes.SPECIALITY, accept: ItemTypes.SPECIALITY,
drop: (item) => { drop: (item) => {
const specialityDetails = specialities.find(speciality => speciality.id === item.id); const specialityDetails = specialities.find(speciality => speciality.id === item.id);
if (!localSpecialities.some(speciality => speciality.id === item.id)) { const exists = localSpecialities.some(speciality => speciality.id === item.id);
setLocalSpecialities(prevSpecialities => [ if (!exists) {
setLocalSpecialities(prevSpecialities => {
const updatedSpecialities = [
...prevSpecialities, ...prevSpecialities,
{ id: item.id, name: specialityDetails.name, color_code: specialityDetails.color_code } { id: item.id, name: specialityDetails.name, color_code: specialityDetails.color_code }
]); ];
return updatedSpecialities;
});
} }
}, },
collect: (monitor) => ({ collect: (monitor) => ({
isOver: !!monitor.isOver(), isOver: !!monitor.isOver(),
canDrop: !!monitor.canDrop(),
}), }),
})); canDrop: () => {
return isEditing;
},
});
const handleRemoveSpeciality = (id) => { const handleRemoveSpeciality = (id) => {
setLocalSpecialities(prevSpecialities => { setLocalSpecialities(prevSpecialities => {
@ -49,16 +60,19 @@ const SpecialitiesDropZone = ({ teacher, handleSpecialitiesChange, specialities,
}; };
return ( return (
<div ref={drop} className="p-2 rounded-md flex flex-col items-center"> <div ref={drop} className={`p-2 rounded-md flex flex-col items-center ${isEditing ? 'border-2 border-dashed border-blue-500 bg-blue-50' : ''} ${
isOver && canDrop ? 'border-2 border-solid border-blue-300' : ''
}`}
>
{isEditing && (
<div className="mb-2 text-blue-500 font-semibold flex items-center space-x-2">
<Hand className="w-5 h-5" /> {/* Ajoutez l'icône Hand */}
<span>Déposez une spécialité ici</span>
</div>
)}
{localSpecialities.map((speciality, index) => ( {localSpecialities.map((speciality, index) => (
<div key={`${speciality.id}-${index}`} className="flex items-center space-x-2 mb-2"> <div key={`${speciality.id}-${index}`} className="flex items-center space-x-2 mb-2">
<span <SpecialityItem key={speciality.id} speciality={speciality} isDraggable={false}/>
className="px-3 py-1 rounded-full font-bold text-white"
style={{ backgroundColor: speciality.color_code }}
title={speciality.name}
>
{speciality.name}
</span>
{isEditing && ( {isEditing && (
<button <button
type="button" type="button"
@ -276,7 +290,11 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
return teacher.email; return teacher.email;
case 'SPECIALITES': case 'SPECIALITES':
return ( return (
<SpecialitiesDropZone teacher={teacher} handleSpecialitiesChange={handleSpecialitiesChange} specialities={specialities} isEditing={false} /> <div className="flex justify-center space-x-2 flex-wrap">
{teacher.specialities_details.map((speciality) => (
<SpecialityItem key={speciality.id} speciality={speciality} isDraggable={false} />
))}
</div>
); );
case 'PROFIL': case 'PROFIL':
if (teacher.associated_profile) { if (teacher.associated_profile) {