chore: application prettier

This commit is contained in:
Luc SORIGNET
2025-04-15 19:37:47 +02:00
parent dd0884bbce
commit f7666c894b
174 changed files with 10609 additions and 8760 deletions

View File

@ -1,4 +1,13 @@
import { Trash2, Edit3, Plus, ZoomIn, Users, Check, X, Hand } from 'lucide-react';
import {
Trash2,
Edit3,
Plus,
ZoomIn,
Users,
Check,
X,
Hand,
} from 'lucide-react';
import React, { useState, useEffect } from 'react';
import Table from '@/components/Table';
import Popup from '@/components/Popup';
@ -17,30 +26,40 @@ const ItemTypes = {
TEACHER: 'teacher',
};
const TeachersDropZone = ({ classe, handleTeachersChange, teachers, isEditing }) => {
const [localTeachers, setLocalTeachers] = useState(classe.teachers_details || []);
const TeachersDropZone = ({
classe,
handleTeachersChange,
teachers,
isEditing,
}) => {
const [localTeachers, setLocalTeachers] = useState(
classe.teachers_details || []
);
useEffect(() => {
}, [teachers]);
useEffect(() => {}, [teachers]);
useEffect(() => {
setLocalTeachers(classe.teachers_details || []);
}, [classe.teachers_details]);
useEffect(() => {
handleTeachersChange(localTeachers.map(teacher => teacher.id));
handleTeachersChange(localTeachers.map((teacher) => teacher.id));
}, [localTeachers]);
const [{ isOver, canDrop }, drop] = useDrop({
accept: ItemTypes.TEACHER,
drop: (item) => {
const teacherDetails = teachers.find(teacher => teacher.id === item.id);
const exists = localTeachers.some(teacher => teacher.id === item.id);
const teacherDetails = teachers.find((teacher) => teacher.id === item.id);
const exists = localTeachers.some((teacher) => teacher.id === item.id);
if (!exists) {
setLocalTeachers(prevTeachers => {
setLocalTeachers((prevTeachers) => {
const updatedTeachers = [
...prevTeachers,
{ id: item.id, last_name: teacherDetails.last_name, first_name: teacherDetails.first_name }
{
id: item.id,
last_name: teacherDetails.last_name,
first_name: teacherDetails.first_name,
},
];
return updatedTeachers;
});
@ -56,26 +75,33 @@ const TeachersDropZone = ({ classe, handleTeachersChange, teachers, isEditing })
});
const handleRemoveTeacher = (id) => {
setLocalTeachers(prevTeachers => {
const updatedTeachers = prevTeachers.filter(teacher => teacher.id !== id);
setLocalTeachers((prevTeachers) => {
const updatedTeachers = prevTeachers.filter(
(teacher) => teacher.id !== id
);
return updatedTeachers;
});
};
return (
<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' : ''
}`}
<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 && (
{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 un enseignant ici</span>
</div>
)}
{localTeachers.map((teacher, index) => (
<div key={`${teacher.id}-${index}`} className="flex items-center space-x-2 mb-2">
<TeacherItem key={teacher.id} teacher={teacher} isDraggable={false}/>
<div
key={`${teacher.id}-${index}`}
className="flex items-center space-x-2 mb-2"
>
<TeacherItem key={teacher.id} teacher={teacher} isDraggable={false} />
{isEditing && (
<button
type="button"
@ -91,15 +117,22 @@ const TeachersDropZone = ({ classe, handleTeachersChange, teachers, isEditing })
);
};
const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdit, handleDelete }) => {
const ClassesSection = ({
classes,
setClasses,
teachers,
handleCreate,
handleEdit,
handleDelete,
}) => {
const [formData, setFormData] = useState({});
const [editingClass, setEditingClass] = useState(null);
const [newClass, setNewClass] = useState(null);
const [localErrors, setLocalErrors] = useState({});
const [popupVisible, setPopupVisible] = useState(false);
const [popupMessage, setPopupMessage] = useState("");
const [popupMessage, setPopupMessage] = useState('');
const [removePopupVisible, setRemovePopupVisible] = useState(false);
const [removePopupMessage, setRemovePopupMessage] = useState("");
const [removePopupMessage, setRemovePopupMessage] = useState('');
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
const [detailsModalVisible, setDetailsModalVisible] = useState(false);
const [selectedClass, setSelectedClass] = useState(null);
@ -122,11 +155,15 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
{ id: 9, name: 'CM2', age: 10 },
];
const allNiveaux = [...niveauxPremierCycle, ...niveauxSecondCycle, ...niveauxTroisiemeCycle];
const allNiveaux = [
...niveauxPremierCycle,
...niveauxSecondCycle,
...niveauxTroisiemeCycle,
];
const getNiveauxLabels = (levels) => {
return levels.map(niveauId => {
const niveau = allNiveaux.find(n => n.id === niveauId);
return levels.map((niveauId) => {
const niveau = allNiveaux.find((n) => n.id === niveauId);
return niveau ? niveau.name : niveauId;
});
};
@ -143,7 +180,10 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
const choices = [];
for (let i = 0; i < 3; i++) {
const year = startYear + i;
choices.push({ value: `${year}-${year + 1}`, label: `${year}-${year + 1}` });
choices.push({
value: `${year}-${year + 1}`,
label: `${year}-${year + 1}`,
});
}
return choices;
};
@ -154,8 +194,25 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
};
const handleAddClass = () => {
setNewClass({ id: Date.now(), atmosphere_name: '', age_range: '', levels: [], number_of_students: '', school_year: '', teachers: [], establishment: ESTABLISHMENT_ID });
setFormData({ atmosphere_name: '', age_range: '', levels: [], number_of_students: '', school_year: '', teachers: [], establishment: ESTABLISHMENT_ID });
setNewClass({
id: Date.now(),
atmosphere_name: '',
age_range: '',
levels: [],
number_of_students: '',
school_year: '',
teachers: [],
establishment: ESTABLISHMENT_ID,
});
setFormData({
atmosphere_name: '',
age_range: '',
levels: [],
number_of_students: '',
school_year: '',
teachers: [],
establishment: ESTABLISHMENT_ID,
});
};
const handleChange = (e) => {
@ -175,7 +232,13 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
};
const handleSaveNewClass = () => {
if (newClass.atmosphere_name && newClass.age_range && newClass.levels.length > 0 && newClass.number_of_students && newClass.school_year) {
if (
newClass.atmosphere_name &&
newClass.age_range &&
newClass.levels.length > 0 &&
newClass.number_of_students &&
newClass.school_year
) {
handleCreate(newClass)
.then((createdClass) => {
setClasses((prevClasses) => [createdClass, ...classes]);
@ -185,21 +248,31 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
.catch((error) => {
logger.error('Error:', error.message);
if (error.details) {
logger.error('Form errors:', error.details);
setLocalErrors(error.details);
logger.error('Form errors:', error.details);
setLocalErrors(error.details);
}
});
} else {
setPopupMessage("Tous les champs doivent être remplis et valides");
setPopupVisible(true);
}
} else {
setPopupMessage('Tous les champs doivent être remplis et valides');
setPopupVisible(true);
}
};
const handleUpdateClass = (id, updatedData) => {
if (updatedData.atmosphere_name && updatedData.age_range && updatedData.levels.length > 0 && updatedData.number_of_students && updatedData.school_year) {
if (
updatedData.atmosphere_name &&
updatedData.age_range &&
updatedData.levels.length > 0 &&
updatedData.number_of_students &&
updatedData.school_year
) {
handleEdit(id, updatedData)
.then((updatedClass) => {
setClasses((prevClasses) => prevClasses.map((classe) => (classe.id === id ? updatedClass : classe)));
setClasses((prevClasses) =>
prevClasses.map((classe) =>
classe.id === id ? updatedClass : classe
)
);
setEditingClass(null);
setFormData({});
setLocalErrors({});
@ -207,12 +280,12 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
.catch((error) => {
logger.error('Error:', error.message);
if (error.details) {
logger.error('Form errors:', error.details);
setLocalErrors(error.details);
logger.error('Form errors:', error.details);
setLocalErrors(error.details);
}
});
} else {
setPopupMessage("Tous les champs doivent être remplis et valides");
setPopupMessage('Tous les champs doivent être remplis et valides');
setPopupVisible(true);
}
};
@ -236,7 +309,7 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
};
const handleMultiSelectChange = (selectedOptions) => {
const levels = selectedOptions.map(option => option.id);
const levels = selectedOptions.map((option) => option.id);
if (editingClass) {
setFormData((prevData) => ({
@ -277,7 +350,7 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
errorMsg={getError('atmosphere_name')}
/>
);
case 'TRANCHE D\'AGE':
case "TRANCHE D'AGE":
return (
<InputText
name="age_range"
@ -286,14 +359,20 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
placeholder="Tranche d'âge (ex: 3-6)"
errorMsg={getError('age_range')}
/>
)
);
case 'NIVEAUX':
return (
<MultiSelect
name="levels"
label="Sélection de niveaux"
options={allNiveaux}
selectedOptions={currentData.levels ? currentData.levels.map(levelId => allNiveaux.find(level => level.id === levelId)) : []}
selectedOptions={
currentData.levels
? currentData.levels.map((levelId) =>
allNiveaux.find((level) => level.id === levelId)
)
: []
}
onChange={handleMultiSelectChange}
errorMsg={getError('levels')}
/>
@ -308,8 +387,8 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
placeholder="Capacité"
errorMsg={getError('number_of_students')}
/>
)
case 'ANNÉE SCOLAIRE' :
);
case 'ANNÉE SCOLAIRE':
return (
<SelectChoice
type="select"
@ -322,24 +401,35 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
IconItem={null}
disabled={false}
/>
)
);
case 'ENSEIGNANTS':
return (
<TeachersDropZone classe={currentData} handleTeachersChange={handleTeachersChange} teachers={teachers} isEditing={isEditing || isCreating} />
<TeachersDropZone
classe={currentData}
handleTeachersChange={handleTeachersChange}
teachers={teachers}
isEditing={isEditing || isCreating}
/>
);
case 'ACTIONS':
return (
<div className="flex justify-center space-x-2">
<button
type="button"
onClick={() => (isEditing ? handleUpdateClass(editingClass, formData) : handleSaveNewClass())}
onClick={() =>
isEditing
? handleUpdateClass(editingClass, formData)
: handleSaveNewClass()
}
className="text-green-500 hover:text-green-700"
>
<Check className="w-5 h-5" />
</button>
<button
type="button"
onClick={() => (isEditing ? setEditingClass(null) : setNewClass(null))}
onClick={() =>
isEditing ? setEditingClass(null) : setNewClass(null)
}
className="text-red-500 hover:text-red-700"
>
<X className="w-5 h-5" />
@ -353,28 +443,34 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
switch (column) {
case 'AMBIANCE':
return classe.atmosphere_name;
case 'TRANCHE D\'AGE':
case "TRANCHE D'AGE":
return classe.age_range;
case 'NIVEAUX':
const levelLabels = Array.isArray(classe.levels) ? getNiveauxLabels(classe.levels) : [];
const levelLabels = Array.isArray(classe.levels)
? getNiveauxLabels(classe.levels)
: [];
return (
<div className="flex flex-wrap justify-center items-center space-x-2">
{levelLabels.length > 0
? levelLabels.map((label, index) => (
<LevelLabel key={index} label={label} index={index} />
))
: 'Aucun niveau'}
? levelLabels.map((label, index) => (
<LevelLabel key={index} label={label} index={index} />
))
: 'Aucun niveau'}
</div>
);
case 'CAPACITE':
return classe.number_of_students;
case 'ANNÉE SCOLAIRE' :
case 'ANNÉE SCOLAIRE':
return classe.school_year;
case 'ENSEIGNANTS':
return (
<div className="flex justify-center space-x-2 flex-wrap">
{classe.teachers_details.map((teacher) => (
<TeacherItem key={teacher.id} teacher={teacher} isDraggable={false} />
<TeacherItem
key={teacher.id}
teacher={teacher}
isDraggable={false}
/>
))}
</div>
);
@ -385,7 +481,9 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
<div className="flex justify-center space-x-2">
<button
type="button"
onClick={() => setEditingClass(classe.id) || setFormData(classe)}
onClick={() =>
setEditingClass(classe.id) || setFormData(classe)
}
className="text-blue-500 hover:text-blue-700"
>
<Edit3 className="w-5 h-5" />
@ -394,18 +492,29 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
type="button"
onClick={() => {
setRemovePopupVisible(true);
setRemovePopupMessage("Attentions ! \nVous êtes sur le point de supprimer la classe " + classe.atmosphere_name + ".\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?");
setRemovePopupMessage(
'Attentions ! \nVous êtes sur le point de supprimer la classe ' +
classe.atmosphere_name +
".\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?"
);
setRemovePopupOnConfirm(() => () => {
handleDelete(classe.id)
.then(data => {
.then((data) => {
logger.debug('Success:', data);
setPopupMessage("La classe " + classe.atmosphere_name + " a été correctement supprimée");
setPopupMessage(
'La classe ' +
classe.atmosphere_name +
' a été correctement supprimée'
);
setPopupVisible(true);
setRemovePopupVisible(false);
})
.catch(error => {
.catch((error) => {
logger.error('Error archiving data:', error);
setPopupMessage("Erreur lors de la suppression de la classe " + classe.atmosphere_name);
setPopupMessage(
'Erreur lors de la suppression de la classe ' +
classe.atmosphere_name
);
setPopupVisible(true);
setRemovePopupVisible(false);
});
@ -431,14 +540,14 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
};
const columns = [
{ name: 'AMBIANCE', label: 'Nom d\'ambiance' },
{ name: 'TRANCHE D\'AGE', label: 'Tranche d\'âge' },
{ name: 'AMBIANCE', label: "Nom d'ambiance" },
{ name: "TRANCHE D'AGE", label: "Tranche d'âge" },
{ name: 'NIVEAUX', label: 'Niveaux' },
{ name: 'CAPACITE', label: 'Capacité max' },
{ name: 'ANNÉE SCOLAIRE', label: 'Année scolaire' },
{ name: 'ENSEIGNANTS', label: 'Enseignants' },
{ name: 'MISE A JOUR', label: 'Date mise à jour' },
{ name: 'ACTIONS', label: 'Actions' }
{ name: 'ACTIONS', label: 'Actions' },
];
return (
@ -449,7 +558,11 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
<Users className="w-6 h-6 text-emerald-500 mr-2" />
<h2 className="text-xl font-semibold">Classes</h2>
</div>
<button type="button" onClick={handleAddClass} className="text-emerald-500 hover:text-emerald-700">
<button
type="button"
onClick={handleAddClass}
className="text-emerald-500 hover:text-emerald-700"
>
<Plus className="w-5 h-5" />
</button>
</div>
@ -460,7 +573,9 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
/>
<Popup
visible={detailsModalVisible}
message={selectedClass ? <ClasseDetails classe={selectedClass} /> : null}
message={
selectedClass ? <ClasseDetails classe={selectedClass} /> : null
}
onConfirm={() => setDetailsModalVisible(false)}
onCancel={() => setDetailsModalVisible(false)}
uniqueConfirmButton={true}
@ -483,4 +598,4 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
);
};
export default ClassesSection;
export default ClassesSection;

View File

@ -1,15 +1,24 @@
import React from 'react';
import { Calendar } from 'lucide-react';
const DateRange = ({ nameStart, nameEnd, valueStart, valueEnd, onChange, label }) => {
const DateRange = ({
nameStart,
nameEnd,
valueStart,
valueEnd,
onChange,
label,
}) => {
return (
<div className="space-y-4 mt-4 p-4 border rounded-md shadow-sm bg-white">
<label className="block text-lg font-medium text-gray-700 mb-2">{label}</label>
<label className="block text-lg font-medium text-gray-700 mb-2">
{label}
</label>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 items-center">
<div className="relative flex items-center">
<span className="mr-2">Du</span>
<Calendar className="w-5 h-5 text-emerald-500 absolute top-3 left-16" />
<input
<input
type="date"
name={nameStart}
value={valueStart}
@ -21,7 +30,7 @@ const DateRange = ({ nameStart, nameEnd, valueStart, valueEnd, onChange, label }
<div className="relative flex items-center">
<span className="mr-2">Au</span>
<Calendar className="w-5 h-5 text-emerald-500 absolute top-3 left-16" />
<input
<input
type="date"
name={nameEnd}
value={valueEnd}

View File

@ -4,7 +4,13 @@ import DateRange from '@/components/Structure/Configuration/DateRange';
import TimeRange from '@/components/Structure/Configuration/TimeRange';
import CheckBoxList from '@/components/CheckBoxList';
const PlanningConfiguration = ({ formData, handleChange, handleTimeChange, handleJoursChange, typeEmploiDuTemps }) => {
const PlanningConfiguration = ({
formData,
handleChange,
handleTimeChange,
handleJoursChange,
typeEmploiDuTemps,
}) => {
const daysOfWeek = [
{ id: 1, name: 'lun' },
{ id: 2, name: 'mar' },
@ -14,13 +20,15 @@ const PlanningConfiguration = ({ formData, handleChange, handleTimeChange, handl
{ id: 6, name: 'sam' },
];
const isLabelAttenuated = (item) => {
return !formData.opening_days.includes(parseInt(item.id));
const isLabelAttenuated = (item) => {
return !formData.opening_days.includes(parseInt(item.id));
};
return (
<div className="space-y-4">
<label className="mt-6 block text-2xl font-medium text-gray-700">Emploi du temps</label>
<label className="mt-6 block text-2xl font-medium text-gray-700">
Emploi du temps
</label>
<div className="flex justify-between space-x-4 items-start">
<div className="w-1/2">
@ -41,7 +49,7 @@ const PlanningConfiguration = ({ formData, handleChange, handleTimeChange, handl
onStartChange={(e) => handleTimeChange(e, 0)}
onEndChange={(e) => handleTimeChange(e, 1)}
/>
{/* CheckBoxList */}
<CheckBoxList
items={daysOfWeek}

View File

@ -8,17 +8,22 @@ import { HTML5Backend } from 'react-dnd-html5-backend';
import SpecialityItem from '@/components/Structure/Configuration/SpecialityItem';
import logger from '@/utils/logger';
const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, handleEdit, handleDelete }) => {
const SpecialitiesSection = ({
specialities,
setSpecialities,
handleCreate,
handleEdit,
handleDelete,
}) => {
const [newSpeciality, setNewSpeciality] = useState(null);
const [editingSpeciality, setEditingSpeciality] = useState(null);
const [formData, setFormData] = useState({});
const [localErrors, setLocalErrors] = useState({});
const [popupVisible, setPopupVisible] = useState(false);
const [popupMessage, setPopupMessage] = useState("");
const [popupMessage, setPopupMessage] = useState('');
const [removePopupVisible, setRemovePopupVisible] = useState(false);
const [removePopupMessage, setRemovePopupMessage] = useState("");
const [removePopupMessage, setRemovePopupMessage] = useState('');
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
// Récupération des messages d'erreur
@ -33,16 +38,17 @@ const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, hand
const handleRemoveSpeciality = (id) => {
return handleDelete(id)
.then(() => {
setSpecialities(prevSpecialities => prevSpecialities.filter(speciality => speciality.id !== id));
setSpecialities((prevSpecialities) =>
prevSpecialities.filter((speciality) => speciality.id !== id)
);
})
.catch(error => {
.catch((error) => {
logger.error(error);
});
};
const handleSaveNewSpeciality = () => {
if (
newSpeciality.name) {
if (newSpeciality.name) {
handleCreate(newSpeciality)
.then((createdSpeciality) => {
setSpecialities([createdSpeciality, ...specialities]);
@ -52,34 +58,37 @@ const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, hand
.catch((error) => {
logger.error('Error:', error.message);
if (error.details) {
logger.error('Form errors:', error.details);
setLocalErrors(error.details);
logger.error('Form errors:', error.details);
setLocalErrors(error.details);
}
});
} else {
setPopupMessage("Tous les champs doivent être remplis et valides");
setPopupMessage('Tous les champs doivent être remplis et valides');
setPopupVisible(true);
}
};
const handleUpdateSpeciality = (id, updatedSpeciality) => {
if (
updatedSpeciality.name) {
if (updatedSpeciality.name) {
handleEdit(id, updatedSpeciality)
.then((updatedSpeciality) => {
setSpecialities(specialities.map(speciality => speciality.id === id ? updatedSpeciality : speciality));
setSpecialities(
specialities.map((speciality) =>
speciality.id === id ? updatedSpeciality : speciality
)
);
setEditingSpeciality(null);
setLocalErrors({});
})
.catch((error) => {
logger.error('Error:', error.message);
if (error.details) {
logger.error('Form errors:', error.details);
setLocalErrors(error.details);
logger.error('Form errors:', error.details);
setLocalErrors(error.details);
}
});
} else {
setPopupMessage("Tous les champs doivent être remplis et valides");
setPopupMessage('Tous les champs doivent être remplis et valides');
setPopupVisible(true);
}
};
@ -129,14 +138,22 @@ const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, hand
<div className="flex justify-center space-x-2">
<button
type="button"
onClick={() => (isEditing ? handleUpdateSpeciality(editingSpeciality, formData) : handleSaveNewSpeciality())}
onClick={() =>
isEditing
? handleUpdateSpeciality(editingSpeciality, formData)
: handleSaveNewSpeciality()
}
className="text-green-500 hover:text-green-700"
>
<Check className="w-5 h-5" />
</button>
<button
type="button"
onClick={() => (isEditing ? setEditingSpeciality(null) : setNewSpeciality(null))}
onClick={() =>
isEditing
? setEditingSpeciality(null)
: setNewSpeciality(null)
}
className="text-red-500 hover:text-red-700"
>
<X className="w-5 h-5" />
@ -149,9 +166,7 @@ const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, hand
} else {
switch (column) {
case 'LIBELLE':
return (
<SpecialityItem key={speciality.id} speciality={speciality} />
);
return <SpecialityItem key={speciality.id} speciality={speciality} />;
case 'MISE A JOUR':
return speciality.updated_date_formatted;
case 'ACTIONS':
@ -159,7 +174,9 @@ const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, hand
<div className="flex justify-center space-x-2">
<button
type="button"
onClick={() => setEditingSpeciality(speciality.id) || setFormData(speciality)}
onClick={() =>
setEditingSpeciality(speciality.id) || setFormData(speciality)
}
className="text-blue-500 hover:text-blue-700"
>
<Edit3 className="w-5 h-5" />
@ -168,18 +185,29 @@ const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, hand
type="button"
onClick={() => {
setRemovePopupVisible(true);
setRemovePopupMessage("Attentions ! \nVous êtes sur le point de supprimer la spécialité " + speciality.name + ".\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?");
setRemovePopupMessage(
'Attentions ! \nVous êtes sur le point de supprimer la spécialité ' +
speciality.name +
".\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?"
);
setRemovePopupOnConfirm(() => () => {
handleRemoveSpeciality(speciality.id)
.then(data => {
.then((data) => {
logger.debug('Success:', data);
setPopupMessage("La spécialité " + speciality.name + " a été correctement supprimée");
setPopupMessage(
'La spécialité ' +
speciality.name +
' a été correctement supprimée'
);
setPopupVisible(true);
setRemovePopupVisible(false);
})
.catch(error => {
.catch((error) => {
logger.error('Error archiving data:', error);
setPopupMessage("Erreur lors de la suppression de la spécialité " + speciality.name);
setPopupMessage(
'Erreur lors de la suppression de la spécialité ' +
speciality.name
);
setPopupVisible(true);
setRemovePopupVisible(false);
});
@ -198,10 +226,10 @@ const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, hand
};
const columns = [
{ name: 'LIBELLE', label: 'Libellé' },
{ name: 'MISE A JOUR', label: 'Date mise à jour' },
{ name: 'ACTIONS', label: 'Actions' }
];
{ name: 'LIBELLE', label: 'Libellé' },
{ name: 'MISE A JOUR', label: 'Date mise à jour' },
{ name: 'ACTIONS', label: 'Actions' },
];
return (
<DndProvider backend={HTML5Backend}>
@ -211,7 +239,11 @@ const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, hand
<BookOpen className="w-6 h-6 text-emerald-500 mr-2" />
<h2 className="text-xl font-semibold">Spécialités</h2>
</div>
<button type="button" onClick={handleAddSpeciality} className="text-emerald-500 hover:text-emerald-700">
<button
type="button"
onClick={handleAddSpeciality}
className="text-emerald-500 hover:text-emerald-700"
>
<Plus className="w-5 h-5" />
</button>
</div>

View File

@ -9,29 +9,32 @@ const lightenColor = (color, percent) => {
const num = parseInt(color.slice(1), 16),
amt = Math.round(2.55 * percent),
R = (num >> 16) + amt,
G = (num >> 8 & 0x00FF) + amt,
B = (num & 0x0000FF) + amt;
return `#${(0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1).toUpperCase()}`;
G = ((num >> 8) & 0x00ff) + amt,
B = (num & 0x0000ff) + amt;
return `#${(0x1000000 + (R < 255 ? (R < 1 ? 0 : R) : 255) * 0x10000 + (G < 255 ? (G < 1 ? 0 : G) : 255) * 0x100 + (B < 255 ? (B < 1 ? 0 : B) : 255)).toString(16).slice(1).toUpperCase()}`;
};
const darkenColor = (color, percent) => {
const num = parseInt(color.slice(1), 16),
amt = Math.round(2.55 * percent),
R = (num >> 16) - amt,
G = (num >> 8 & 0x00FF) - amt,
B = (num & 0x0000FF) - amt;
return `#${(0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1).toUpperCase()}`;
G = ((num >> 8) & 0x00ff) - amt,
B = (num & 0x0000ff) - amt;
return `#${(0x1000000 + (R < 255 ? (R < 1 ? 0 : R) : 255) * 0x10000 + (G < 255 ? (G < 1 ? 0 : G) : 255) * 0x100 + (B < 255 ? (B < 1 ? 0 : B) : 255)).toString(16).slice(1).toUpperCase()}`;
};
const SpecialityItem = ({ speciality, isDraggable = true }) => {
const [{ isDragging }, drag] = useDrag(() => ({
type: ItemTypes.SPECIALITY,
item: { id: speciality.id, name: speciality.name },
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
const [{ isDragging }, drag] = useDrag(
() => ({
type: ItemTypes.SPECIALITY,
item: { id: speciality.id, name: speciality.name },
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
canDrag: () => isDraggable,
}),
canDrag: () => isDraggable,
}), [isDraggable]);
[isDraggable]
);
return (
<div
@ -40,10 +43,12 @@ const SpecialityItem = ({ speciality, isDraggable = true }) => {
isDragging ? 'opacity-30' : 'opacity-100'
} ${isDraggable ? 'cursor-grabbing hover:shadow-lg hover:scale-105' : ''}`}
style={{
backgroundColor: isDragging ? lightenColor(speciality.color_code, 30) : speciality.color_code,
backgroundColor: isDragging
? lightenColor(speciality.color_code, 30)
: speciality.color_code,
border: `1px solid ${darkenColor(speciality.color_code, 20)}`,
color: 'white',
boxShadow: isDraggable ? '0 2px 4px rgba(0, 0, 0, 0.1)' : 'none'
boxShadow: isDraggable ? '0 2px 4px rgba(0, 0, 0, 0.1)' : 'none',
}}
>
{speciality.name}
@ -51,4 +56,4 @@ const SpecialityItem = ({ speciality, isDraggable = true }) => {
);
};
export default SpecialityItem;
export default SpecialityItem;

View File

@ -3,9 +3,24 @@ import SpecialitiesSection from '@/components/Structure/Configuration/Specialiti
import TeachersSection from '@/components/Structure/Configuration/TeachersSection';
import ClassesSection from '@/components/Structure/Configuration/ClassesSection';
import { ClassesProvider } from '@/context/ClassesContext';
import { BE_SCHOOL_SPECIALITIES_URL, BE_SCHOOL_TEACHERS_URL, BE_SCHOOL_SCHOOLCLASSES_URL } from '@/utils/Url';
import {
BE_SCHOOL_SPECIALITIES_URL,
BE_SCHOOL_TEACHERS_URL,
BE_SCHOOL_SCHOOLCLASSES_URL,
} from '@/utils/Url';
const StructureManagement = ({ specialities, setSpecialities, teachers, setTeachers, classes, setClasses, profiles, handleCreate, handleEdit, handleDelete }) => {
const StructureManagement = ({
specialities,
setSpecialities,
teachers,
setTeachers,
classes,
setClasses,
profiles,
handleCreate,
handleEdit,
handleDelete,
}) => {
return (
<div className="max-w-8xl mx-auto p-4 mt-6 space-y-8">
<ClassesProvider>
@ -13,9 +28,24 @@ const StructureManagement = ({ specialities, setSpecialities, teachers, setTeach
<SpecialitiesSection
specialities={specialities}
setSpecialities={setSpecialities}
handleCreate={(newData) => handleCreate(`${BE_SCHOOL_SPECIALITIES_URL}`, newData, setSpecialities)}
handleEdit={(id, updatedData) => handleEdit(`${BE_SCHOOL_SPECIALITIES_URL}`, id, updatedData, setSpecialities)}
handleDelete={(id) => handleDelete(`${BE_SCHOOL_SPECIALITIES_URL}`, id, setSpecialities)}
handleCreate={(newData) =>
handleCreate(
`${BE_SCHOOL_SPECIALITIES_URL}`,
newData,
setSpecialities
)
}
handleEdit={(id, updatedData) =>
handleEdit(
`${BE_SCHOOL_SPECIALITIES_URL}`,
id,
updatedData,
setSpecialities
)
}
handleDelete={(id) =>
handleDelete(`${BE_SCHOOL_SPECIALITIES_URL}`, id, setSpecialities)
}
/>
</div>
<div className="w-4/5 p-4 bg-white rounded-lg shadow-md">
@ -24,9 +54,20 @@ const StructureManagement = ({ specialities, setSpecialities, teachers, setTeach
setTeachers={setTeachers}
specialities={specialities}
profiles={profiles}
handleCreate={(newData) => handleCreate(`${BE_SCHOOL_TEACHERS_URL}`, newData, setTeachers)}
handleEdit={(id, updatedData) => handleEdit(`${BE_SCHOOL_TEACHERS_URL}`, id, updatedData, setTeachers)}
handleDelete={(id) => handleDelete(`${BE_SCHOOL_TEACHERS_URL}`, id, setTeachers)}
handleCreate={(newData) =>
handleCreate(`${BE_SCHOOL_TEACHERS_URL}`, newData, setTeachers)
}
handleEdit={(id, updatedData) =>
handleEdit(
`${BE_SCHOOL_TEACHERS_URL}`,
id,
updatedData,
setTeachers
)
}
handleDelete={(id) =>
handleDelete(`${BE_SCHOOL_TEACHERS_URL}`, id, setTeachers)
}
/>
</div>
<div className="w-full p-4 bg-white rounded-lg shadow-md">
@ -34,9 +75,24 @@ const StructureManagement = ({ specialities, setSpecialities, teachers, setTeach
classes={classes}
setClasses={setClasses}
teachers={teachers}
handleCreate={(newData) => handleCreate(`${BE_SCHOOL_SCHOOLCLASSES_URL}`, newData, setClasses)}
handleEdit={(id, updatedData) => handleEdit(`${BE_SCHOOL_SCHOOLCLASSES_URL}`, id, updatedData, setClasses)}
handleDelete={(id) => handleDelete(`${BE_SCHOOL_SCHOOLCLASSES_URL}`, id, setClasses)}
handleCreate={(newData) =>
handleCreate(
`${BE_SCHOOL_SCHOOLCLASSES_URL}`,
newData,
setClasses
)
}
handleEdit={(id, updatedData) =>
handleEdit(
`${BE_SCHOOL_SCHOOLCLASSES_URL}`,
id,
updatedData,
setClasses
)
}
handleDelete={(id) =>
handleDelete(`${BE_SCHOOL_SCHOOLCLASSES_URL}`, id, setClasses)
}
/>
</div>
</ClassesProvider>

View File

@ -4,9 +4,9 @@ const TabsStructure = ({ activeTab, setActiveTab, tabs }) => {
return (
<div className="flex justify-center items-center w-full">
{tabs.map((tab) => (
<button
<button
key={tab.id}
className={`tab px-4 py-2 mx-2 flex items-center justify-center space-x-2 ${activeTab === tab.id ? 'bg-emerald-600 text-white shadow-lg' : 'bg-emerald-200 text-emerald-600'} rounded-full`}
className={`tab px-4 py-2 mx-2 flex items-center justify-center space-x-2 ${activeTab === tab.id ? 'bg-emerald-600 text-white shadow-lg' : 'bg-emerald-200 text-emerald-600'} rounded-full`}
onClick={() => setActiveTab(tab.id)}
>
<tab.icon className="w-5 h-5" />
@ -18,6 +18,3 @@ const TabsStructure = ({ activeTab, setActiveTab, tabs }) => {
};
export default TabsStructure;

View File

@ -6,14 +6,20 @@ const ItemTypes = {
};
const TeacherItem = ({ teacher, isDraggable = true }) => {
const [{ isDragging }, drag] = useDrag(() => ({
type: ItemTypes.TEACHER,
item: { id: teacher.id, name: `${teacher.last_name} ${teacher.first_name}` },
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
const [{ isDragging }, drag] = useDrag(
() => ({
type: ItemTypes.TEACHER,
item: {
id: teacher.id,
name: `${teacher.last_name} ${teacher.first_name}`,
},
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
canDrag: () => isDraggable,
}),
canDrag: () => isDraggable,
}), [isDraggable]);
[isDraggable]
);
return (
<div
@ -22,9 +28,13 @@ const TeacherItem = ({ teacher, isDraggable = true }) => {
isDragging ? 'opacity-30' : 'opacity-100'
} ${isDraggable ? 'cursor-grabbing hover:shadow-lg hover:scale-105' : ''}`}
style={{
backgroundColor: isDragging ? '#d1d5db' : isDraggable ? '#10b981' : '#a7f3d0', // Change background color based on dragging state and draggable state
backgroundColor: isDragging
? '#d1d5db'
: isDraggable
? '#10b981'
: '#a7f3d0', // Change background color based on dragging state and draggable state
border: isDraggable ? '1px solid #10b981' : '1px solid #a7f3d0', // Add a border
boxShadow: isDraggable ? '0 2px 4px rgba(0, 0, 0, 0.1)' : 'none' // Add a shadow if draggable
boxShadow: isDraggable ? '0 2px 4px rgba(0, 0, 0, 0.1)' : 'none', // Add a shadow if draggable
}}
>
{teacher.last_name} {teacher.first_name}
@ -32,4 +42,4 @@ const TeacherItem = ({ teacher, isDraggable = true }) => {
);
};
export default TeacherItem;
export default TeacherItem;

View File

@ -1,5 +1,14 @@
import React, { useState, useEffect } from 'react';
import { Plus, Edit3, Trash2, GraduationCap, Check, X, Hand, Search } from 'lucide-react';
import {
Plus,
Edit3,
Trash2,
GraduationCap,
Check,
X,
Hand,
Search,
} from 'lucide-react';
import Table from '@/components/Table';
import Popup from '@/components/Popup';
import ToggleSwitch from '@/components/ToggleSwitch';
@ -18,30 +27,46 @@ const ItemTypes = {
SPECIALITY: 'speciality',
};
const SpecialitiesDropZone = ({ teacher, handleSpecialitiesChange, specialities, isEditing }) => {
const [localSpecialities, setLocalSpecialities] = useState(teacher.specialities_details || []);
const SpecialitiesDropZone = ({
teacher,
handleSpecialitiesChange,
specialities,
isEditing,
}) => {
const [localSpecialities, setLocalSpecialities] = useState(
teacher.specialities_details || []
);
useEffect(() => {
}, [specialities]);
useEffect(() => {}, [specialities]);
useEffect(() => {
setLocalSpecialities(teacher.specialities_details || []);
}, [teacher.specialities_details]);
useEffect(() => {
handleSpecialitiesChange(localSpecialities.map(speciality => speciality.id));
handleSpecialitiesChange(
localSpecialities.map((speciality) => speciality.id)
);
}, [localSpecialities]);
const [{ isOver, canDrop }, drop] = useDrop({
accept: ItemTypes.SPECIALITY,
drop: (item) => {
const specialityDetails = specialities.find(speciality => speciality.id === item.id);
const exists = localSpecialities.some(speciality => speciality.id === item.id);
const specialityDetails = specialities.find(
(speciality) => speciality.id === item.id
);
const exists = localSpecialities.some(
(speciality) => speciality.id === item.id
);
if (!exists) {
setLocalSpecialities(prevSpecialities => {
setLocalSpecialities((prevSpecialities) => {
const updatedSpecialities = [
...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;
});
@ -57,26 +82,37 @@ const SpecialitiesDropZone = ({ teacher, handleSpecialitiesChange, specialities,
});
const handleRemoveSpeciality = (id) => {
setLocalSpecialities(prevSpecialities => {
const updatedSpecialities = prevSpecialities.filter(speciality => speciality.id !== id);
setLocalSpecialities((prevSpecialities) => {
const updatedSpecialities = prevSpecialities.filter(
(speciality) => speciality.id !== id
);
return updatedSpecialities;
});
};
return (
<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' : ''
}`}
<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 && (
{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) => (
<div key={`${speciality.id}-${index}`} className="flex items-center space-x-2 mb-2">
<SpecialityItem key={speciality.id} speciality={speciality} isDraggable={false}/>
<div
key={`${speciality.id}-${index}`}
className="flex items-center space-x-2 mb-2"
>
<SpecialityItem
key={speciality.id}
speciality={speciality}
isDraggable={false}
/>
{isEditing && (
<button
type="button"
@ -92,37 +128,45 @@ const SpecialitiesDropZone = ({ teacher, handleSpecialitiesChange, specialities,
);
};
const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handleCreate, handleEdit, handleDelete }) => {
const TeachersSection = ({
teachers,
setTeachers,
specialities,
profiles,
handleCreate,
handleEdit,
handleDelete,
}) => {
const csrfToken = useCsrfToken();
const [editingTeacher, setEditingTeacher] = useState(null);
const [newTeacher, setNewTeacher] = useState(null);
const [formData, setFormData] = useState({});
const [localErrors, setLocalErrors] = useState({});
const [popupVisible, setPopupVisible] = useState(false);
const [popupMessage, setPopupMessage] = useState("");
const [popupMessage, setPopupMessage] = useState('');
const [removePopupVisible, setRemovePopupVisible] = useState(false);
const [removePopupMessage, setRemovePopupMessage] = useState("");
const [removePopupMessage, setRemovePopupMessage] = useState('');
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
const [confirmPopupVisible, setConfirmPopupVisible] = useState(false);
const [confirmPopupMessage, setConfirmPopupMessage] = useState("");
const [confirmPopupMessage, setConfirmPopupMessage] = useState('');
const [confirmPopupOnConfirm, setConfirmPopupOnConfirm] = useState(() => {});
const { selectedEstablishmentId } = useEstablishment();
const handleEmailChange = (e) => {
const email = e.target.value;
// Vérifier si l'email correspond à un profil existant
const existingProfile = profiles.find((profile) => profile.email === email);
setFormData((prevData) => ({
...prevData,
associated_profile_email: email,
existingProfileId: existingProfile ? existingProfile.id : null,
}));
if (newTeacher) {
setNewTeacher((prevData) => ({
...prevData,
@ -133,7 +177,7 @@ const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handle
};
const handleCancelConfirmation = () => {
setConfirmPopupVisible(false);
setConfirmPopupVisible(false);
};
// Récupération des messages d'erreur
@ -142,22 +186,41 @@ const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handle
};
const handleAddTeacher = () => {
setNewTeacher({ id: Date.now(), last_name: '', first_name: '', associated_profile_email: '', specialities: [], role_type: 0 });
setFormData({ last_name: '', first_name: '', associated_profile_email: '', specialities: [], role_type: 0});
setNewTeacher({
id: Date.now(),
last_name: '',
first_name: '',
associated_profile_email: '',
specialities: [],
role_type: 0,
});
setFormData({
last_name: '',
first_name: '',
associated_profile_email: '',
specialities: [],
role_type: 0,
});
};
const handleRemoveTeacher = (id) => {
return handleDelete(id)
.then(() => {
setTeachers(prevTeachers => prevTeachers.filter(teacher => teacher.id !== id));
setTeachers((prevTeachers) =>
prevTeachers.filter((teacher) => teacher.id !== id)
);
})
.catch(error => {
.catch((error) => {
logger.error(error);
});
};
const handleSaveNewTeacher = () => {
if (formData.last_name && formData.first_name && formData.associated_profile_email) {
if (
formData.last_name &&
formData.first_name &&
formData.associated_profile_email
) {
const data = {
last_name: formData.last_name,
first_name: formData.first_name,
@ -177,7 +240,7 @@ const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handle
},
specialities: formData.specialities || [],
};
handleCreate(data)
.then((createdTeacher) => {
setTeachers([createdTeacher, ...teachers]);
@ -192,7 +255,7 @@ const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handle
}
});
} else {
setPopupMessage("Tous les champs doivent être remplis et valides");
setPopupMessage('Tous les champs doivent être remplis et valides');
setPopupVisible(true);
}
};
@ -202,17 +265,24 @@ const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handle
const currentTeacher = teachers.find((teacher) => teacher.id === id);
// Vérifier si l'email correspond à un profil existant
const existingProfile = profiles.find((profile) => profile.email === currentTeacher.associated_profile_email);
const existingProfile = profiles.find(
(profile) => profile.email === currentTeacher.associated_profile_email
);
// Vérifier si l'email a été modifié
const isEmailModified = currentTeacher
? currentTeacher.associated_profile_email !== updatedData.associated_profile_email
: true;
? currentTeacher.associated_profile_email !==
updatedData.associated_profile_email
: true;
// Mettre à jour existingProfileId en fonction de l'email
updatedData.existingProfileId = existingProfile ? existingProfile.id : null;
if (updatedData.last_name && updatedData.first_name && updatedData.associated_profile_email) {
if (
updatedData.last_name &&
updatedData.first_name &&
updatedData.associated_profile_email
) {
const data = {
last_name: updatedData.last_name,
first_name: updatedData.first_name,
@ -238,7 +308,9 @@ const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handle
handleEdit(id, data)
.then((updatedTeacher) => {
setTeachers((prevTeachers) =>
prevTeachers.map((teacher) => (teacher.id === id ? { ...teacher, ...updatedTeacher } : teacher))
prevTeachers.map((teacher) =>
teacher.id === id ? { ...teacher, ...updatedTeacher } : teacher
)
);
setEditingTeacher(null);
setFormData({});
@ -251,7 +323,7 @@ const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handle
}
});
} else {
setPopupMessage("Tous les champs doivent être remplis et valides");
setPopupMessage('Tous les champs doivent être remplis et valides');
setPopupVisible(true);
}
};
@ -347,7 +419,12 @@ const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handle
);
case 'SPECIALITES':
return (
<SpecialitiesDropZone teacher={currentData} handleSpecialitiesChange={handleSpecialitiesChange} specialities={specialities} isEditing={isEditing || isCreating} />
<SpecialitiesDropZone
teacher={currentData}
handleSpecialitiesChange={handleSpecialitiesChange}
specialities={specialities}
isEditing={isEditing || isCreating}
/>
);
case 'ADMINISTRATEUR':
return (
@ -364,14 +441,20 @@ const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handle
<div className="flex justify-center space-x-2">
<button
type="button"
onClick={() => (isEditing ? handleUpdateTeacher(editingTeacher, formData) : handleSaveNewTeacher())}
onClick={() =>
isEditing
? handleUpdateTeacher(editingTeacher, formData)
: handleSaveNewTeacher()
}
className="text-green-500 hover:text-green-700"
>
<Check className="w-5 h-5" />
</button>
<button
type="button"
onClick={() => (isEditing ? setEditingTeacher(null) : setNewTeacher(null))}
onClick={() =>
isEditing ? setEditingTeacher(null) : setNewTeacher(null)
}
className="text-red-500 hover:text-red-700"
>
<X className="w-5 h-5" />
@ -384,33 +467,43 @@ const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handle
} else {
switch (column) {
case 'NOM - PRENOM':
return (
<TeacherItem key={teacher.id} teacher={teacher} />
);
return <TeacherItem key={teacher.id} teacher={teacher} />;
case 'EMAIL':
return teacher.associated_profile_email;
case 'SPECIALITES':
return (
<div className="flex justify-center space-x-2 flex-wrap">
{teacher.specialities_details.map((speciality) => (
<SpecialityItem key={speciality.id} speciality={speciality} isDraggable={false} />
<SpecialityItem
key={speciality.id}
speciality={speciality}
isDraggable={false}
/>
))}
</div>
);
case 'ADMINISTRATEUR':
if (teacher.associated_profile_email) {
const badgeClass = teacher.role_type === 1 ? 'bg-red-100 text-red-600' : 'bg-blue-100 text-blue-600';
const label = teacher.role_type === 1 ? 'OUI' : 'NON';
return (
<div key={teacher.id} className="flex justify-center items-center space-x-2">
<span className={`px-3 py-1 rounded-full font-bold ${badgeClass}`}>
{label}
</span>
</div>
);
} else {
return <i>Non définie</i>;
};
if (teacher.associated_profile_email) {
const badgeClass =
teacher.role_type === 1
? 'bg-red-100 text-red-600'
: 'bg-blue-100 text-blue-600';
const label = teacher.role_type === 1 ? 'OUI' : 'NON';
return (
<div
key={teacher.id}
className="flex justify-center items-center space-x-2"
>
<span
className={`px-3 py-1 rounded-full font-bold ${badgeClass}`}
>
{label}
</span>
</div>
);
} else {
return <i>Non définie</i>;
}
case 'MISE A JOUR':
return teacher.updated_date_formatted;
case 'ACTIONS':
@ -427,18 +520,35 @@ const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handle
type="button"
onClick={() => {
setRemovePopupVisible(true);
setRemovePopupMessage("Attentions ! \nVous êtes sur le point de supprimer l'enseignant " + teacher.last_name + " " + teacher.first_name + ".\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?");
setRemovePopupMessage(
"Attentions ! \nVous êtes sur le point de supprimer l'enseignant " +
teacher.last_name +
' ' +
teacher.first_name +
".\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?"
);
setRemovePopupOnConfirm(() => () => {
handleRemoveTeacher(teacher.id)
.then(data => {
.then((data) => {
logger.debug('Success:', data);
setPopupMessage("L'enseignant " + teacher.last_name + " " + teacher.first_name + " a été correctement supprimé");
setPopupMessage(
"L'enseignant " +
teacher.last_name +
' ' +
teacher.first_name +
' a été correctement supprimé'
);
setPopupVisible(true);
setRemovePopupVisible(false);
})
.catch(error => {
.catch((error) => {
logger.error('Error archiving data:', error);
setPopupMessage("Erreur lors de la suppression de l'enseignant " + teacher.last_name + " " + teacher.first_name);
setPopupMessage(
"Erreur lors de la suppression de l'enseignant " +
teacher.last_name +
' ' +
teacher.first_name
);
setPopupVisible(true);
setRemovePopupVisible(false);
});
@ -462,7 +572,7 @@ const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handle
{ name: 'SPECIALITES', label: 'Spécialités' },
{ name: 'ADMINISTRATEUR', label: 'Profil' },
{ name: 'MISE A JOUR', label: 'Mise à jour' },
{ name: 'ACTIONS', label: 'Actions' }
{ name: 'ACTIONS', label: 'Actions' },
];
return (
@ -473,7 +583,11 @@ const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handle
<GraduationCap className="w-6 h-6 text-emerald-500 mr-2" />
<h2 className="text-xl font-semibold">Enseignants</h2>
</div>
<button type="button" onClick={handleAddTeacher} className="text-emerald-500 hover:text-emerald-700">
<button
type="button"
onClick={handleAddTeacher}
className="text-emerald-500 hover:text-emerald-700"
>
<Plus className="w-5 h-5" />
</button>
</div>

View File

@ -1,23 +1,37 @@
import React from 'react';
import Table from '@/components/Table';
const TeachersSelectionConfiguration = ({ formData, teachers, handleTeacherSelection, selectedTeachers }) => {
const TeachersSelectionConfiguration = ({
formData,
teachers,
handleTeacherSelection,
selectedTeachers,
}) => {
return (
<div className="mt-4" style={{ maxHeight: '300px', overflowY: 'auto' }}>
<label className="mt-6 block text-2xl font-medium text-gray-700 mb-2">Enseignants</label>
<label className={`block text-sm font-medium mb-4`}>Sélection : <span className={`${formData.teachers.length !== 0 ? 'text-emerald-400' : 'text-red-300'}`}>{formData.teachers.length}</span></label>
<label className="mt-6 block text-2xl font-medium text-gray-700 mb-2">
Enseignants
</label>
<label className={`block text-sm font-medium mb-4`}>
Sélection :{' '}
<span
className={`${formData.teachers.length !== 0 ? 'text-emerald-400' : 'text-red-300'}`}
>
{formData.teachers.length}
</span>
</label>
<Table
columns={[
{
name: 'Nom',
{
name: 'Nom',
transform: (row) => row.last_name,
},
{
name: 'Prénom',
{
name: 'Prénom',
transform: (row) => row.first_name,
},
// {
// name: 'Spécialités',
// {
// name: 'Spécialités',
// transform: (row) => (
// <div className="flex flex-wrap items-center">
// {row.specialites.map(specialite => (

View File

@ -5,7 +5,9 @@ const TimeRange = ({ startTime, endTime, onStartChange, onEndChange }) => {
<div className="mb-4">
<div className="flex space-x-4">
<div className="w-1/2">
<label className="block text-sm font-medium text-gray-700 mb-2">Heure de début</label>
<label className="block text-sm font-medium text-gray-700 mb-2">
Heure de début
</label>
<input
type="time"
name="startTime"
@ -15,7 +17,9 @@ const TimeRange = ({ startTime, endTime, onStartChange, onEndChange }) => {
/>
</div>
<div className="w-1/2">
<label className="block text-sm font-medium text-gray-700 mb-2">Heure de fin</label>
<label className="block text-sm font-medium text-gray-700 mb-2">
Heure de fin
</label>
<input
type="time"
name="endTime"