mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: Gestion des profils ADMIN/ECOLE (création des enseignants)
This commit is contained in:
@ -68,6 +68,7 @@ class ProfileSerializer(serializers.ModelSerializer):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
class ProfileRoleSerializer(serializers.ModelSerializer):
|
class ProfileRoleSerializer(serializers.ModelSerializer):
|
||||||
|
id = serializers.IntegerField(required=False)
|
||||||
profile = serializers.PrimaryKeyRelatedField(queryset=Profile.objects.all(), required=False)
|
profile = serializers.PrimaryKeyRelatedField(queryset=Profile.objects.all(), required=False)
|
||||||
profile_data = ProfileSerializer(write_only=True, required=False)
|
profile_data = ProfileSerializer(write_only=True, required=False)
|
||||||
associated_profile_email = serializers.SerializerMethodField()
|
associated_profile_email = serializers.SerializerMethodField()
|
||||||
|
|||||||
@ -32,7 +32,7 @@ class Teacher(models.Model):
|
|||||||
last_name = models.CharField(max_length=100)
|
last_name = models.CharField(max_length=100)
|
||||||
first_name = models.CharField(max_length=100)
|
first_name = models.CharField(max_length=100)
|
||||||
specialities = models.ManyToManyField(Speciality, blank=True)
|
specialities = models.ManyToManyField(Speciality, blank=True)
|
||||||
profile_role = models.OneToOneField(ProfileRole, on_delete=models.CASCADE, related_name='teacher_profile', null=True, blank=True)
|
profile_role = models.OneToOneField(ProfileRole, on_delete=models.CASCADE, related_name='teacher_profile', blank=True)
|
||||||
updated_date = models.DateTimeField(auto_now=True)
|
updated_date = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
@ -33,72 +33,85 @@ class TeacherSerializer(serializers.ModelSerializer):
|
|||||||
specialities = serializers.PrimaryKeyRelatedField(queryset=Speciality.objects.all(), many=True, required=False)
|
specialities = serializers.PrimaryKeyRelatedField(queryset=Speciality.objects.all(), many=True, required=False)
|
||||||
specialities_details = serializers.SerializerMethodField()
|
specialities_details = serializers.SerializerMethodField()
|
||||||
updated_date_formatted = serializers.SerializerMethodField()
|
updated_date_formatted = serializers.SerializerMethodField()
|
||||||
role_type_display = serializers.SerializerMethodField()
|
role_type = serializers.SerializerMethodField()
|
||||||
role_type = serializers.IntegerField(write_only=True)
|
|
||||||
associated_profile_email = serializers.EmailField(write_only=True)
|
|
||||||
profile_role = serializers.PrimaryKeyRelatedField(queryset=ProfileRole.objects.all(), required=False)
|
profile_role = serializers.PrimaryKeyRelatedField(queryset=ProfileRole.objects.all(), required=False)
|
||||||
associated_profile_email_display = serializers.SerializerMethodField()
|
profile_role_data = ProfileRoleSerializer(write_only=True, required=False)
|
||||||
|
associated_profile_email = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Teacher
|
model = Teacher
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
def create_or_update_profile_role(self, profile, associated_profile_email, establishment_id, role_type):
|
def create_or_update_teacher(self, teacher_data):
|
||||||
# Mettre à jour l'email du profil si nécessaire
|
profile_role_data = teacher_data.pop('profile_role_data', None)
|
||||||
if profile.email != associated_profile_email:
|
profile_role = teacher_data.pop('profile_role', None)
|
||||||
profile.email = associated_profile_email
|
|
||||||
profile.username = associated_profile_email
|
|
||||||
profile.save()
|
|
||||||
|
|
||||||
profile_role, created = ProfileRole.objects.update_or_create(
|
# Gestion du ProfileRole
|
||||||
profile=profile,
|
if profile_role_data:
|
||||||
establishment_id=establishment_id,
|
# Vérifiez si 'profile' est un objet ou une clé primaire
|
||||||
defaults={'role_type': role_type, 'is_active': True}
|
if isinstance(profile_role_data.get('profile'), Profile):
|
||||||
)
|
profile_role_data['profile'] = profile_role_data['profile'].id
|
||||||
|
establishment_id = profile_role_data.pop('establishment').id
|
||||||
|
profile_role_data['establishment'] = establishment_id
|
||||||
|
|
||||||
if not created:
|
# Vérifiez si un ID est fourni pour une mise à jour
|
||||||
profile_role.role_type = role_type
|
profile_role_id = profile_role_data.get('id')
|
||||||
profile_role.establishment_id = establishment_id
|
if profile_role_id:
|
||||||
profile_role.save()
|
# Mettre à jour un ProfileRole existant
|
||||||
|
try:
|
||||||
|
profile_role_instance = ProfileRole.objects.get(id=profile_role_id)
|
||||||
|
profile_role_serializer = ProfileRoleSerializer(profile_role_instance, data=profile_role_data)
|
||||||
|
profile_role_serializer.is_valid(raise_exception=True)
|
||||||
|
profile_role = profile_role_serializer.save()
|
||||||
|
except ProfileRole.DoesNotExist:
|
||||||
|
raise serializers.ValidationError({"profile_role_data": f"ProfileRole with id {profile_role_id} does not exist."})
|
||||||
|
else:
|
||||||
|
# Créer un nouveau ProfileRole
|
||||||
|
profile_role_serializer = ProfileRoleSerializer(data=profile_role_data)
|
||||||
|
profile_role_serializer.is_valid(raise_exception=True)
|
||||||
|
profile_role = profile_role_serializer.save()
|
||||||
|
elif profile_role:
|
||||||
|
# Récupérer un ProfileRole existant
|
||||||
|
profile_role = ProfileRole.objects.get(id=profile_role.id)
|
||||||
|
|
||||||
return profile_role
|
if profile_role:
|
||||||
|
teacher_data['profile_role'] = profile_role
|
||||||
|
|
||||||
|
# Vérifier si un Teacher existe déjà pour ce profile_role
|
||||||
|
teacher_instance = Teacher.objects.filter(profile_role=profile_role).first()
|
||||||
|
|
||||||
|
if teacher_instance:
|
||||||
|
# Mettre à jour les champs existants
|
||||||
|
for key, value in teacher_data.items():
|
||||||
|
setattr(teacher_instance, key, value)
|
||||||
|
teacher_instance.save()
|
||||||
|
created = False
|
||||||
|
else:
|
||||||
|
# Créer un nouveau Teacher
|
||||||
|
teacher_instance = Teacher.objects.create(**teacher_data)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
return teacher_instance
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
specialities_data = validated_data.pop('specialities', None)
|
specialities_data = validated_data.pop('specialities', [])
|
||||||
associated_profile_email = validated_data.pop('associated_profile_email')
|
teacher_instance = self.create_or_update_teacher(validated_data)
|
||||||
establishment_id = validated_data.get('establishment')
|
|
||||||
role_type = validated_data.pop('role_type')
|
|
||||||
|
|
||||||
profile, created = Profile.objects.get_or_create(
|
# Associer les spécialités
|
||||||
email=associated_profile_email,
|
|
||||||
defaults={'username': associated_profile_email}
|
|
||||||
)
|
|
||||||
|
|
||||||
profile_role = self.create_or_update_profile_role(profile, associated_profile_email, establishment_id, role_type)
|
|
||||||
|
|
||||||
teacher = Teacher.objects.create(profile_role=profile_role, **validated_data)
|
|
||||||
if specialities_data:
|
if specialities_data:
|
||||||
teacher.specialities.set(specialities_data)
|
teacher_instance.specialities.set(specialities_data)
|
||||||
teacher.save()
|
|
||||||
return teacher
|
return teacher_instance
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
specialities_data = validated_data.pop('specialities', [])
|
specialities_data = validated_data.pop('specialities', [])
|
||||||
associated_profile_email = validated_data.pop('associated_profile_email', instance.profile_role.profile.email)
|
teacher_instance = self.create_or_update_teacher(validated_data)
|
||||||
establishment_id = validated_data.get('establishment', instance.profile_role.establishment.id)
|
|
||||||
role_type = validated_data.get('role_type', instance.profile_role.role_type)
|
|
||||||
|
|
||||||
profile = instance.profile_role.profile
|
# Mettre à jour les spécialités
|
||||||
|
|
||||||
profile_role = self.create_or_update_profile_role(profile, associated_profile_email, establishment_id, role_type)
|
|
||||||
instance.profile_role = profile_role
|
|
||||||
|
|
||||||
instance.last_name = validated_data.get('last_name', instance.last_name)
|
|
||||||
instance.first_name = validated_data.get('first_name', instance.first_name)
|
|
||||||
instance.save()
|
|
||||||
if specialities_data:
|
if specialities_data:
|
||||||
instance.specialities.set(specialities_data)
|
teacher_instance.specialities.set(specialities_data)
|
||||||
return instance
|
|
||||||
|
return teacher_instance
|
||||||
|
|
||||||
def get_updated_date_formatted(self, obj):
|
def get_updated_date_formatted(self, obj):
|
||||||
utc_time = timezone.localtime(obj.updated_date) # Convert to local time
|
utc_time = timezone.localtime(obj.updated_date) # Convert to local time
|
||||||
@ -114,14 +127,11 @@ class TeacherSerializer(serializers.ModelSerializer):
|
|||||||
return obj.profile_role.profile.email
|
return obj.profile_role.profile.email
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_role_type_display(self, obj):
|
def get_role_type(self, obj):
|
||||||
if obj.profile_role:
|
if obj.profile_role:
|
||||||
return obj.profile_role.role_type
|
return obj.profile_role.role_type
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_associated_profile_email_display(self, obj):
|
|
||||||
return self.get_associated_profile_email(obj)
|
|
||||||
|
|
||||||
class PlanningSerializer(serializers.ModelSerializer):
|
class PlanningSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Planning
|
model = Planning
|
||||||
|
|||||||
@ -116,7 +116,7 @@ class TeacherDetailView(APIView):
|
|||||||
return JsonResponse(teacher_serializer.errors, safe=False)
|
return JsonResponse(teacher_serializer.errors, safe=False)
|
||||||
|
|
||||||
def delete(self, request, id):
|
def delete(self, request, id):
|
||||||
return delete_object(Teacher, id, related_field='profile')
|
return delete_object(Teacher, id, related_field='profile_role')
|
||||||
|
|
||||||
@method_decorator(csrf_protect, name='dispatch')
|
@method_decorator(csrf_protect, name='dispatch')
|
||||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import {
|
|||||||
fetchTuitionPaymentPlans,
|
fetchTuitionPaymentPlans,
|
||||||
fetchRegistrationPaymentModes,
|
fetchRegistrationPaymentModes,
|
||||||
fetchTuitionPaymentModes } from '@/app/actions/schoolAction';
|
fetchTuitionPaymentModes } from '@/app/actions/schoolAction';
|
||||||
import { fetchProfileRoles } from '@/app/actions/authAction';
|
import { fetchProfileRoles, fetchProfiles } from '@/app/actions/authAction';
|
||||||
import SidebarTabs from '@/components/SidebarTabs';
|
import SidebarTabs from '@/components/SidebarTabs';
|
||||||
import FilesGroupsManagement from '@/components/Structure/Files/FilesGroupsManagement';
|
import FilesGroupsManagement from '@/components/Structure/Files/FilesGroupsManagement';
|
||||||
import { fetchRegistrationTemplateMaster } from "@/app/actions/registerFileGroupAction";
|
import { fetchRegistrationTemplateMaster } from "@/app/actions/registerFileGroupAction";
|
||||||
@ -43,6 +43,7 @@ export default function Page() {
|
|||||||
const [tuitionPaymentPlans, setTuitionPaymentPlans] = useState([]);
|
const [tuitionPaymentPlans, setTuitionPaymentPlans] = useState([]);
|
||||||
const [registrationPaymentModes, setRegistrationPaymentModes] = useState([]);
|
const [registrationPaymentModes, setRegistrationPaymentModes] = useState([]);
|
||||||
const [tuitionPaymentModes, setTuitionPaymentModes] = useState([]);
|
const [tuitionPaymentModes, setTuitionPaymentModes] = useState([]);
|
||||||
|
const [profiles, setProfiles] = useState([]);
|
||||||
|
|
||||||
const csrfToken = useCsrfToken();
|
const csrfToken = useCsrfToken();
|
||||||
const { selectedEstablishmentId } = useEstablishment();
|
const { selectedEstablishmentId } = useEstablishment();
|
||||||
@ -91,6 +92,14 @@ export default function Page() {
|
|||||||
|
|
||||||
// Fetch data for tuition payment modes
|
// Fetch data for tuition payment modes
|
||||||
handleTuitionPaymentModes();
|
handleTuitionPaymentModes();
|
||||||
|
|
||||||
|
fetchProfiles()
|
||||||
|
.then(data => {
|
||||||
|
setProfiles(data);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
logger.error('Error fetching profileRoles:', error);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}, [selectedEstablishmentId]);
|
}, [selectedEstablishmentId]);
|
||||||
|
|
||||||
@ -258,6 +267,7 @@ export default function Page() {
|
|||||||
setTeachers={setTeachers}
|
setTeachers={setTeachers}
|
||||||
classes={classes}
|
classes={classes}
|
||||||
setClasses={setClasses}
|
setClasses={setClasses}
|
||||||
|
profiles={profiles}
|
||||||
handleCreate={handleCreate}
|
handleCreate={handleCreate}
|
||||||
handleEdit={handleEdit}
|
handleEdit={handleEdit}
|
||||||
handleDelete={handleDelete}
|
handleDelete={handleDelete}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
import { User, Mail, Phone, UserCheck, DollarSign, Percent } from 'lucide-react';
|
import { User, Mail, Phone, UserCheck, DollarSign, Percent } from 'lucide-react';
|
||||||
import InputTextIcon from '@/components/InputTextIcon';
|
import InputTextIcon from '@/components/InputTextIcon';
|
||||||
import ToggleSwitch from '@/components/ToggleSwitch';
|
import ToggleSwitch from '@/components/ToggleSwitch';
|
||||||
@ -51,6 +51,8 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
|
|||||||
const [popupVisible, setPopupVisible] = useState(false);
|
const [popupVisible, setPopupVisible] = useState(false);
|
||||||
const [popupMessage, setPopupMessage] = useState("");
|
const [popupMessage, setPopupMessage] = useState("");
|
||||||
|
|
||||||
|
const formDataRef = useRef(formData);
|
||||||
|
|
||||||
const stepTitles = {
|
const stepTitles = {
|
||||||
1: 'Nouvel élève',
|
1: 'Nouvel élève',
|
||||||
2: 'Nouveau Responsable',
|
2: 'Nouveau Responsable',
|
||||||
@ -103,6 +105,10 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
|
|||||||
|
|
||||||
}, [registrationDiscounts, registrationFees]);
|
}, [registrationDiscounts, registrationFees]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
formDataRef.current = formData; // Mettre à jour la référence à chaque changement de formData
|
||||||
|
}, [formData]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setStep(currentStep || 1);
|
setStep(currentStep || 1);
|
||||||
}, [currentStep]);
|
}, [currentStep]);
|
||||||
@ -119,24 +125,39 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const nextStep = () => {
|
const validateAndSubmit = async () => {
|
||||||
if (step === 2) {
|
const existingProfile = profiles.find(profile => profile.email === formData.guardianEmail);
|
||||||
// Vérifier si l'adresse email saisie est rattachée à un profil existant
|
|
||||||
const existingProfile = profiles.find(profile => profile.email === formData.guardianEmail);
|
if (existingProfile) {
|
||||||
|
console.log('existingProfile : ', existingProfile);
|
||||||
if (existingProfile) {
|
await setFormData((prevData) => ({
|
||||||
// Vérifier si le profil a un rôle de type PARENT
|
...prevData,
|
||||||
const parentRole = existingProfile.roles.find(role => role.role_type === 2);
|
guardianEmail: existingProfile.email, // Mettre à jour le champ guardianEmail avec l'email du profil
|
||||||
console.log('Profil associé trouvé !', existingProfile);
|
isExistingParentProfile: true, // Indiquer que le profil est un parent existant
|
||||||
setFormData((prevData) => ({
|
existingProfileId: existingProfile.id,
|
||||||
...prevData,
|
}));
|
||||||
guardianEmail: existingProfile.email, // Mettre à jour le champ guardianEmail avec l'email du profil
|
|
||||||
isExistingParentProfile: true, // Indiquer que le profil est un parent existant
|
|
||||||
existingProfileId: existingProfile.id
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Utiliser la dernière version de formData via formDataRef
|
||||||
|
logger.debug('Submitting form data:', formDataRef.current);
|
||||||
|
onSubmit(formDataRef.current);
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextStep = async () => {
|
||||||
|
if (step === 2) {
|
||||||
|
const existingProfile = profiles.find(profile => profile.email === formData.guardianEmail);
|
||||||
|
|
||||||
|
if (existingProfile) {
|
||||||
|
console.log('existingProfile : ', existingProfile);
|
||||||
|
await setFormData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
guardianEmail: existingProfile.email, // Mettre à jour le champ guardianEmail avec l'email du profil
|
||||||
|
isExistingParentProfile: true, // Indiquer que le profil est un parent existant
|
||||||
|
existingProfileId: existingProfile.id,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!showOnlyStep2 && step < steps.length) {
|
if (!showOnlyStep2 && step < steps.length) {
|
||||||
setStep(step + 1);
|
setStep(step + 1);
|
||||||
}
|
}
|
||||||
@ -182,9 +203,11 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
|
|||||||
};
|
};
|
||||||
|
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
|
setTimeout(() => {
|
||||||
logger.debug('Submitting form data:', formData);
|
logger.debug('Submitting form data:', formData);
|
||||||
onSubmit(formData);
|
onSubmit(formData);
|
||||||
}
|
}, 0);
|
||||||
|
};
|
||||||
|
|
||||||
const handleRegistrationFeeSelection = (feeId) => {
|
const handleRegistrationFeeSelection = (feeId) => {
|
||||||
setFormData((prevData) => {
|
setFormData((prevData) => {
|
||||||
@ -683,7 +706,7 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
|
|||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
text="Valider"
|
text="Valider"
|
||||||
onClick={submit}
|
onClick={validateAndSubmit}
|
||||||
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
|
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
|
||||||
(
|
(
|
||||||
(step === 1 && !isStep1Valid) ||
|
(step === 1 && !isStep1Valid) ||
|
||||||
|
|||||||
@ -196,35 +196,44 @@ const ProfileDirectory = ({ profileRoles, handleActivateProfile, handleDeletePro
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
{ name: 'Utilisateur', transform: (row) => (
|
{ name: 'Utilisateur', transform: (row) => (
|
||||||
<div className="flex items-center justify-center space-x-2">
|
<div className="flex items-center justify-center space-x-2 relative">
|
||||||
<span>{row.associated_person?.teacher_name}</span>
|
<span>{row.associated_person?.teacher_name}</span>
|
||||||
{row.associated_person && (
|
{row.associated_person && (
|
||||||
<Tooltip content={
|
<div
|
||||||
<div>
|
className="relative group"
|
||||||
<div className="mb-2">
|
onMouseEnter={() => handleTooltipVisibility(row.id)} // Afficher la tooltip pour cette ligne
|
||||||
<strong>Classes associées:</strong>
|
onMouseLeave={handleTooltipHide} // Cacher la tooltip
|
||||||
<div className="flex flex-wrap justify-center space-x-2">
|
>
|
||||||
{row.associated_person?.classes?.map(classe => (
|
<button className="relative text-blue-500 hover:text-blue-700 flex items-center justify-center">
|
||||||
<span key={classe.id} className="px-2 py-1 rounded-full bg-gray-200 text-gray-800">
|
<div className="w-6 h-6 bg-blue-100 text-blue-700 rounded-full flex items-center justify-center font-bold">
|
||||||
{classe.name}
|
<Info className="w-4 h-4" /> {/* Icône Info */}
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<strong>Spécialités:</strong>
|
|
||||||
<div className="flex flex-wrap justify-center space-x-2">
|
|
||||||
{row.associated_person?.specialities?.map(speciality => (
|
|
||||||
<SpecialityItem key={speciality.name} speciality={speciality} isDraggable={false} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}>
|
|
||||||
<button className="text-blue-500 hover:text-blue-700">
|
|
||||||
<Info className="w-5 h-5" />
|
|
||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
{visibleTooltipId === row.id && ( // Afficher uniquement si l'ID correspond
|
||||||
|
<div
|
||||||
|
className="fixed z-50 w-96 p-4 bg-white border border-gray-200 rounded shadow-lg -translate-x-1/2"
|
||||||
|
>
|
||||||
|
<div className="mb-2">
|
||||||
|
<strong>Classes associées:</strong>
|
||||||
|
<div className="flex flex-wrap justify-center space-x-2 mt-4">
|
||||||
|
{row.associated_person?.classes?.map(classe => (
|
||||||
|
<span key={classe.id} className="px-2 py-1 rounded-full bg-gray-200 text-gray-800">
|
||||||
|
{classe.name}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Spécialités:</strong>
|
||||||
|
<div className="flex flex-wrap justify-center space-x-2 mt-4">
|
||||||
|
{row.associated_person?.specialities?.map(speciality => (
|
||||||
|
<SpecialityItem key={speciality.name} speciality={speciality} isDraggable={false} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import ClassesSection from '@/components/Structure/Configuration/ClassesSection'
|
|||||||
import { ClassesProvider } from '@/context/ClassesContext';
|
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, handleCreate, handleEdit, handleDelete }) => {
|
const StructureManagement = ({ specialities, setSpecialities, teachers, setTeachers, classes, setClasses, profiles, handleCreate, handleEdit, handleDelete }) => {
|
||||||
return (
|
return (
|
||||||
<div className="max-w-8xl mx-auto p-4 mt-6 space-y-8">
|
<div className="max-w-8xl mx-auto p-4 mt-6 space-y-8">
|
||||||
<ClassesProvider>
|
<ClassesProvider>
|
||||||
@ -23,6 +23,7 @@ const StructureManagement = ({ specialities, setSpecialities, teachers, setTeach
|
|||||||
teachers={teachers}
|
teachers={teachers}
|
||||||
setTeachers={setTeachers}
|
setTeachers={setTeachers}
|
||||||
specialities={specialities}
|
specialities={specialities}
|
||||||
|
profiles={profiles}
|
||||||
handleCreate={(newData) => handleCreate(`${BE_SCHOOL_TEACHERS_URL}`, newData, setTeachers)}
|
handleCreate={(newData) => handleCreate(`${BE_SCHOOL_TEACHERS_URL}`, newData, setTeachers)}
|
||||||
handleEdit={(id, updatedData) => handleEdit(`${BE_SCHOOL_TEACHERS_URL}`, id, updatedData, setTeachers)}
|
handleEdit={(id, updatedData) => handleEdit(`${BE_SCHOOL_TEACHERS_URL}`, id, updatedData, setTeachers)}
|
||||||
handleDelete={(id) => handleDelete(`${BE_SCHOOL_TEACHERS_URL}`, id, setTeachers)}
|
handleDelete={(id) => handleDelete(`${BE_SCHOOL_TEACHERS_URL}`, id, setTeachers)}
|
||||||
|
|||||||
@ -92,7 +92,7 @@ const SpecialitiesDropZone = ({ teacher, handleSpecialitiesChange, specialities,
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, handleEdit, handleDelete }) => {
|
const TeachersSection = ({ teachers, setTeachers, specialities, profiles, handleCreate, handleEdit, handleDelete }) => {
|
||||||
const csrfToken = useCsrfToken();
|
const csrfToken = useCsrfToken();
|
||||||
const [editingTeacher, setEditingTeacher] = useState(null);
|
const [editingTeacher, setEditingTeacher] = useState(null);
|
||||||
const [newTeacher, setNewTeacher] = useState(null);
|
const [newTeacher, setNewTeacher] = useState(null);
|
||||||
@ -111,6 +111,27 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
|
|
||||||
const { selectedEstablishmentId } = useEstablishment();
|
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,
|
||||||
|
associated_profile_email: email,
|
||||||
|
existingProfileId: existingProfile ? existingProfile.id : null,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleCancelConfirmation = () => {
|
const handleCancelConfirmation = () => {
|
||||||
setConfirmPopupVisible(false);
|
setConfirmPopupVisible(false);
|
||||||
};
|
};
|
||||||
@ -140,12 +161,23 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
const data = {
|
const data = {
|
||||||
last_name: formData.last_name,
|
last_name: formData.last_name,
|
||||||
first_name: formData.first_name,
|
first_name: formData.first_name,
|
||||||
associated_profile_email: formData.associated_profile_email,
|
profile_role_data: {
|
||||||
establishment: selectedEstablishmentId,
|
establishment: selectedEstablishmentId,
|
||||||
role_type: formData.role_type,
|
role_type: formData.role_type || 0,
|
||||||
specialities: formData.specialities
|
is_active: true,
|
||||||
|
...(formData.existingProfileId
|
||||||
|
? { profile: formData.existingProfileId }
|
||||||
|
: {
|
||||||
|
profile_data: {
|
||||||
|
email: formData.associated_profile_email,
|
||||||
|
username: formData.associated_profile_email,
|
||||||
|
password: 'Provisoire01!',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
specialities: formData.specialities || [],
|
||||||
};
|
};
|
||||||
|
|
||||||
handleCreate(data)
|
handleCreate(data)
|
||||||
.then((createdTeacher) => {
|
.then((createdTeacher) => {
|
||||||
setTeachers([createdTeacher, ...teachers]);
|
setTeachers([createdTeacher, ...teachers]);
|
||||||
@ -166,30 +198,59 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdateTeacher = (id, updatedData) => {
|
const handleUpdateTeacher = (id, updatedData) => {
|
||||||
if (updatedData.last_name && updatedData.first_name && updatedData.associated_profile_email_display) {
|
// Récupérer l'enseignant actuel à partir de la liste des enseignants
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Vérifier si l'email a été modifié
|
||||||
|
const isEmailModified = currentTeacher
|
||||||
|
? 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) {
|
||||||
const data = {
|
const data = {
|
||||||
last_name: formData.last_name,
|
last_name: updatedData.last_name,
|
||||||
first_name: formData.first_name,
|
first_name: updatedData.first_name,
|
||||||
associated_profile_email: formData.associated_profile_email || formData.associated_profile_email_display,
|
profile_role_data: {
|
||||||
establishment: selectedEstablishmentId,
|
id: updatedData.profile_role,
|
||||||
role_type: formData.role_type,
|
establishment: selectedEstablishmentId,
|
||||||
specialities: formData.specialities
|
role_type: updatedData.role_type || 0,
|
||||||
|
is_active: true,
|
||||||
|
...(isEmailModified
|
||||||
|
? {
|
||||||
|
profile_data: {
|
||||||
|
id: updatedData.existingProfileId,
|
||||||
|
email: updatedData.associated_profile_email,
|
||||||
|
username: updatedData.associated_profile_email,
|
||||||
|
password: 'Provisoire01!',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: { profile: updatedData.existingProfileId }),
|
||||||
|
},
|
||||||
|
specialities: updatedData.specialities || [],
|
||||||
};
|
};
|
||||||
|
|
||||||
handleEdit(id, data)
|
handleEdit(id, data)
|
||||||
.then((updatedTeacher) => {
|
.then((updatedTeacher) => {
|
||||||
setTeachers(prevTeachers => prevTeachers.map(teacher => teacher.id === id ? { ...teacher, ...updatedTeacher } : teacher));
|
setTeachers((prevTeachers) =>
|
||||||
setEditingTeacher(null);
|
prevTeachers.map((teacher) => (teacher.id === id ? { ...teacher, ...updatedTeacher } : teacher))
|
||||||
setFormData({});
|
);
|
||||||
})
|
setEditingTeacher(null);
|
||||||
.catch((error) => {
|
setFormData({});
|
||||||
logger.error('Error:', error.message);
|
})
|
||||||
if (error.details) {
|
.catch((error) => {
|
||||||
|
logger.error('Error:', error.message);
|
||||||
|
if (error.details) {
|
||||||
logger.error('Form errors:', error.details);
|
logger.error('Form errors:', error.details);
|
||||||
setLocalErrors(error.details);
|
setLocalErrors(error.details);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
setPopupMessage("Tous les champs doivent être remplis et valides");
|
setPopupMessage("Tous les champs doivent être remplis et valides");
|
||||||
setPopupVisible(true);
|
setPopupVisible(true);
|
||||||
}
|
}
|
||||||
@ -242,8 +303,8 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
setEditingTeacher(teacher.id);
|
setEditingTeacher(teacher.id);
|
||||||
setFormData({
|
setFormData({
|
||||||
...teacher,
|
...teacher,
|
||||||
associated_profile_email: teacher.associated_profile_email_display,
|
associated_profile_email: teacher.associated_profile_email,
|
||||||
role_type: teacher.role_type_display,
|
role_type: teacher.role_type,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -278,8 +339,8 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
<InputText
|
<InputText
|
||||||
name="associated_profile_email"
|
name="associated_profile_email"
|
||||||
type="email"
|
type="email"
|
||||||
value={currentData.associated_profile_email || teacher.associated_profile_email_display || ''}
|
value={currentData.associated_profile_email || ''}
|
||||||
onChange={handleChange}
|
onChange={handleEmailChange}
|
||||||
placeholder="Adresse email de l'enseignant"
|
placeholder="Adresse email de l'enseignant"
|
||||||
errorMsg={getError('email')}
|
errorMsg={getError('email')}
|
||||||
/>
|
/>
|
||||||
@ -327,7 +388,7 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
<TeacherItem key={teacher.id} teacher={teacher} />
|
<TeacherItem key={teacher.id} teacher={teacher} />
|
||||||
);
|
);
|
||||||
case 'EMAIL':
|
case 'EMAIL':
|
||||||
return teacher.associated_profile_email_display;
|
return teacher.associated_profile_email;
|
||||||
case 'SPECIALITES':
|
case 'SPECIALITES':
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center space-x-2 flex-wrap">
|
<div className="flex justify-center space-x-2 flex-wrap">
|
||||||
@ -337,9 +398,9 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
case 'ADMINISTRATEUR':
|
case 'ADMINISTRATEUR':
|
||||||
if (teacher.associated_profile_email_display) {
|
if (teacher.associated_profile_email) {
|
||||||
const badgeClass = teacher.role_type_display === 1 ? 'bg-red-100 text-red-600' : 'bg-blue-100 text-blue-600';
|
const badgeClass = teacher.role_type === 1 ? 'bg-red-100 text-red-600' : 'bg-blue-100 text-blue-600';
|
||||||
const label = teacher.role_type_display === 1 ? 'OUI' : 'NON';
|
const label = teacher.role_type === 1 ? 'OUI' : 'NON';
|
||||||
return (
|
return (
|
||||||
<div key={teacher.id} className="flex justify-center items-center space-x-2">
|
<div key={teacher.id} className="flex justify-center items-center space-x-2">
|
||||||
<span className={`px-3 py-1 rounded-full font-bold ${badgeClass}`}>
|
<span className={`px-3 py-1 rounded-full font-bold ${badgeClass}`}>
|
||||||
|
|||||||
Reference in New Issue
Block a user