refactor: Revue de la modale permettant de créer un dossier

d'inscription
This commit is contained in:
N3WT DE COMPET
2025-01-26 15:43:11 +01:00
parent 1c4d96d4c3
commit cb3f909fa4
16 changed files with 1049 additions and 814 deletions

View File

@ -1,93 +1,231 @@
import { Trash2, MoreVertical, Edit3, Plus } from 'lucide-react';
import { Plus, Trash2, Edit3, Check, X, BookOpen } from 'lucide-react';
import { useState } from 'react';
import Table from '@/components/Table';
import DropdownMenu from '@/components/DropdownMenu';
import Modal from '@/components/Modal';
import SpecialityForm from '@/components/Structure/Configuration/SpecialityForm';
import { SpecialityFormProvider } from '@/context/SpecialityFormContext';
import Popup from '@/components/Popup';
import InputTextWithColorIcon from '@/components/InputTextWithColorIcon';
import { DndProvider, useDrag } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
const SpecialitiesSection = ({ specialities, handleCreate, handleEdit, handleDelete }) => {
const ItemTypes = {
SPECIALITY: 'speciality',
};
const [isOpen, setIsOpen] = useState(false);
const [editingSpeciality, setEditingSpeciality] = useState(null);
const openEditModal = (speciality) => {
setIsOpen(true);
setEditingSpeciality(speciality);
}
const closeEditModal = () => {
setIsOpen(false);
setEditingSpeciality(null);
};
const handleModalSubmit = (updatedData) => {
if (editingSpeciality) {
handleEdit(editingSpeciality.id, updatedData);
} else {
handleCreate(updatedData);
}
closeEditModal();
};
const SpecialityItem = ({ speciality }) => {
const [{ isDragging }, drag] = useDrag(() => ({
type: ItemTypes.SPECIALITY,
item: { id: speciality.id, name: speciality.name },
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
}));
return (
<div className="mb-8">
<div className="flex justify-between items-center mb-4 max-w-4xl ml-0">
<h2 className="text-xl font-bold mb-4">Gestion des spécialités</h2>
<button
onClick={() => openEditModal(null)} // ouvrir le modal pour créer une nouvelle spécialité
className="flex items-center bg-emerald-600 text-white p-2 rounded-full shadow hover:bg-emerald-900 transition duration-200"
>
<Plus className="w-5 h-5" />
</button>
</div>
<div className="bg-white rounded-lg border border-gray-200 max-w-4xl ml-0">
<Table
columns={[
{
name: 'INTITULÉ',
transform: (row) => (
<div
className="inline-block px-3 py-1 rounded-full font-bold text-white"
style={{ backgroundColor: row.color_code }}
title={row.color_code}
>
<span className="font-bold text-white">{row.name.toUpperCase()}</span>
</div>
)
},
{ name: 'DATE DE CREATION', transform: (row) => row.updated_date_formatted },
{ name: 'ACTIONS', transform: (row) => (
<DropdownMenu
buttonContent={<MoreVertical size={20} className="text-gray-400 hover:text-gray-600" />}
items={[
{ label: 'Modifier', icon:Edit3, onClick: () => openEditModal(row) },
{ label: 'Supprimer', icon: Trash2, onClick: () => handleDelete(row.id) }
]
}
buttonClassName="text-gray-400 hover:text-gray-600"
menuClassName="absolute right-0 mt-2 w-48 bg-white border border-gray-200 rounded-md shadow-lg z-10 flex flex-col items-center"
/>
)}
]}
data={specialities}
/>
</div>
{isOpen && (
<SpecialityFormProvider initialSpeciality={editingSpeciality || {}}>
<Modal
isOpen={isOpen}
setIsOpen={setIsOpen}
title={editingSpeciality ? "Modification de la spécialité" : "Création d'une nouvelle spécialité"}
size='sm:w-1/6'
ContentComponent={() => (
<SpecialityForm onSubmit={handleModalSubmit} isNew={!editingSpeciality} />
)}
/>
</SpecialityFormProvider>
)}
<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 [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 handleAddSpeciality = () => {
setNewSpeciality({ id: Date.now(), name: '', color_code: '' });
};
const handleRemoveSpeciality = (id) => {
handleDelete(id)
.then(() => {
setSpecialities(prevSpecialities => prevSpecialities.filter(speciality => speciality.id !== id));
})
.catch(error => {
console.error(error);
});
};
const handleSaveNewSpeciality = () => {
if (
newSpeciality.name) {
handleCreate(newSpeciality)
.then((createdSpeciality) => {
setSpecialities([createdSpeciality, ...specialities]);
setNewSpeciality(null);
setLocalErrors({});
})
.catch(error => {
if (error && typeof error === 'object') {
setLocalErrors(error);
} else {
console.error(error);
}
});
} else {
setPopupMessage("Tous les champs doivent être remplis et valides");
setPopupVisible(true);
}
};
const handleUpdateSpeciality = (id, updatedSpeciality) => {
if (
updatedSpeciality.name) {
handleEdit(id, updatedSpeciality)
.then((updatedSpeciality) => {
setSpecialities(specialities.map(speciality => speciality.id === id ? updatedSpeciality : speciality));
setEditingSpeciality(null);
setLocalErrors({});
})
.catch(error => {
if (error && typeof error === 'object') {
setLocalErrors(error);
} else {
console.error(error);
}
});
} else {
setPopupMessage("Tous les champs doivent être remplis et valides");
setPopupVisible(true);
}
};
const handleChange = (e) => {
const { name, value } = e.target;
let parsedValue = value;
if (name.includes('_color')) {
parsedValue = value;
}
const fieldName = name.includes('_color') ? 'color_code' : name;
if (editingSpeciality) {
setFormData((prevData) => ({
...prevData,
[fieldName]: parsedValue,
}));
} else if (newSpeciality) {
setNewSpeciality((prevData) => ({
...prevData,
[fieldName]: parsedValue,
}));
}
};
const renderSpecialityCell = (speciality, column) => {
const isEditing = editingSpeciality === speciality.id;
const isCreating = newSpeciality && newSpeciality.id === speciality.id;
const currentData = isEditing ? formData : newSpeciality;
if (isEditing || isCreating) {
switch (column) {
case 'LIBELLE':
return (
<InputTextWithColorIcon
name="name"
textValue={currentData.name}
colorValue={currentData.color_code}
onTextChange={handleChange}
onColorChange={handleChange}
placeholder="Nom de la spécialité"
errorMsg={localErrors && localErrors.name && Array.isArray(localErrors.name) ? localErrors.name[0] : ''}
/>
);
case 'ACTIONS':
return (
<div className="flex justify-center space-x-2">
<button
type="button"
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))}
className="text-red-500 hover:text-red-700"
>
<X className="w-5 h-5" />
</button>
</div>
);
default:
return null;
}
} else {
switch (column) {
case 'LIBELLE':
return (
<SpecialityItem key={speciality.id} speciality={speciality} />
);
case 'MISE A JOUR':
return speciality.updated_date_formatted;
case 'ACTIONS':
return (
<div className="flex justify-center space-x-2">
<button
type="button"
onClick={() => setEditingSpeciality(speciality.id) || setFormData(speciality)}
className="text-blue-500 hover:text-blue-700"
>
<Edit3 className="w-5 h-5" />
</button>
<button
type="button"
onClick={() => handleRemoveSpeciality(speciality.id)}
className="text-red-500 hover:text-red-700"
>
<Trash2 className="w-5 h-5" />
</button>
</div>
);
default:
return null;
}
}
};
const columns = [
{ name: 'LIBELLE', label: 'Libellé' },
{ name: 'MISE A JOUR', label: 'Date mise à jour' },
{ name: 'ACTIONS', label: 'Actions' }
];
return (
<DndProvider backend={HTML5Backend}>
<div className="space-y-4">
<div className="flex justify-between items-center">
<div className="flex items-center mb-4">
<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">
<Plus className="w-5 h-5" />
</button>
</div>
<Table
data={newSpeciality ? [newSpeciality, ...specialities] : specialities}
columns={columns}
renderCell={renderSpecialityCell}
/>
<Popup
visible={popupVisible}
message={popupMessage}
onConfirm={() => setPopupVisible(false)}
onCancel={() => setPopupVisible(false)}
uniqueConfirmButton={true}
/>
</div>
</DndProvider>
);
};
export default SpecialitiesSection;

View File

@ -1,66 +0,0 @@
import { useState } from 'react';
import { BookOpen, Palette } from 'lucide-react';
import InputTextIcon from '@/components/InputTextIcon';
import InputColorIcon from '@/components/InputColorIcon';
import Button from '@/components/Button';
import { useSpecialityForm } from '@/context/SpecialityFormContext';
const SpecialityForm = ({ onSubmit, isNew }) => {
const { formData, setFormData } = useSpecialityForm();
const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prevState) => ({
...prevState,
[name]: value,
}));
};
const handleSubmit = (e) => {
e.preventDefault();
onSubmit(formData);
};
return (
<div className="space-y-4 mt-8">
<div>
<InputTextIcon
type="text"
name="name"
IconItem={BookOpen}
placeholder="Nom de la spécialité"
value={formData.name}
onChange={handleChange}
className="w-full mt-4"
/>
</div>
<div className="mt-4">
<InputColorIcon
type="color"
name="color_code"
IconItem={Palette}
placeholder="Nom de la spécialité"
value={formData.color_code}
onChange={handleChange}
className="w-full mt-4"
/>
</div>
<div className="flex justify-end mt-4 space-x-4">
<Button text={`${isNew ? "Créer" : "Modifier"}`}
onClick={handleSubmit}
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
!formData.name
? "bg-gray-300 text-gray-700 cursor-not-allowed"
: "bg-emerald-500 text-white hover:bg-emerald-600"
}`}
primary
disabled={!formData.name}
type="submit"
name="Create" />
</div>
</div>
);
};
export default SpecialityForm;

View File

@ -9,7 +9,7 @@ const StructureManagement = ({ specialities, setSpecialities, teachers, setTeach
return (
<div className="max-w-8xl mx-auto p-4 mt-6 space-y-6">
<ClassesProvider>
<div className="p-4 bg-white rounded-lg shadow-md">
<div className="max-w-4xl p-4 bg-white rounded-lg shadow-md">
<SpecialitiesSection
specialities={specialities}
setSpecialities={setSpecialities}
@ -18,9 +18,10 @@ const StructureManagement = ({ specialities, setSpecialities, teachers, setTeach
handleDelete={(id) => handleDelete(`${BE_SCHOOL_SPECIALITY_URL}`, id, setSpecialities)}
/>
</div>
<div className="p-4 bg-white rounded-lg shadow-md">
<div className="max-w-8xl p-4 bg-white rounded-lg shadow-md">
<TeachersSection
teachers={teachers}
setTeachers={setTeachers}
specialities={specialities}
handleCreate={(newData) => handleCreate(`${BE_SCHOOL_TEACHER_URL}`, newData, setTeachers)}
handleEdit={(id, updatedData) => handleEdit(`${BE_SCHOOL_TEACHER_URL}`, id, updatedData, setTeachers)}

View File

@ -1,122 +0,0 @@
import React, { useState } from 'react';
import { GraduationCap, Mail, BookOpen, Check } from 'lucide-react';
import InputTextIcon from '@/components/InputTextIcon';
import Button from '@/components/Button';
import CheckBoxList from '@/components/CheckBoxList';
import ToggleSwitch from '@/components/ToggleSwitch'
import { useTeacherForm } from '@/context/TeacherFormContext';
const TeacherForm = ({ onSubmit, isNew, specialities }) => {
const { formData, setFormData } = useTeacherForm();
const handleToggleChange = () => {
setFormData({ ...formData, droit: 1-formData.droit.id });
};
const handleChange = (e) => {
const target = e.target || e.currentTarget;
const { name, value, type, checked } = target;
if (type === 'checkbox') {
setFormData((prevState) => {
const newValues = checked
? [...(prevState[name] || []), parseInt(value, 10)]
: (prevState[name] || []).filter((v) => v !== parseInt(value, 10));
return {
...prevState,
[name]: newValues,
};
});
} else {
setFormData((prevState) => ({
...prevState,
[name]: type === 'radio' ? parseInt(value, 10) : value,
}));
}
};
const handleSubmit = () => {
onSubmit(formData, isNew);
};
const getSpecialityLabel = (speciality) => {
return `${speciality.name}`;
};
const isLabelAttenuated = (item) => {
return !formData.specialities.includes(parseInt(item.id));
};
return (
<form onSubmit={handleSubmit} className="space-y-4 mt-8">
<div>
<InputTextIcon
name="last_name"
type="text"
IconItem={GraduationCap}
placeholder="Nom de l'enseignant"
value={formData.last_name}
onChange={handleChange}
className="w-full"
/>
</div>
<div>
<InputTextIcon
name="first_name"
type="text"
IconItem={GraduationCap}
placeholder="Prénom de l'enseignant"
value={formData.first_name}
onChange={handleChange}
className="w-full"
/>
</div>
<div>
<InputTextIcon
name="email"
type="email"
IconItem={Mail}
placeholder="Email de l'enseignant"
value={formData.email}
onChange={handleChange}
className="w-full mt-4"
/>
</div>
<div className="flex space-x-4">
<CheckBoxList
items={specialities}
formData={formData}
handleChange={handleChange}
fieldName="specialities"
label="Spécialités"
icon={BookOpen}
className="w-full mt-4"
itemLabelFunc={getSpecialityLabel}
labelAttenuated={isLabelAttenuated}
/>
</div>
<div className='mt-4'>
<ToggleSwitch
label="Administrateur"
checked={formData.droit.id}
onChange={handleToggleChange}
/>
</div>
<div className="flex justify-end mt-4 space-x-4">
<Button text={`${isNew ? "Créer" : "Modifier"}`}
onClick={handleSubmit}
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
(!formData.last_name || !formData.first_name || !formData.email || formData.specialities.length === 0)
? "bg-gray-300 text-gray-700 cursor-not-allowed"
: "bg-emerald-500 text-white hover:bg-emerald-600"
}`}
primary
disabled={(!formData.last_name || !formData.first_name || !formData.email || formData.specialities.length === 0)}
type="submit"
name="Create" />
</div>
</form>
);
};
export default TeacherForm;

View File

@ -1,162 +1,359 @@
import { Trash2, MoreVertical, Edit3, Plus } from 'lucide-react';
import { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { Plus, Edit3, Trash2, GraduationCap, Check, X } from 'lucide-react';
import Table from '@/components/Table';
import DropdownMenu from '@/components/DropdownMenu';
import Modal from '@/components/Modal';
import TeacherForm from '@/components/Structure/Configuration/TeacherForm';
import useCsrfToken from '@/hooks/useCsrfToken';
import { TeacherFormProvider } from '@/context/TeacherFormContext';
import Popup from '@/components/Popup';
import InputTextIcon from '@/components/InputTextIcon';
import ToggleSwitch from '@/components/ToggleSwitch';
import { createProfile, updateProfile } from '@/app/lib/authAction';
import useCsrfToken from '@/hooks/useCsrfToken';
import { DndProvider, useDrag, useDrop } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
const TeachersSection = ({ teachers, specialities , handleCreate, handleEdit, handleDelete}) => {
const ItemTypes = {
SPECIALITY: 'speciality',
};
const [isOpen, setIsOpen] = useState(false);
const [editingTeacher, setEditingTeacher] = useState(null);
const SpecialitiesDropZone = ({ teacher, handleSpecialitiesChange, specialities, isEditing }) => {
const [localSpecialities, setLocalSpecialities] = useState(teacher.specialities_details || []);
const csrfToken = useCsrfToken();
useEffect(() => {
setLocalSpecialities(teacher.specialities_details || []);
}, [teacher.specialities_details]);
const openEditModal = (teacher) => {
setIsOpen(true);
setEditingTeacher(teacher);
}
useEffect(() => {
handleSpecialitiesChange(localSpecialities.map(speciality => speciality.id));
}, [localSpecialities]);
const closeEditModal = () => {
setIsOpen(false);
setEditingTeacher(null);
};
const handleModalSubmit = (updatedData) => {
if (editingTeacher) {
// Modification du profil
const data = {
email: updatedData.email,
username: updatedData.email,
droit:updatedData.droit
const [{ isOver }, drop] = useDrop(() => ({
accept: ItemTypes.SPECIALITY,
drop: (item) => {
const specialityDetails = specialities.find(speciality => speciality.id === item.id);
if (!localSpecialities.some(speciality => speciality.id === item.id)) {
setLocalSpecialities(prevSpecialities => [
...prevSpecialities,
{ id: item.id, name: specialityDetails.name, color_code: specialityDetails.color_code }
]);
}
},
collect: (monitor) => ({
isOver: !!monitor.isOver(),
}),
}));
updateProfile(updatedData.associated_profile,data,csrfToken)
.then(response => {
console.log('Success:', response);
console.log('UpdateData:', updatedData);
handleEdit(editingTeacher.id, updatedData);
})
.catch(error => {
console.error('Error fetching data:', error);
error = error.errorMessage;
console.log(error);
});
} else {
// Création d'un profil associé à l'adresse mail du responsable saisie
// Le profil est inactif
const data = {
email: updatedData.email,
password: 'Provisoire01!',
username: updatedData.email,
is_active: 1, // On rend le profil actif : on considère qu'au moment de la configuration de l'école un abonnement a été souscrit
droit:updatedData.droit
}
createProfile(data,csrfToken)
.then(response => {
console.log('Success:', response);
console.log('UpdateData:', updatedData);
if (response.id) {
let idProfil = response.id;
updatedData.associated_profile = idProfil;
handleCreate(updatedData);
}
})
.catch(error => {
console.error('Error fetching data:', error);
error = error.errorMessage;
console.log(error);
});
}
closeEditModal();
const handleRemoveSpeciality = (id) => {
setLocalSpecialities(prevSpecialities => {
const updatedSpecialities = prevSpecialities.filter(speciality => speciality.id !== id);
return updatedSpecialities;
});
};
return (
<div className="mb-8">
<div className="flex justify-between items-center mb-4 max-w-8xl ml-0">
<h2 className="text-xl font-bold mb-4">Gestion des enseignants</h2>
<button
onClick={() => openEditModal(null)} // ouvrir le modal pour créer une nouvelle spécialité
className="flex items-center bg-emerald-600 text-white p-2 rounded-full shadow hover:bg-emerald-900 transition duration-200"
>
<Plus className="w-5 h-5" />
</button>
</div>
<div className="bg-white rounded-lg border border-gray-200 max-w-8xl ml-0">
<Table
columns={[
{ name: 'NOM', transform: (row) => row.last_name },
{ name: 'PRENOM', transform: (row) => row.first_name },
{ name: 'MAIL', transform: (row) => row.email },
{
name: 'SPÉCIALITÉS',
transform: (row) => (
<div key={row.id} className="flex flex-wrap justify-center items-center space-x-2">
{row.specialities_details.map((speciality,index) => (
<span
key={`${speciality.id}-${index}`}
className="px-3 py-1 rounded-full font-bold text-white"
style={{ backgroundColor: speciality.color_code }}
title={speciality.name}
>
{speciality.name}
</span>
))}
</div>
)
},
{
name: 'TYPE PROFIL',
transform: (row) => {
if (row.associated_profile) {
const badgeClass = row.droit.label === 'ECOLE' ? 'bg-blue-100 text-blue-600' : 'bg-red-100 text-red-600';
return (
<div key={row.id} className="flex justify-center items-center space-x-2">
<span className={`px-3 py-1 rounded-full font-bold ${badgeClass}`}>
{row.droit.label}
</span>
</div>
);
} else {
return <i>Non définie</i>;
}
}
},
{ name: 'DATE DE CREATION', transform: (row) => row.updated_date_formatted },
{ name: 'ACTIONS', transform: (row) => (
<DropdownMenu
buttonContent={<MoreVertical size={20} className="text-gray-400 hover:text-gray-600" />}
items={[
{ label: 'Modifier', icon:Edit3, onClick: () => openEditModal(row) },
{ label: 'Supprimer', icon: Trash2, onClick: () => handleDelete(row.id) }
]
}
buttonClassName="text-gray-400 hover:text-gray-600"
menuClassName="absolute right-0 mt-2 w-48 bg-white border border-gray-200 rounded-md shadow-lg z-10 flex flex-col items-center"
/>
)}
]}
data={teachers}
/>
</div>
{isOpen && (
<TeacherFormProvider initialTeacher={editingTeacher || {}}>
<Modal
isOpen={isOpen}
setIsOpen={setIsOpen}
title={editingTeacher ? "Modification de l'enseignant" : "Création d'un nouvel enseignant"}
size='sm:w-1/4'
ContentComponent={() => (
<TeacherForm teacher={editingTeacher || {}} onSubmit={handleModalSubmit} isNew={!editingTeacher} specialities={specialities} />
)}
/>
</TeacherFormProvider>
)}
<div ref={drop} className="p-2 rounded-md flex flex-col items-center">
{localSpecialities.map((speciality, index) => (
<div key={`${speciality.id}-${index}`} className="flex items-center space-x-2 mb-2">
<span
className="px-3 py-1 rounded-full font-bold text-white"
style={{ backgroundColor: speciality.color_code }}
title={speciality.name}
>
{speciality.name}
</span>
{isEditing && (
<button
type="button"
onClick={() => handleRemoveSpeciality(speciality.id)}
className="text-red-500 hover:text-red-700"
>
<X className="w-4 h-4" />
</button>
)}
</div>
))}
</div>
);
};
const TeachersSection = ({ teachers, setTeachers, specialities, 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 handleAddTeacher = () => {
setNewTeacher({ id: Date.now(), last_name: '', first_name: '', email: '', specialities: [], droit: 0 });
setFormData({ last_name: '', first_name: '', email: '', specialities: [], droit: 0 });
};
const handleRemoveTeacher = (id) => {
handleDelete(id)
.then(() => {
setTeachers(prevTeachers => prevTeachers.filter(teacher => teacher.id !== id));
})
.catch(error => {
console.error(error);
});
};
const handleSaveNewTeacher = () => {
if (formData.last_name && formData.first_name && formData.email) {
const data = {
email: formData.email,
password: 'Provisoire01!',
username: formData.email,
is_active: 1,
droit: formData.droit,
};
createProfile(data, csrfToken)
.then(response => {
console.log('Success:', response);
if (response.id) {
let idProfil = response.id;
newTeacher.associated_profile = idProfil;
handleCreate(newTeacher)
.then((createdTeacher) => {
setTeachers([createdTeacher, ...teachers]);
setNewTeacher(null);
setLocalErrors({});
});
}
})
.catch(error => {
if (error && typeof error === 'object') {
setLocalErrors(error);
} else {
console.error(error);
}
});
} else {
setPopupMessage("Tous les champs doivent être remplis et valides");
setPopupVisible(true);
}
};
const handleUpdateTeacher = (id, updatedData) => {
console.log('UpdatedData:', updatedData);
const data = {
email: updatedData.email,
username: updatedData.email,
droit: updatedData.droit.id,
};
updateProfile(updatedData.associated_profile, data, csrfToken)
.then(response => {
console.log('Success:', response);
handleEdit(id, updatedData)
.then((updatedTeacher) => {
setTeachers(prevTeachers => prevTeachers.map(teacher => teacher.id === id ? { ...teacher, ...updatedTeacher } : teacher));
setEditingTeacher(null);
setFormData({});
})
})
.catch(error => {
console.error(error);
});
};
const handleChange = (e) => {
const { name, value } = e.target;
let parsedValue = value;
if (editingTeacher) {
setFormData((prevData) => ({
...prevData,
[name]: parsedValue,
}));
} else if (newTeacher) {
setNewTeacher((prevData) => ({
...prevData,
[name]: parsedValue,
}));
setFormData((prevData) => ({
...prevData,
[name]: parsedValue,
}));
}
};
const handleSpecialitiesChange = (selectedSpecialities) => {
if (editingTeacher) {
setFormData((prevData) => ({
...prevData,
specialities: selectedSpecialities,
}));
} else if (newTeacher) {
setNewTeacher((prevData) => ({
...prevData,
specialities: selectedSpecialities,
}));
setFormData((prevData) => ({
...prevData,
specialities: selectedSpecialities,
}));
}
};
const renderTeacherCell = (teacher, column) => {
const isEditing = editingTeacher === teacher.id;
const isCreating = newTeacher && newTeacher.id === teacher.id;
const currentData = isEditing ? formData : newTeacher;
if (isEditing || isCreating) {
switch (column) {
case 'NOM':
return (
<InputTextIcon
name="last_name"
value={currentData.last_name}
onChange={handleChange}
placeholder="Nom de l'enseignant"
errorMsg={localErrors && localErrors.last_name && Array.isArray(localErrors.last_name) ? localErrors.last_name[0] : ''}
/>
);
case 'PRENOM':
return (
<InputTextIcon
name="first_name"
value={currentData.first_name}
onChange={handleChange}
placeholder="Prénom de l'enseignant"
errorMsg={localErrors && localErrors.first_name && Array.isArray(localErrors.firstname) ? localErrors.firstname[0] : ''}
/>
);
case 'EMAIL':
return (
<InputTextIcon
name="email"
value={currentData.email}
onChange={handleChange}
placeholder="Email de l'enseignant"
errorMsg={localErrors && localErrors.email && Array.isArray(localErrors.email) ? localErrors.email[0] : ''}
/>
);
case 'SPECIALITES':
return (
<SpecialitiesDropZone teacher={currentData} handleSpecialitiesChange={handleSpecialitiesChange} specialities={specialities} isEditing={isEditing || isCreating} />
);
// case 'PROFIL':
// return (
// <ToggleSwitch
// name="profile"
// checked={currentData.profile}
// onChange={handleChange}
// />
// );
case 'ACTIONS':
return (
<div className="flex justify-center space-x-2">
<button
type="button"
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))}
className="text-red-500 hover:text-red-700"
>
<X className="w-5 h-5" />
</button>
</div>
);
default:
return null;
}
} else {
switch (column) {
case 'NOM':
return teacher.last_name;
case 'PRENOM':
return teacher.first_name;
case 'EMAIL':
return teacher.email;
case 'SPECIALITES':
return (
<SpecialitiesDropZone teacher={teacher} handleSpecialitiesChange={handleSpecialitiesChange} specialities={specialities} isEditing={false} />
);
case 'PROFIL':
if (teacher.associated_profile) {
const badgeClass = teacher.droit.label === 'ECOLE' ? 'bg-blue-100 text-blue-600' : 'bg-red-100 text-red-600';
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}`}>
{teacher.droit.label}
</span>
</div>
);
} else {
return <i>Non définie</i>;
};
case 'MISE A JOUR':
return teacher.updated_date_formatted;
case 'ACTIONS':
return (
<div className="flex justify-center space-x-2">
<button
type="button"
onClick={() => setEditingTeacher(teacher.id) || setFormData(teacher)}
className="text-blue-500 hover:text-blue-700"
>
<Edit3 className="w-5 h-5" />
</button>
<button
type="button"
onClick={() => handleRemoveTeacher(teacher.id)}
className="text-red-500 hover:text-red-700"
>
<Trash2 className="w-5 h-5" />
</button>
</div>
);
default:
return null;
}
}
};
const columns = [
{ name: 'NOM', label: 'Nom' },
{ name: 'PRENOM', label: 'Prénom' },
{ name: 'EMAIL', label: 'Email' },
{ name: 'SPECIALITES', label: 'Spécialités' },
{ name: 'PROFIL', label: 'Profil' },
{ name: 'MISE A JOUR', label: 'Mise à jour' },
{ name: 'ACTIONS', label: 'Actions' }
];
return (
<DndProvider backend={HTML5Backend}>
<div className="space-y-4">
<div className="flex justify-between items-center">
<div className="flex items-center mb-4">
<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">
<Plus className="w-5 h-5" />
</button>
</div>
<Table
data={newTeacher ? [newTeacher, ...teachers] : teachers}
columns={columns}
renderCell={renderTeacherCell}
/>
<Popup
visible={popupVisible}
message={popupMessage}
onConfirm={() => setPopupVisible(false)}
onCancel={() => setPopupVisible(false)}
uniqueConfirmButton={true}
/>
</div>
</DndProvider>
);
};
export default TeachersSection;

View File

@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { Plus, Trash, Edit3, Check, X, Percent, EuroIcon, Tag } from 'lucide-react';
import { Plus, Trash2, Edit3, Check, X, Percent, EuroIcon, Tag } from 'lucide-react';
import Table from '@/components/Table';
import InputTextIcon from '@/components/InputTextIcon';
import Popup from '@/components/Popup';
@ -181,7 +181,7 @@ const DiscountsSection = ({ discounts, setDiscounts, handleCreate, handleEdit, h
onClick={() => handleRemoveDiscount(discount.id)}
className="text-red-500 hover:text-red-700"
>
<Trash className="w-5 h-5" />
<Trash2 className="w-5 h-5" />
</button>
</div>
);

View File

@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { Plus, Trash, Edit3, Check, X, EyeOff, Eye, CreditCard, BookOpen } from 'lucide-react';
import { Plus, Trash2, Edit3, Check, X, EyeOff, Eye, CreditCard, BookOpen } from 'lucide-react';
import Table from '@/components/Table';
import InputTextIcon from '@/components/InputTextIcon';
import Popup from '@/components/Popup';
@ -190,7 +190,7 @@ const FeesSection = ({ fees, setFees, discounts, handleCreate, handleEdit, handl
onClick={() => handleRemoveFee(fee.id)}
className="text-red-500 hover:text-red-700"
>
<Trash className="w-5 h-5" />
<Trash2 className="w-5 h-5" />
</button>
</div>
);