mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: Création d'un annuaire / mise à jour du subscribe
This commit is contained in:
@ -1,6 +1,8 @@
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from Auth.models import Profile, ProfileRole
|
from Auth.models import Profile, ProfileRole
|
||||||
from Establishment.models import Establishment
|
from Establishment.models import Establishment
|
||||||
|
from Subscriptions.models import Guardian, RegistrationForm
|
||||||
|
from School.models import Teacher
|
||||||
|
|
||||||
class ProfileSerializer(serializers.ModelSerializer):
|
class ProfileSerializer(serializers.ModelSerializer):
|
||||||
id = serializers.IntegerField(required=False)
|
id = serializers.IntegerField(required=False)
|
||||||
@ -14,7 +16,7 @@ class ProfileSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
def get_roles(self, obj):
|
def get_roles(self, obj):
|
||||||
roles = ProfileRole.objects.filter(profile=obj)
|
roles = ProfileRole.objects.filter(profile=obj)
|
||||||
return [{'role_type': role.role_type, 'establishment': role.establishment.id, 'is_active': role.is_active} for role in roles]
|
return [{'role_type': role.role_type, 'establishment': role.establishment.id, 'establishment_name': role.establishment.name, 'is_active': role.is_active} for role in roles]
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
user = Profile(
|
user = Profile(
|
||||||
@ -48,10 +50,12 @@ class ProfileSerializer(serializers.ModelSerializer):
|
|||||||
class ProfileRoleSerializer(serializers.ModelSerializer):
|
class ProfileRoleSerializer(serializers.ModelSerializer):
|
||||||
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_person = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ProfileRole
|
model = ProfileRole
|
||||||
fields = ['role_type', 'establishment', 'is_active', 'profile', 'profile_data']
|
fields = ['id', 'role_type', 'establishment', 'is_active', 'profile', 'profile_data', 'associated_profile_email', 'associated_person']
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
profile_data = validated_data.pop('profile_data', None)
|
profile_data = validated_data.pop('profile_data', None)
|
||||||
@ -83,3 +87,39 @@ class ProfileRoleSerializer(serializers.ModelSerializer):
|
|||||||
instance.is_active = validated_data.get('is_active', instance.is_active)
|
instance.is_active = validated_data.get('is_active', instance.is_active)
|
||||||
instance.save()
|
instance.save()
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
def get_associated_profile_email(self, obj):
|
||||||
|
if obj.profile:
|
||||||
|
return obj.profile.email
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_associated_person(self, obj):
|
||||||
|
if obj.role_type == ProfileRole.RoleType.PROFIL_PARENT:
|
||||||
|
guardian = Guardian.objects.filter(profile_role=obj).first()
|
||||||
|
if guardian:
|
||||||
|
students = guardian.student_set.all()
|
||||||
|
students_list = []
|
||||||
|
for student in students:
|
||||||
|
registration_form = RegistrationForm.objects.filter(student=student).first()
|
||||||
|
registration_status = registration_form.status if registration_form else None
|
||||||
|
students_list.append({
|
||||||
|
"student_name": f"{student.last_name} {student.first_name}",
|
||||||
|
"registration_status": registration_status
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
"guardian_name": f"{guardian.last_name} {guardian.first_name}",
|
||||||
|
"students": students_list
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
teacher = Teacher.objects.filter(profile_role=obj).first()
|
||||||
|
if teacher:
|
||||||
|
classes = teacher.schoolclass_set.all()
|
||||||
|
classes_list = [{"id": classe.id, "name": classe.atmosphere_name} for classe in classes]
|
||||||
|
specialities = teacher.specialities.all()
|
||||||
|
specialities_list = [{"name": speciality.name, "color_code": speciality.color_code} for speciality in specialities]
|
||||||
|
return {
|
||||||
|
"teacher_name": f"{teacher.last_name} {teacher.first_name}",
|
||||||
|
"classes": classes_list,
|
||||||
|
"specialities": specialities_list
|
||||||
|
}
|
||||||
|
return None
|
||||||
@ -200,7 +200,7 @@ class LoginView(APIView):
|
|||||||
primary_role = ProfileRole.objects.filter(profile=user, role_type=role_type, is_active=True).first()
|
primary_role = ProfileRole.objects.filter(profile=user, role_type=role_type, is_active=True).first()
|
||||||
|
|
||||||
if not primary_role:
|
if not primary_role:
|
||||||
return JsonResponse({"errorMessage": "Role not assigned to the user"}, status=status.HTTP_401_UNAUTHORIZED)
|
return JsonResponse({"errorMessage": "Profil inactif"}, status=status.HTTP_401_UNAUTHORIZED)
|
||||||
|
|
||||||
login(request, user)
|
login(request, user)
|
||||||
user.save()
|
user.save()
|
||||||
@ -305,10 +305,10 @@ class RefreshJWTView(APIView):
|
|||||||
role_type = payload.get('role_type')
|
role_type = payload.get('role_type')
|
||||||
|
|
||||||
# Récupérer le rôle principal de l'utilisateur
|
# Récupérer le rôle principal de l'utilisateur
|
||||||
primary_role = ProfileRole.objects.filter(profile=user, role_type=role_type).first()
|
primary_role = ProfileRole.objects.filter(profile=user, role_type=role_type, is_active=True).first()
|
||||||
|
|
||||||
if not primary_role:
|
if not primary_role:
|
||||||
return JsonResponse({'errorMessage': 'No role assigned to the user'}, status=400)
|
return JsonResponse({'errorMessage': 'Profil inactif'}, status=400)
|
||||||
|
|
||||||
# Générer un nouveau Access Token avec les informations complètes
|
# Générer un nouveau Access Token avec les informations complètes
|
||||||
new_access_payload = {
|
new_access_payload = {
|
||||||
@ -383,10 +383,7 @@ class SubscribeView(APIView):
|
|||||||
retourErreur = error.returnMessage[error.BAD_URL]
|
retourErreur = error.returnMessage[error.BAD_URL]
|
||||||
retour = ''
|
retour = ''
|
||||||
newProfilConnection = JSONParser().parse(request)
|
newProfilConnection = JSONParser().parse(request)
|
||||||
establishment_id = request.GET.get('establishment_id')
|
establishment_id = newProfilConnection['establishment_id']
|
||||||
|
|
||||||
if not establishment_id:
|
|
||||||
return JsonResponse({'message': retour, 'errorMessage': 'establishment_id manquant', "errorFields": {}, "id": -1}, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
validatorSubscription = validator.ValidatorSubscription(data=newProfilConnection)
|
validatorSubscription = validator.ValidatorSubscription(data=newProfilConnection)
|
||||||
validationOk, errorFields = validatorSubscription.validate()
|
validationOk, errorFields = validatorSubscription.validate()
|
||||||
@ -398,7 +395,7 @@ class SubscribeView(APIView):
|
|||||||
retourErreur = error.returnMessage[error.PROFIL_NOT_EXISTS]
|
retourErreur = error.returnMessage[error.PROFIL_NOT_EXISTS]
|
||||||
else:
|
else:
|
||||||
# Vérifier si le profil a déjà un rôle actif pour l'établissement donné
|
# Vérifier si le profil a déjà un rôle actif pour l'établissement donné
|
||||||
active_roles = ProfileRole.objects.filter(profile=profil, establishment_id=establishment_id, is_active=True)
|
active_roles = ProfileRole.objects.filter(profile=profil, establishment=establishment_id, is_active=True)
|
||||||
if active_roles.exists():
|
if active_roles.exists():
|
||||||
retourErreur = error.returnMessage[error.PROFIL_ACTIVE]
|
retourErreur = error.returnMessage[error.PROFIL_ACTIVE]
|
||||||
return JsonResponse({'message': retour, 'errorMessage': retourErreur, "errorFields": errorFields, "id": profil.id}, safe=False)
|
return JsonResponse({'message': retour, 'errorMessage': retourErreur, "errorFields": errorFields, "id": profil.id}, safe=False)
|
||||||
@ -408,18 +405,23 @@ class SubscribeView(APIView):
|
|||||||
profil.full_clean()
|
profil.full_clean()
|
||||||
profil.save()
|
profil.save()
|
||||||
|
|
||||||
# Utiliser le sérialiseur ProfileRoleSerializer pour créer ou mettre à jour le rôle
|
# Récupérer le ProfileRole existant pour l'établissement et le profil
|
||||||
role_data = {
|
profile_role = ProfileRole.objects.filter(profile=profil, establishment=establishment_id).first()
|
||||||
'profile': profil.id,
|
if profile_role:
|
||||||
'establishment_id': establishment_id,
|
profile_role.is_active = True
|
||||||
'role_type': ProfileRole.RoleType.PROFIL_PARENT,
|
profile_role.save()
|
||||||
'is_active': True
|
|
||||||
}
|
|
||||||
role_serializer = ProfileRoleSerializer(data=role_data)
|
|
||||||
if role_serializer.is_valid():
|
|
||||||
role_serializer.save()
|
|
||||||
else:
|
else:
|
||||||
return JsonResponse(role_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
# Si aucun ProfileRole n'existe, en créer un nouveau
|
||||||
|
role_data = {
|
||||||
|
'profile': profil.id,
|
||||||
|
'establishment': establishment_id,
|
||||||
|
'is_active': True
|
||||||
|
}
|
||||||
|
role_serializer = ProfileRoleSerializer(data=role_data)
|
||||||
|
if role_serializer.is_valid():
|
||||||
|
role_serializer.save()
|
||||||
|
else:
|
||||||
|
return JsonResponse(role_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
clear_cache()
|
clear_cache()
|
||||||
retour = error.returnMessage[error.MESSAGE_ACTIVATION_PROFILE]
|
retour = error.returnMessage[error.MESSAGE_ACTIVATION_PROFILE]
|
||||||
@ -536,7 +538,13 @@ class ProfileRoleView(APIView):
|
|||||||
responses={200: ProfileRoleSerializer(many=True)}
|
responses={200: ProfileRoleSerializer(many=True)}
|
||||||
)
|
)
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
|
establishment_id = request.GET.get('establishment_id', None)
|
||||||
|
if establishment_id is None:
|
||||||
|
return JsonResponse({'error': 'establishment_id est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
profiles_roles_List = bdd.getAllObjects(_objectName=ProfileRole)
|
profiles_roles_List = bdd.getAllObjects(_objectName=ProfileRole)
|
||||||
|
if profiles_roles_List:
|
||||||
|
profiles_roles_List = profiles_roles_List.filter(establishment=establishment_id).distinct()
|
||||||
profile_roles_serializer = ProfileRoleSerializer(profiles_roles_List, many=True)
|
profile_roles_serializer = ProfileRoleSerializer(profiles_roles_List, many=True)
|
||||||
return JsonResponse(profile_roles_serializer.data, safe=False)
|
return JsonResponse(profile_roles_serializer.data, safe=False)
|
||||||
|
|
||||||
|
|||||||
@ -103,20 +103,26 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
# Créer entre 1 et 3 ProfileRole pour chaque profil
|
# Créer entre 1 et 3 ProfileRole pour chaque profil
|
||||||
num_roles = random.randint(1, 3)
|
num_roles = random.randint(1, 3)
|
||||||
|
created_roles = set()
|
||||||
for _ in range(num_roles):
|
for _ in range(num_roles):
|
||||||
establishment = random.choice(self.establishments)
|
establishment = random.choice(self.establishments)
|
||||||
role_type = random.choice([ProfileRole.RoleType.PROFIL_ECOLE, ProfileRole.RoleType.PROFIL_ADMIN, ProfileRole.RoleType.PROFIL_PARENT])
|
role_type = random.choice([ProfileRole.RoleType.PROFIL_ECOLE, ProfileRole.RoleType.PROFIL_ADMIN, ProfileRole.RoleType.PROFIL_PARENT])
|
||||||
|
|
||||||
|
# Vérifier si le rôle existe déjà pour cet établissement
|
||||||
|
if (establishment.id, role_type) in created_roles:
|
||||||
|
continue
|
||||||
|
|
||||||
profile_role_data = {
|
profile_role_data = {
|
||||||
"profile": profile.id,
|
"profile": profile.id,
|
||||||
"establishment": establishment.id,
|
"establishment": establishment.id,
|
||||||
"role_type": role_type,
|
"role_type": role_type,
|
||||||
"is_active": True
|
"is_active": random.choice([True, False])
|
||||||
}
|
}
|
||||||
|
|
||||||
profile_role_serializer = ProfileRoleSerializer(data=profile_role_data)
|
profile_role_serializer = ProfileRoleSerializer(data=profile_role_data)
|
||||||
if profile_role_serializer.is_valid():
|
if profile_role_serializer.is_valid():
|
||||||
profile_role_serializer.save()
|
profile_role_serializer.save()
|
||||||
|
created_roles.add((establishment.id, role_type))
|
||||||
self.stdout.write(self.style.SUCCESS(f'ProfileRole for {profile.email} created successfully with role type {role_type}'))
|
self.stdout.write(self.style.SUCCESS(f'ProfileRole for {profile.email} created successfully with role type {role_type}'))
|
||||||
else:
|
else:
|
||||||
self.stdout.write(self.style.ERROR(f'Error in data for profile role: {profile_role_serializer.errors}'))
|
self.stdout.write(self.style.ERROR(f'Error in data for profile role: {profile_role_serializer.errors}'))
|
||||||
@ -129,7 +135,7 @@ class Command(BaseCommand):
|
|||||||
for fee_data in fees_data:
|
for fee_data in fees_data:
|
||||||
establishment = random.choice(self.establishments)
|
establishment = random.choice(self.establishments)
|
||||||
print(f'establishment : {establishment}')
|
print(f'establishment : {establishment}')
|
||||||
fee_data["name"] = f"{fee_data['name']} - {establishment.name}"
|
fee_data["name"] = fee_data['name']
|
||||||
fee_data["establishment"] = establishment.id
|
fee_data["establishment"] = establishment.id
|
||||||
fee_data["type"] = random.choice([FeeType.REGISTRATION_FEE, FeeType.TUITION_FEE])
|
fee_data["type"] = random.choice([FeeType.REGISTRATION_FEE, FeeType.TUITION_FEE])
|
||||||
|
|
||||||
@ -145,7 +151,7 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
for discount_data in discounts_data:
|
for discount_data in discounts_data:
|
||||||
establishment = random.choice(self.establishments)
|
establishment = random.choice(self.establishments)
|
||||||
discount_data["name"] = f"{discount_data['name']} - {establishment.name}"
|
discount_data["name"] = discount_data['name']
|
||||||
discount_data["establishment"] = establishment.id
|
discount_data["establishment"] = establishment.id
|
||||||
discount_data["type"] = random.choice([FeeType.REGISTRATION_FEE, FeeType.TUITION_FEE])
|
discount_data["type"] = random.choice([FeeType.REGISTRATION_FEE, FeeType.TUITION_FEE])
|
||||||
discount_data["discount_type"] = random.choice([DiscountType.CURRENCY, DiscountType.PERCENT])
|
discount_data["discount_type"] = random.choice([DiscountType.CURRENCY, DiscountType.PERCENT])
|
||||||
@ -216,7 +222,7 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
for speciality_data in specialities_data:
|
for speciality_data in specialities_data:
|
||||||
establishment = random.choice(self.establishments)
|
establishment = random.choice(self.establishments)
|
||||||
speciality_data["name"] = f"{speciality_data['name']} - {establishment.name}"
|
speciality_data["name"] = speciality_data['name']
|
||||||
speciality_data["establishment"] = establishment.id
|
speciality_data["establishment"] = establishment.id
|
||||||
|
|
||||||
serializer = SpecialitySerializer(data=speciality_data)
|
serializer = SpecialitySerializer(data=speciality_data)
|
||||||
@ -260,7 +266,7 @@ class Command(BaseCommand):
|
|||||||
# Générer des données fictives pour l'enseignant
|
# Générer des données fictives pour l'enseignant
|
||||||
teacher_data = {
|
teacher_data = {
|
||||||
"last_name": fake.last_name(),
|
"last_name": fake.last_name(),
|
||||||
"first_name": f"{fake.first_name()} - {profile_role.establishment.name}",
|
"first_name": fake.first_name(),
|
||||||
"profile_role": profile_role.id
|
"profile_role": profile_role.id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,7 +293,7 @@ class Command(BaseCommand):
|
|||||||
for index, class_data in enumerate(school_classes_data, start=1):
|
for index, class_data in enumerate(school_classes_data, start=1):
|
||||||
# Randomize establishment
|
# Randomize establishment
|
||||||
establishment = random.choice(self.establishments)
|
establishment = random.choice(self.establishments)
|
||||||
class_data["atmosphere_name"] = f"Classe {index} - {establishment.name}"
|
class_data["atmosphere_name"] = f"Classe {index}"
|
||||||
class_data["establishment"] = establishment.id
|
class_data["establishment"] = establishment.id
|
||||||
|
|
||||||
# Randomize levels
|
# Randomize levels
|
||||||
@ -295,9 +301,12 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
# Randomize teachers
|
# Randomize teachers
|
||||||
establishment_teachers = list(Teacher.objects.filter(profile_role__establishment=establishment))
|
establishment_teachers = list(Teacher.objects.filter(profile_role__establishment=establishment))
|
||||||
num_teachers = min(random.randint(1, 10), len(establishment_teachers))
|
if len(establishment_teachers) > 0:
|
||||||
selected_teachers = random.sample(establishment_teachers, num_teachers)
|
num_teachers = min(2, len(establishment_teachers))
|
||||||
teachers_ids = [teacher.id for teacher in selected_teachers]
|
selected_teachers = random.sample(establishment_teachers, num_teachers)
|
||||||
|
teachers_ids = [teacher.id for teacher in selected_teachers]
|
||||||
|
else:
|
||||||
|
teachers_ids = []
|
||||||
|
|
||||||
# Use the serializer to create or update the school class
|
# Use the serializer to create or update the school class
|
||||||
class_data["teachers"] = teachers_ids
|
class_data["teachers"] = teachers_ids
|
||||||
@ -315,7 +324,7 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
for establishment in self.establishments:
|
for establishment in self.establishments:
|
||||||
for i in range(1, 4): # Créer 3 groupes de fichiers par établissement
|
for i in range(1, 4): # Créer 3 groupes de fichiers par établissement
|
||||||
name = f"Fichiers d'inscription - {fake.word()} - {establishment.name}"
|
name = f"Fichiers d'inscription - {fake.word()}"
|
||||||
description = fake.sentence()
|
description = fake.sentence()
|
||||||
group_data = {
|
group_data = {
|
||||||
"name": name,
|
"name": name,
|
||||||
@ -342,8 +351,6 @@ class Command(BaseCommand):
|
|||||||
used_profiles = set()
|
used_profiles = set()
|
||||||
|
|
||||||
for _ in range(50):
|
for _ in range(50):
|
||||||
establishment = random.choice(self.establishments)
|
|
||||||
|
|
||||||
# Récupérer un profil aléatoire qui n'a pas encore été utilisé
|
# Récupérer un profil aléatoire qui n'a pas encore été utilisé
|
||||||
available_profiles = profiles_with_parent_role.exclude(id__in=used_profiles)
|
available_profiles = profiles_with_parent_role.exclude(id__in=used_profiles)
|
||||||
if not available_profiles.exists():
|
if not available_profiles.exists():
|
||||||
@ -354,7 +361,8 @@ class Command(BaseCommand):
|
|||||||
used_profiles.add(profile.id)
|
used_profiles.add(profile.id)
|
||||||
|
|
||||||
# Récupérer le ProfileRole Parent associé au profil
|
# Récupérer le ProfileRole Parent associé au profil
|
||||||
profile_role = ProfileRole.objects.filter(profile=profile, role_type=ProfileRole.RoleType.PROFIL_PARENT).first()
|
profile_roles = ProfileRole.objects.filter(profile=profile, role_type=ProfileRole.RoleType.PROFIL_PARENT)
|
||||||
|
profile_role = random.choice(profile_roles)
|
||||||
|
|
||||||
# Générer des données fictives pour le guardian
|
# Générer des données fictives pour le guardian
|
||||||
guardian_data = {
|
guardian_data = {
|
||||||
@ -370,7 +378,7 @@ class Command(BaseCommand):
|
|||||||
# Générer des données fictives pour l'étudiant
|
# Générer des données fictives pour l'étudiant
|
||||||
student_data = {
|
student_data = {
|
||||||
"last_name": fake.last_name(),
|
"last_name": fake.last_name(),
|
||||||
"first_name": f"{fake.first_name()} - {establishment.name}",
|
"first_name": fake.first_name(),
|
||||||
"address": fake.address(),
|
"address": fake.address(),
|
||||||
"birth_date": fake.date_of_birth(),
|
"birth_date": fake.date_of_birth(),
|
||||||
"birth_place": fake.city(),
|
"birth_place": fake.city(),
|
||||||
@ -398,14 +406,14 @@ class Command(BaseCommand):
|
|||||||
# Créer les données du formulaire d'inscription
|
# Créer les données du formulaire d'inscription
|
||||||
register_form_data = {
|
register_form_data = {
|
||||||
"fileGroup": RegistrationFileGroup.objects.get(id=fake.random_int(min=1, max=file_group_count)),
|
"fileGroup": RegistrationFileGroup.objects.get(id=fake.random_int(min=1, max=file_group_count)),
|
||||||
"establishment": establishment,
|
"establishment": profile_role.establishment,
|
||||||
"status": fake.random_int(min=1, max=3)
|
"status": fake.random_int(min=1, max=3)
|
||||||
}
|
}
|
||||||
|
|
||||||
# Créer ou mettre à jour le formulaire d'inscription
|
# Créer ou mettre à jour le formulaire d'inscription
|
||||||
register_form, created = RegistrationForm.objects.get_or_create(
|
register_form, created = RegistrationForm.objects.get_or_create(
|
||||||
student=student,
|
student=student,
|
||||||
establishment=establishment,
|
establishment=profile_role.establishment,
|
||||||
defaults=register_form_data
|
defaults=register_form_data
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -49,7 +49,9 @@ class TeacherSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
if profile_role_data:
|
if profile_role_data:
|
||||||
establishment_id = profile_role_data.pop('establishment').id
|
establishment_id = profile_role_data.pop('establishment').id
|
||||||
|
profile_id = profile_role_data.pop('profile').id
|
||||||
profile_role_data['establishment'] = establishment_id
|
profile_role_data['establishment'] = establishment_id
|
||||||
|
profile_role_data['profile'] = profile_id
|
||||||
|
|
||||||
# Créer l'instance de ProfileRole
|
# Créer l'instance de ProfileRole
|
||||||
profile_role_serializer = ProfileRoleSerializer(data=profile_role_data)
|
profile_role_serializer = ProfileRoleSerializer(data=profile_role_data)
|
||||||
@ -95,7 +97,9 @@ class TeacherSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
def get_role_type(self, obj):
|
def get_role_type(self, obj):
|
||||||
profile_role = obj.profile_role
|
profile_role = obj.profile_role
|
||||||
return {'role_type': profile_role.role_type, 'establishment': profile_role.establishment.name}
|
if profile_role:
|
||||||
|
return {'role_type': profile_role.role_type, 'establishment': profile_role.establishment.name}
|
||||||
|
return None
|
||||||
|
|
||||||
def get_specialities_details(self, obj):
|
def get_specialities_details(self, obj):
|
||||||
return [{'id': speciality.id, 'name': speciality.name, 'color_code': speciality.color_code} for speciality in obj.specialities.all()]
|
return [{'id': speciality.id, 'name': speciality.name, 'color_code': speciality.color_code} for speciality in obj.specialities.all()]
|
||||||
|
|||||||
@ -23,7 +23,7 @@ def envoieReinitMotDePasse(recipients, code):
|
|||||||
return errorMessage
|
return errorMessage
|
||||||
|
|
||||||
|
|
||||||
def sendRegisterForm(recipients):
|
def sendRegisterForm(recipients, establishment_id):
|
||||||
errorMessage = ''
|
errorMessage = ''
|
||||||
try:
|
try:
|
||||||
print(f'{settings.EMAIL_HOST_USER}')
|
print(f'{settings.EMAIL_HOST_USER}')
|
||||||
@ -31,7 +31,8 @@ def sendRegisterForm(recipients):
|
|||||||
EMAIL_INSCRIPTION_SUBJECT = '[N3WT-SCHOOL] Dossier Inscription'
|
EMAIL_INSCRIPTION_SUBJECT = '[N3WT-SCHOOL] Dossier Inscription'
|
||||||
context = {
|
context = {
|
||||||
'BASE_URL': settings.BASE_URL,
|
'BASE_URL': settings.BASE_URL,
|
||||||
'email': recipients
|
'email': recipients,
|
||||||
|
'establishment': establishment_id
|
||||||
}
|
}
|
||||||
|
|
||||||
subject = EMAIL_INSCRIPTION_SUBJECT
|
subject = EMAIL_INSCRIPTION_SUBJECT
|
||||||
|
|||||||
@ -38,7 +38,7 @@
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<p>Bonjour,</p>
|
<p>Bonjour,</p>
|
||||||
<p>Nous vous confirmons la réception de votre demande d'inscription, vous trouverez ci-joint le lien vers la page d'authentification : <a href="{{BASE_URL}}/users/login">{{BASE_URL}}/users/login</a></p>
|
<p>Nous vous confirmons la réception de votre demande d'inscription, vous trouverez ci-joint le lien vers la page d'authentification : <a href="{{BASE_URL}}/users/login">{{BASE_URL}}/users/login</a></p>
|
||||||
<p>S'il s'agit de votre première connexion, veuillez procéder à l'activation de votre compte à cette url : <a href="{{BASE_URL}}/users/subscribe">{{BASE_URL}}/users/subscribe</a></p>
|
<p>S'il s'agit de votre première connexion, veuillez procéder à l'activation de votre compte à cette url : <a href="{{BASE_URL}}/users/subscribe?establishment_id={{establishment}}">{{BASE_URL}}/users/subscribe</a></p>
|
||||||
<p>votre identifiant est : {{ email }}</p>
|
<p>votre identifiant est : {{ email }}</p>
|
||||||
<p>Merci de compléter votre dossier d'inscription en suivant les instructions fournies.</p>
|
<p>Merci de compléter votre dossier d'inscription en suivant les instructions fournies.</p>
|
||||||
<p>Cordialement,</p>
|
<p>Cordialement,</p>
|
||||||
|
|||||||
@ -332,8 +332,8 @@ def send(request,id):
|
|||||||
if register_form != None:
|
if register_form != None:
|
||||||
student = register_form.student
|
student = register_form.student
|
||||||
guardian = student.getMainGuardian()
|
guardian = student.getMainGuardian()
|
||||||
email = guardian.email
|
email = guardian.profile_role.profile.email
|
||||||
errorMessage = mailer.sendRegisterForm(email)
|
errorMessage = mailer.sendRegisterForm(email, register_form.establishment.pk)
|
||||||
if errorMessage == '':
|
if errorMessage == '':
|
||||||
register_form.last_update=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
|
register_form.last_update=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
|
||||||
updateStateMachine(register_form, 'envoiDI')
|
updateStateMachine(register_form, 'envoiDI')
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
"dashboard": "Dashboard",
|
"dashboard": "Dashboard",
|
||||||
"subscriptions": "Subscriptions",
|
"subscriptions": "Subscriptions",
|
||||||
"structure": "Structure",
|
"structure": "Structure",
|
||||||
|
"directory": "Directory",
|
||||||
"events": "Events",
|
"events": "Events",
|
||||||
"grades": "Grades",
|
"grades": "Grades",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
"dashboard": "Tableau de bord",
|
"dashboard": "Tableau de bord",
|
||||||
"subscriptions": "Inscriptions",
|
"subscriptions": "Inscriptions",
|
||||||
"structure": "Structure",
|
"structure": "Structure",
|
||||||
|
"directory": "Annuaire",
|
||||||
"events": "Evenements",
|
"events": "Evenements",
|
||||||
"grades": "Notes",
|
"grades": "Notes",
|
||||||
"settings": "Paramètres",
|
"settings": "Paramètres",
|
||||||
|
|||||||
66
Front-End/src/app/[locale]/admin/directory/page.js
Normal file
66
Front-End/src/app/[locale]/admin/directory/page.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
'use client'
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { fetchProfileRoles, updateProfileRoles, deleteProfileRoles } from '@/app/actions/authAction';
|
||||||
|
import logger from '@/utils/logger';
|
||||||
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
|
import DjangoCSRFToken from '@/components/DjangoCSRFToken';
|
||||||
|
import { useCsrfToken } from '@/context/CsrfContext';
|
||||||
|
import ProfileDirectory from '@/components/ProfileDirectory';
|
||||||
|
import { BE_AUTH_PROFILES_ROLES_URL } from '@/utils/Url';
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
const [profileRoles, setProfileRoles] = useState([]);
|
||||||
|
|
||||||
|
const csrfToken = useCsrfToken();
|
||||||
|
const { selectedEstablishmentId } = useEstablishment();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEstablishmentId) {
|
||||||
|
// Fetch data for profileRoles
|
||||||
|
handleProfiles();
|
||||||
|
}
|
||||||
|
}, [selectedEstablishmentId]);
|
||||||
|
|
||||||
|
const handleProfiles = () => {
|
||||||
|
fetchProfileRoles(selectedEstablishmentId)
|
||||||
|
.then(data => {
|
||||||
|
setProfileRoles(data);
|
||||||
|
})
|
||||||
|
.catch(error => logger.error('Error fetching profileRoles:', error));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = (profileRole) => {
|
||||||
|
const updatedData = { ...profileRole, is_active: !profileRole.is_active };
|
||||||
|
return updateProfileRoles(profileRole.id, updatedData, csrfToken)
|
||||||
|
.then(data => {
|
||||||
|
setProfileRoles(prevState => prevState.map(item => item.id === profileRole.id ? data : item));
|
||||||
|
return data;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
logger.error('Error editing data:', error);
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = (id) => {
|
||||||
|
return deleteProfileRoles(id, csrfToken)
|
||||||
|
.then(() => {
|
||||||
|
setProfileRoles(prevState => prevState.filter(item => item.id !== id));
|
||||||
|
logger.debug("Profile deleted successfully:", id);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
logger.error('Error deleting profile:', error);
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='p-8'>
|
||||||
|
<DjangoCSRFToken csrfToken={csrfToken} />
|
||||||
|
|
||||||
|
<div className="w-full p-4">
|
||||||
|
<ProfileDirectory profileRoles={profileRoles} handleActivateProfile={handleEdit} handleDeleteProfile={handleDelete} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -5,12 +5,13 @@ import { usePathname } from 'next/navigation';
|
|||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import {
|
import {
|
||||||
|
LayoutDashboard,
|
||||||
|
FileText,
|
||||||
|
School,
|
||||||
Users,
|
Users,
|
||||||
Building,
|
Award,
|
||||||
Home,
|
|
||||||
Calendar,
|
Calendar,
|
||||||
Settings,
|
Settings,
|
||||||
FileText,
|
|
||||||
LogOut,
|
LogOut,
|
||||||
Menu,
|
Menu,
|
||||||
X
|
X
|
||||||
@ -22,6 +23,7 @@ import {
|
|||||||
FE_ADMIN_HOME_URL,
|
FE_ADMIN_HOME_URL,
|
||||||
FE_ADMIN_SUBSCRIPTIONS_URL,
|
FE_ADMIN_SUBSCRIPTIONS_URL,
|
||||||
FE_ADMIN_STRUCTURE_URL,
|
FE_ADMIN_STRUCTURE_URL,
|
||||||
|
FE_ADMIN_DIRECTORY_URL,
|
||||||
FE_ADMIN_GRADES_URL,
|
FE_ADMIN_GRADES_URL,
|
||||||
FE_ADMIN_PLANNING_URL,
|
FE_ADMIN_PLANNING_URL,
|
||||||
FE_ADMIN_SETTINGS_URL
|
FE_ADMIN_SETTINGS_URL
|
||||||
@ -43,10 +45,11 @@ export default function Layout({
|
|||||||
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
||||||
|
|
||||||
const sidebarItems = {
|
const sidebarItems = {
|
||||||
"admin": { "id": "admin", "name": t('dashboard'), "url": FE_ADMIN_HOME_URL, "icon": Home },
|
"admin": { "id": "admin", "name": t('dashboard'), "url": FE_ADMIN_HOME_URL, "icon": LayoutDashboard },
|
||||||
"subscriptions": { "id": "subscriptions", "name": t('subscriptions'), "url": FE_ADMIN_SUBSCRIPTIONS_URL, "icon": Users },
|
"subscriptions": { "id": "subscriptions", "name": t('subscriptions'), "url": FE_ADMIN_SUBSCRIPTIONS_URL, "icon": FileText },
|
||||||
"structure": { "id": "structure", "name": t('structure'), "url": FE_ADMIN_STRUCTURE_URL, "icon": Building },
|
"structure": { "id": "structure", "name": t('structure'), "url": FE_ADMIN_STRUCTURE_URL, "icon": School },
|
||||||
"grades": { "id": "grades", "name": t('grades'), "url": FE_ADMIN_GRADES_URL, "icon": FileText },
|
"directory": { "id": "directory", "name": t('directory'), "url": FE_ADMIN_DIRECTORY_URL, "icon": Users },
|
||||||
|
"grades": { "id": "grades", "name": t('grades'), "url": FE_ADMIN_GRADES_URL, "icon": Award },
|
||||||
"planning": { "id": "planning", "name": t('events'), "url": FE_ADMIN_PLANNING_URL, "icon": Calendar },
|
"planning": { "id": "planning", "name": t('events'), "url": FE_ADMIN_PLANNING_URL, "icon": Calendar },
|
||||||
"settings": { "id": "settings", "name": t('settings'), "url": FE_ADMIN_SETTINGS_URL, "icon": Settings }
|
"settings": { "id": "settings", "name": t('settings'), "url": FE_ADMIN_SETTINGS_URL, "icon": Settings }
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,7 +6,8 @@ import FeesManagement from '@/components/Structure/Tarification/FeesManagement';
|
|||||||
import DjangoCSRFToken from '@/components/DjangoCSRFToken';
|
import DjangoCSRFToken from '@/components/DjangoCSRFToken';
|
||||||
import { useCsrfToken } from '@/context/CsrfContext';
|
import { useCsrfToken } from '@/context/CsrfContext';
|
||||||
import { ClassesProvider } from '@/context/ClassesContext';
|
import { ClassesProvider } from '@/context/ClassesContext';
|
||||||
import { createDatas,
|
import {
|
||||||
|
createDatas,
|
||||||
updateDatas,
|
updateDatas,
|
||||||
removeDatas,
|
removeDatas,
|
||||||
fetchSpecialities,
|
fetchSpecialities,
|
||||||
@ -21,11 +22,10 @@ import { createDatas,
|
|||||||
fetchTuitionPaymentPlans,
|
fetchTuitionPaymentPlans,
|
||||||
fetchRegistrationPaymentModes,
|
fetchRegistrationPaymentModes,
|
||||||
fetchTuitionPaymentModes } from '@/app/actions/schoolAction';
|
fetchTuitionPaymentModes } from '@/app/actions/schoolAction';
|
||||||
|
import { fetchProfileRoles } 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 {
|
import { fetchRegistrationTemplateMaster } from "@/app/actions/registerFileGroupAction";
|
||||||
fetchRegistrationTemplateMaster
|
|
||||||
} from "@/app/actions/registerFileGroupAction";
|
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
|
|
||||||
|
|||||||
@ -453,8 +453,8 @@ useEffect(()=>{
|
|||||||
const columns = [
|
const columns = [
|
||||||
{ name: t('studentName'), transform: (row) => row.student.last_name },
|
{ name: t('studentName'), transform: (row) => row.student.last_name },
|
||||||
{ name: t('studentFistName'), transform: (row) => row.student.first_name },
|
{ name: t('studentFistName'), transform: (row) => row.student.first_name },
|
||||||
{ name: t('mainContactMail'), transform: (row) => row.student.guardians[0].associated_profile_email },
|
{ name: t('mainContactMail'), transform: (row) => (row.student.guardians && row.student.guardians.length > 0) ? row.student.guardians[0].associated_profile_email : '' },
|
||||||
{ name: t('phone'), transform: (row) => formatPhoneNumber(row.student.guardians[0].phone) },
|
{ name: t('phone'), transform: (row) => formatPhoneNumber(row.student.guardians[0]?.phone) },
|
||||||
{ name: t('lastUpdateDate'), transform: (row) => row.formatted_last_update},
|
{ name: t('lastUpdateDate'), transform: (row) => row.formatted_last_update},
|
||||||
{ name: t('registrationFileStatus'), transform: (row) => (
|
{ name: t('registrationFileStatus'), transform: (row) => (
|
||||||
<div className="flex justify-center items-center h-full">
|
<div className="flex justify-center items-center h-full">
|
||||||
|
|||||||
@ -13,8 +13,8 @@ import { User, KeySquare } from 'lucide-react'; // Importez directement les icô
|
|||||||
import { FE_USERS_LOGIN_URL } from '@/utils/Url';
|
import { FE_USERS_LOGIN_URL } from '@/utils/Url';
|
||||||
import { useCsrfToken } from '@/context/CsrfContext';
|
import { useCsrfToken } from '@/context/CsrfContext';
|
||||||
import { subscribe } from '@/app/actions/authAction';
|
import { subscribe } from '@/app/actions/authAction';
|
||||||
const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true';
|
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
@ -30,39 +30,27 @@ export default function Page() {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const csrfToken = useCsrfToken();
|
const csrfToken = useCsrfToken();
|
||||||
|
|
||||||
useEffect(() => {
|
const establishment_id = searchParams.get('establishment_id');
|
||||||
if (useFakeData) {
|
|
||||||
setIsLoading(true);
|
|
||||||
// Simuler une réponse réussie
|
|
||||||
const data = {
|
|
||||||
errorFields: {},
|
|
||||||
errorMessage: ""
|
|
||||||
};
|
|
||||||
setUserFieldError("")
|
|
||||||
setPassword1FieldError("")
|
|
||||||
setPassword2FieldError("")
|
|
||||||
setErrorMessage("")
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
function isOK(data) {
|
function isOK(data) {
|
||||||
return data.errorMessage === ""
|
return data.errorMessage === ""
|
||||||
}
|
}
|
||||||
|
|
||||||
function subscribeFormSubmit(formData) {
|
function subscribeFormSubmit(formData) {
|
||||||
if (useFakeData) {
|
const data ={
|
||||||
// Simuler une réponse réussie
|
email: formData.get('login'),
|
||||||
const data = {
|
password1: formData.get('password1'),
|
||||||
errorFields: {},
|
password2: formData.get('password2'),
|
||||||
errorMessage: ""
|
establishment_id: establishment_id
|
||||||
};
|
}
|
||||||
|
subscribe(data,csrfToken).then(data => {
|
||||||
|
logger.debug('Success:', data);
|
||||||
setUserFieldError("")
|
setUserFieldError("")
|
||||||
setPassword1FieldError("")
|
setPassword1FieldError("")
|
||||||
setPassword2FieldError("")
|
setPassword2FieldError("")
|
||||||
setErrorMessage("")
|
setErrorMessage("")
|
||||||
if(isOK(data)){
|
if(isOK(data)){
|
||||||
setPopupMessage("Votre compte a été créé avec succès");
|
setPopupMessage(data.message);
|
||||||
setPopupVisible(true);
|
setPopupVisible(true);
|
||||||
} else {
|
} else {
|
||||||
if(data.errorMessage){
|
if(data.errorMessage){
|
||||||
@ -74,38 +62,12 @@ export default function Page() {
|
|||||||
setPassword2FieldError(data.errorFields.password2)
|
setPassword2FieldError(data.errorFields.password2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
const data ={
|
.catch(error => {
|
||||||
email: formData.get('login'),
|
logger.error('Error fetching data:', error);
|
||||||
password1: formData.get('password1'),
|
error = error.errorMessage;
|
||||||
password2: formData.get('password2'),
|
logger.debug(error);
|
||||||
}
|
});
|
||||||
subscribe(data,csrfToken).then(data => {
|
|
||||||
logger.debug('Success:', data);
|
|
||||||
setUserFieldError("")
|
|
||||||
setPassword1FieldError("")
|
|
||||||
setPassword2FieldError("")
|
|
||||||
setErrorMessage("")
|
|
||||||
if(isOK(data)){
|
|
||||||
setPopupMessage(data.message);
|
|
||||||
setPopupVisible(true);
|
|
||||||
} else {
|
|
||||||
if(data.errorMessage){
|
|
||||||
setErrorMessage(data.errorMessage);
|
|
||||||
}
|
|
||||||
if(data.errorFields){
|
|
||||||
setUserFieldError(data.errorFields.email)
|
|
||||||
setPassword1FieldError(data.errorFields.password1)
|
|
||||||
setPassword2FieldError(data.errorFields.password2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
logger.error('Error fetching data:', error);
|
|
||||||
error = error.errorMessage;
|
|
||||||
logger.debug(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLoading === true) {
|
if (isLoading === true) {
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {
|
|||||||
BE_AUTH_REFRESH_JWT_URL,
|
BE_AUTH_REFRESH_JWT_URL,
|
||||||
BE_AUTH_REGISTER_URL,
|
BE_AUTH_REGISTER_URL,
|
||||||
BE_AUTH_PROFILES_URL,
|
BE_AUTH_PROFILES_URL,
|
||||||
|
BE_AUTH_PROFILES_ROLES_URL,
|
||||||
BE_AUTH_RESET_PASSWORD_URL,
|
BE_AUTH_RESET_PASSWORD_URL,
|
||||||
BE_AUTH_NEW_PASSWORD_URL,
|
BE_AUTH_NEW_PASSWORD_URL,
|
||||||
FE_USERS_LOGIN_URL,
|
FE_USERS_LOGIN_URL,
|
||||||
@ -77,6 +78,41 @@ export const disconnect = () => {
|
|||||||
signOut({ callbackUrl: FE_USERS_LOGIN_URL });
|
signOut({ callbackUrl: FE_USERS_LOGIN_URL });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const fetchProfileRoles = (establishment) => {
|
||||||
|
return fetch(`${BE_AUTH_PROFILES_ROLES_URL}?establishment_id=${establishment}`)
|
||||||
|
.then(requestResponseHandler)
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateProfileRoles = (id, data, csrfToken) => {
|
||||||
|
const request = new Request(
|
||||||
|
`${BE_AUTH_PROFILES_ROLES_URL}/${id}`,
|
||||||
|
{
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRFToken': csrfToken
|
||||||
|
},
|
||||||
|
credentials: 'include',
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return fetch(request).then(requestResponseHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteProfileRoles = (id, csrfToken) => {
|
||||||
|
const request = new Request(
|
||||||
|
`${BE_AUTH_PROFILES_ROLES_URL}/${id}`,
|
||||||
|
{
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'X-CSRFToken': csrfToken
|
||||||
|
},
|
||||||
|
credentials: 'include'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return fetch(request).then(requestResponseHandler);
|
||||||
|
};
|
||||||
|
|
||||||
export const createProfile = (data, csrfToken) => {
|
export const createProfile = (data, csrfToken) => {
|
||||||
const request = new Request(
|
const request = new Request(
|
||||||
`${BE_AUTH_PROFILES_URL}`,
|
`${BE_AUTH_PROFILES_URL}`,
|
||||||
|
|||||||
@ -22,7 +22,7 @@ const CheckBoxList = ({
|
|||||||
<div className={`mt-2 grid ${horizontal ? 'grid-cols-6 gap-2' : 'grid-cols-1 gap-4'}`}>
|
<div className={`mt-2 grid ${horizontal ? 'grid-cols-6 gap-2' : 'grid-cols-1 gap-4'}`}>
|
||||||
{items.map(item => (
|
{items.map(item => (
|
||||||
<CheckBox
|
<CheckBox
|
||||||
key={item.id}
|
key={`${fieldName}-${item.id}`}
|
||||||
item={item}
|
item={item}
|
||||||
formData={formData}
|
formData={formData}
|
||||||
handleChange={handleChange}
|
handleChange={handleChange}
|
||||||
|
|||||||
@ -291,6 +291,24 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
|
|||||||
</div>
|
</div>
|
||||||
{formData.responsableType === 'new' && (
|
{formData.responsableType === 'new' && (
|
||||||
<>
|
<>
|
||||||
|
<InputTextIcon
|
||||||
|
name="guardianLastName"
|
||||||
|
type="text"
|
||||||
|
IconItem={User}
|
||||||
|
placeholder="Nom du responsable (optionnel)"
|
||||||
|
value={formData.guardianLastName}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="w-full mt-4"
|
||||||
|
/>
|
||||||
|
<InputTextIcon
|
||||||
|
name="guardianFirstName"
|
||||||
|
type="text"
|
||||||
|
IconItem={User}
|
||||||
|
placeholder="Prénom du responsable (optionnel)"
|
||||||
|
value={formData.guardianFirstName}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="w-full mt-4"
|
||||||
|
/>
|
||||||
<InputTextIcon
|
<InputTextIcon
|
||||||
name="guardianEmail"
|
name="guardianEmail"
|
||||||
type="email"
|
type="email"
|
||||||
|
|||||||
218
Front-End/src/components/ProfileDirectory.js
Normal file
218
Front-End/src/components/ProfileDirectory.js
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Trash2, Eye, EyeOff, ToggleLeft, ToggleRight } from 'lucide-react';
|
||||||
|
import Table from '@/components/Table';
|
||||||
|
import Popup from '@/components/Popup';
|
||||||
|
import StatusLabel from '@/components/StatusLabel';
|
||||||
|
import SpecialityItem from '@/components/Structure/Configuration/SpecialityItem';
|
||||||
|
|
||||||
|
const roleTypeToLabel = (roleType) => {
|
||||||
|
switch (roleType) {
|
||||||
|
case 0:
|
||||||
|
return 'ECOLE';
|
||||||
|
case 1:
|
||||||
|
return 'ADMIN';
|
||||||
|
case 2:
|
||||||
|
return 'PARENT';
|
||||||
|
default:
|
||||||
|
return 'UNKNOWN';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const roleTypeToBadgeClass = (roleType) => {
|
||||||
|
switch (roleType) {
|
||||||
|
case 0:
|
||||||
|
return 'bg-blue-100 text-blue-600';
|
||||||
|
case 1:
|
||||||
|
return 'bg-red-100 text-red-600';
|
||||||
|
case 2:
|
||||||
|
return 'bg-green-100 text-green-600';
|
||||||
|
default:
|
||||||
|
return 'bg-gray-100 text-gray-600';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ProfileDirectory = ({ profileRoles, handleActivateProfile, handleDeleteProfile }) => {
|
||||||
|
const parentProfiles = profileRoles.filter(profileRole => profileRole.role_type === 2);
|
||||||
|
const schoolAdminProfiles = profileRoles.filter(profileRole => profileRole.role_type !== 2);
|
||||||
|
|
||||||
|
const [popupVisible, setPopupVisible] = useState(false);
|
||||||
|
const [popupMessage, setPopupMessage] = useState("");
|
||||||
|
const [confirmPopupVisible, setConfirmPopupVisible] = useState(false);
|
||||||
|
const [confirmPopupMessage, setConfirmPopupMessage] = useState("");
|
||||||
|
const [confirmPopupOnConfirm, setConfirmPopupOnConfirm] = useState(() => {});
|
||||||
|
|
||||||
|
const handleConfirmActivateProfile = (profileRole) => {
|
||||||
|
setConfirmPopupMessage(`Êtes-vous sûr de vouloir ${profileRole.is_active ? 'désactiver' : 'activer'} ce profil ?`);
|
||||||
|
setConfirmPopupOnConfirm(() => () => {
|
||||||
|
handleActivateProfile(profileRole)
|
||||||
|
.then(() => {
|
||||||
|
setPopupMessage(`Le profil a été ${profileRole.is_active ? 'désactivé' : 'activé'} avec succès.`);
|
||||||
|
setPopupVisible(true);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
setPopupMessage(`Erreur lors de la ${profileRole.is_active ? 'désactivation' : 'activation'} du profil.`);
|
||||||
|
setPopupVisible(true);
|
||||||
|
});
|
||||||
|
setConfirmPopupVisible(false);
|
||||||
|
});
|
||||||
|
setConfirmPopupVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleConfirmDeleteProfile = (id) => {
|
||||||
|
setConfirmPopupMessage("Êtes-vous sûr de vouloir supprimer ce profil ?");
|
||||||
|
setConfirmPopupOnConfirm(() => () => {
|
||||||
|
handleDeleteProfile(id)
|
||||||
|
.then(() => {
|
||||||
|
setPopupMessage("Le profil a été supprimé avec succès.");
|
||||||
|
setPopupVisible(true);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
setPopupMessage("Erreur lors de la suppression du profil.");
|
||||||
|
setPopupVisible(true);
|
||||||
|
});
|
||||||
|
setConfirmPopupVisible(false);
|
||||||
|
});
|
||||||
|
setConfirmPopupVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const parentColumns = [
|
||||||
|
{ name: 'Identifiant', transform: (row) => row.associated_profile_email },
|
||||||
|
{ name: 'Rôle', transform: (row) => (
|
||||||
|
<span className={`px-2 py-1 rounded-full font-bold ${roleTypeToBadgeClass(row.role_type)}`}>
|
||||||
|
{roleTypeToLabel(row.role_type)}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{ name: 'Utilisateur', transform: (row) => row.associated_person?.guardian_name },
|
||||||
|
{ name: 'Elève(s) associé(s)', transform: (row) => (
|
||||||
|
<div className="flex flex-col justify-center space-y-2">
|
||||||
|
{row.associated_person?.students?.map(student => (
|
||||||
|
<span key={student.student_name} className="px-2 py-1 rounded-full text-gray-800">
|
||||||
|
{student.student_name}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{ name: 'Etat du dossier d\'inscription', transform: (row) => (
|
||||||
|
<div className="flex flex-col justify-center items-center space-y-2">
|
||||||
|
{row.associated_person?.students?.map(student => (
|
||||||
|
<StatusLabel key={student.student_name} status={student.registration_status} showDropdown={false} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Actions',
|
||||||
|
transform: (row) => (
|
||||||
|
<div className="flex justify-center space-x-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={row.is_active ? 'text-emerald-500 hover:text-emerald-700' : 'text-orange-500 hover:text-orange-700'}
|
||||||
|
onClick={() => handleConfirmActivateProfile(row)}
|
||||||
|
>
|
||||||
|
{row.is_active ? <ToggleRight className="w-5 h-5 " /> : <ToggleLeft className="w-5 h-5" />}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="text-red-500 hover:text-red-700"
|
||||||
|
onClick={() => handleConfirmDeleteProfile(row.id)}
|
||||||
|
>
|
||||||
|
<Trash2 className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const schoolAdminColumns = [
|
||||||
|
{ name: 'Identifiant', transform: (row) => row.associated_profile_email },
|
||||||
|
{ name: 'Rôle', transform: (row) => (
|
||||||
|
<span className={`px-2 py-1 rounded-full font-bold ${roleTypeToBadgeClass(row.role_type)}`}>
|
||||||
|
{roleTypeToLabel(row.role_type)}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{ name: 'Utilisateur', transform: (row) => row.associated_person?.teacher_name },
|
||||||
|
{ name: 'Classe(s) associée(s)', transform: (row) => (
|
||||||
|
<div className="flex flex-wrap justify-center space-x-2">
|
||||||
|
{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>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{ name: 'Spécialités', transform: (row) => (
|
||||||
|
<div className="flex flex-wrap justify-center space-x-2">
|
||||||
|
{row.associated_person?.specialities?.map(speciality => (
|
||||||
|
<SpecialityItem speciality={speciality} isDraggable={false}/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Actions',
|
||||||
|
transform: (row) => (
|
||||||
|
<div className="flex justify-center space-x-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={row.is_active ? 'text-emerald-500 hover:text-emerald-700' : 'text-orange-500 hover:text-orange-700'}
|
||||||
|
onClick={() => handleConfirmActivateProfile(row)}
|
||||||
|
>
|
||||||
|
{row.is_active ? <ToggleRight className="w-5 h-5 " /> : <ToggleLeft className="w-5 h-5" />}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="text-red-500 hover:text-red-700"
|
||||||
|
onClick={() => handleConfirmDeleteProfile(row.id)}
|
||||||
|
>
|
||||||
|
<Trash2 className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-white rounded-lg shadow-lg w-full p-6">
|
||||||
|
<div className="space-y-8">
|
||||||
|
<div className="max-h-128 overflow-y-auto border rounded p-4">
|
||||||
|
{parentProfiles.length === 0 ? (
|
||||||
|
<div>Aucun profil trouvé</div>
|
||||||
|
) : (
|
||||||
|
<Table
|
||||||
|
data={parentProfiles}
|
||||||
|
columns={parentColumns}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="max-h-128 overflow-y-auto border rounded p-4">
|
||||||
|
{schoolAdminProfiles.length === 0 ? (
|
||||||
|
<div>Aucun profil trouvé</div>
|
||||||
|
) : (
|
||||||
|
<Table
|
||||||
|
data={schoolAdminProfiles}
|
||||||
|
columns={schoolAdminColumns}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Popup
|
||||||
|
visible={popupVisible}
|
||||||
|
message={popupMessage}
|
||||||
|
onConfirm={() => setPopupVisible(false)}
|
||||||
|
uniqueConfirmButton={true}
|
||||||
|
/>
|
||||||
|
<Popup
|
||||||
|
visible={confirmPopupVisible}
|
||||||
|
message={confirmPopupMessage}
|
||||||
|
onConfirm={confirmPopupOnConfirm}
|
||||||
|
onCancel={() => setConfirmPopupVisible(false)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProfileDirectory;
|
||||||
@ -4,6 +4,8 @@ import { SessionProvider } from "next-auth/react"
|
|||||||
import { CsrfProvider } from '@/context/CsrfContext'
|
import { CsrfProvider } from '@/context/CsrfContext'
|
||||||
import { NextIntlClientProvider } from 'next-intl'
|
import { NextIntlClientProvider } from 'next-intl'
|
||||||
import { EstablishmentProvider } from '@/context/EstablishmentContext';
|
import { EstablishmentProvider } from '@/context/EstablishmentContext';
|
||||||
|
import { DndProvider } from 'react-dnd';
|
||||||
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
|
|
||||||
|
|
||||||
export default function Providers({ children, messages, locale, session }) {
|
export default function Providers({ children, messages, locale, session }) {
|
||||||
@ -13,13 +15,15 @@ export default function Providers({ children, messages, locale, session }) {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<SessionProvider session={session}>
|
<SessionProvider session={session}>
|
||||||
<CsrfProvider>
|
<DndProvider backend={HTML5Backend}>
|
||||||
<EstablishmentProvider>
|
<CsrfProvider>
|
||||||
<NextIntlClientProvider messages={messages} locale={locale}>
|
<EstablishmentProvider>
|
||||||
{children}
|
<NextIntlClientProvider messages={messages} locale={locale}>
|
||||||
</NextIntlClientProvider>
|
{children}
|
||||||
</EstablishmentProvider>
|
</NextIntlClientProvider>
|
||||||
</CsrfProvider>
|
</EstablishmentProvider>
|
||||||
|
</CsrfProvider>
|
||||||
|
</DndProvider>
|
||||||
</SessionProvider>
|
</SessionProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Plus, Edit3, Trash2, GraduationCap, Check, X, Hand } from 'lucide-react';
|
import { Plus, Edit3, Trash2, GraduationCap, Check, X, Hand, Search } from 'lucide-react';
|
||||||
import Table from '@/components/Table';
|
import Table from '@/components/Table';
|
||||||
import Popup from '@/components/Popup';
|
import Popup from '@/components/Popup';
|
||||||
import ToggleSwitch from '@/components/ToggleSwitch';
|
import ToggleSwitch from '@/components/ToggleSwitch';
|
||||||
@ -11,6 +11,8 @@ import InputText from '@/components/InputText';
|
|||||||
import SpecialityItem from '@/components/Structure/Configuration/SpecialityItem';
|
import SpecialityItem from '@/components/Structure/Configuration/SpecialityItem';
|
||||||
import TeacherItem from './TeacherItem';
|
import TeacherItem from './TeacherItem';
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
|
import { fetchProfiles } from '@/app/actions/authAction';
|
||||||
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
|
|
||||||
const ItemTypes = {
|
const ItemTypes = {
|
||||||
SPECIALITY: 'speciality',
|
SPECIALITY: 'speciality',
|
||||||
@ -103,14 +105,40 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
const [removePopupMessage, setRemovePopupMessage] = useState("");
|
const [removePopupMessage, setRemovePopupMessage] = useState("");
|
||||||
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
|
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
|
||||||
|
|
||||||
|
const [confirmPopupVisible, setConfirmPopupVisible] = useState(false);
|
||||||
|
const [confirmPopupMessage, setConfirmPopupMessage] = useState("");
|
||||||
|
const [confirmPopupOnConfirm, setConfirmPopupOnConfirm] = useState(() => {});
|
||||||
|
|
||||||
|
const { selectedEstablishmentId } = useEstablishment();
|
||||||
|
|
||||||
|
const handleSelectProfile = (profile) => {
|
||||||
|
setNewTeacher((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
selectedProfile: profile,
|
||||||
|
}));
|
||||||
|
setFormData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
selectedProfile: profile
|
||||||
|
}));
|
||||||
|
setConfirmPopupMessage(`Vous êtes sur le point de rattacher l'enseignant ${newTeacher?.first_name} ${newTeacher?.last_name} au profil ${profile.email} ID = ${profile.id}.`);
|
||||||
|
setConfirmPopupOnConfirm(() => () => {
|
||||||
|
setConfirmPopupVisible(false);
|
||||||
|
});
|
||||||
|
setConfirmPopupVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancelConfirmation = () => {
|
||||||
|
setConfirmPopupVisible(false);
|
||||||
|
};
|
||||||
|
|
||||||
// Récupération des messages d'erreur
|
// Récupération des messages d'erreur
|
||||||
const getError = (field) => {
|
const getError = (field) => {
|
||||||
return localErrors?.[field]?.[0];
|
return localErrors?.[field]?.[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddTeacher = () => {
|
const handleAddTeacher = () => {
|
||||||
setNewTeacher({ id: Date.now(), last_name: '', first_name: '', email: '', specialities: [], droit: 0 });
|
setNewTeacher({ id: Date.now(), last_name: '', first_name: '', selectedProfile: null, specialities: [], droit: 0 });
|
||||||
setFormData({ last_name: '', first_name: '', email: '', specialities: [], droit: 0 });
|
setFormData({ last_name: '', first_name: '', selectedProfile: null, specialities: [], droit: 0});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveTeacher = (id) => {
|
const handleRemoveTeacher = (id) => {
|
||||||
@ -124,43 +152,32 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveNewTeacher = () => {
|
const handleSaveNewTeacher = () => {
|
||||||
if (formData.last_name && formData.first_name && formData.email) {
|
if (formData.last_name && formData.first_name && formData.selectedProfile) {
|
||||||
const data = {
|
const data = {
|
||||||
email: formData.email,
|
last_name: formData.last_name,
|
||||||
password: 'Provisoire01!',
|
first_name: formData.first_name,
|
||||||
username: formData.email,
|
profile_role_data: {
|
||||||
is_active: 1,
|
role_type: formData.droit,
|
||||||
droit: formData.droit,
|
establishment: selectedEstablishmentId,
|
||||||
|
is_active: true,
|
||||||
|
profile: formData.selectedProfile.id
|
||||||
|
},
|
||||||
|
specialities: formData.specialities
|
||||||
};
|
};
|
||||||
createProfile(data, csrfToken)
|
|
||||||
.then(response => {
|
handleCreate(data)
|
||||||
logger.debug('Success:', response);
|
.then((createdTeacher) => {
|
||||||
if (response.id) {
|
setTeachers([createdTeacher, ...teachers]);
|
||||||
let idProfil = response.id;
|
setNewTeacher(null);
|
||||||
newTeacher.associated_profile = idProfil;
|
setLocalErrors({});
|
||||||
handleCreate(newTeacher)
|
})
|
||||||
.then((createdTeacher) => {
|
.catch((error) => {
|
||||||
setTeachers([createdTeacher, ...teachers]);
|
logger.error('Error:', error.message);
|
||||||
setNewTeacher(null);
|
if (error.details) {
|
||||||
setLocalErrors({});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
logger.error('Error:', error.message);
|
|
||||||
if (error.details) {
|
|
||||||
logger.error('Form errors:', error.details);
|
|
||||||
setLocalErrors(error.details);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setLocalErrors({});
|
|
||||||
})
|
|
||||||
.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);
|
||||||
@ -260,7 +277,6 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
<div className="flex justify-center space-x-2">
|
<div className="flex justify-center space-x-2">
|
||||||
<InputText
|
<InputText
|
||||||
name="last_name"
|
name="last_name"
|
||||||
label="nom"
|
|
||||||
value={currentData.last_name}
|
value={currentData.last_name}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
placeholder="Nom de l'enseignant"
|
placeholder="Nom de l'enseignant"
|
||||||
@ -268,7 +284,6 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
name="first_name"
|
name="first_name"
|
||||||
label="prénom"
|
|
||||||
value={currentData.first_name}
|
value={currentData.first_name}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
placeholder="Prénom de l'enseignant"
|
placeholder="Prénom de l'enseignant"
|
||||||
@ -276,16 +291,26 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
case 'EMAIL':
|
case 'EMAIL':
|
||||||
return (
|
return (
|
||||||
<InputText
|
<div className="flex items-center space-x-2">
|
||||||
name="email"
|
{currentData.selectedProfile ? (
|
||||||
value={currentData.email}
|
<span className="text-gray-900">
|
||||||
onChange={handleChange}
|
{currentData.selectedProfile.email}
|
||||||
placeholder="Email de l'enseignant"
|
</span>
|
||||||
errorMsg={getError('email')}
|
) : (
|
||||||
/>
|
<span className="text-gray-500 italic">
|
||||||
);
|
Rechercher un profil existant
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setDirectoryPopupVisible(true)}
|
||||||
|
>
|
||||||
|
<Search className="w-5 h-5 text-emerald-500 hover:text-emerald-700"/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
case 'SPECIALITES':
|
case 'SPECIALITES':
|
||||||
return (
|
return (
|
||||||
<SpecialitiesDropZone teacher={currentData} handleSpecialitiesChange={handleSpecialitiesChange} specialities={specialities} isEditing={isEditing || isCreating} />
|
<SpecialitiesDropZone teacher={currentData} handleSpecialitiesChange={handleSpecialitiesChange} specialities={specialities} isEditing={isEditing || isCreating} />
|
||||||
@ -339,9 +364,9 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
case 'ADMINISTRATEUR':
|
case 'ADMINISTRATEUR':
|
||||||
if (teacher.associated_profile) {
|
if (teacher.associated_profile_email) {
|
||||||
const badgeClass = teacher.droit === 1 ? 'bg-red-100 text-red-600' : 'bg-blue-100 text-blue-600';
|
const badgeClass = teacher.role_type.role_type === 1 ? 'bg-red-100 text-red-600' : 'bg-blue-100 text-blue-600';
|
||||||
const label = teacher.droit === 1 ? 'OUI' : 'NON';
|
const label = teacher.role_type.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}`}>
|
||||||
|
|||||||
@ -6,6 +6,7 @@ const localePrefixes = {
|
|||||||
|
|
||||||
|
|
||||||
export function formatPhoneNumber(phoneString, fromFormat = 'XX-XX-XX-XX-XX', toFormat = 'LX-XX-XX-XX-XX', locale = "fr-FR") {
|
export function formatPhoneNumber(phoneString, fromFormat = 'XX-XX-XX-XX-XX', toFormat = 'LX-XX-XX-XX-XX', locale = "fr-FR") {
|
||||||
|
if (!phoneString) return;
|
||||||
// Extraire les chiffres du numéro de téléphone
|
// Extraire les chiffres du numéro de téléphone
|
||||||
const digits = phoneString.replace(/\D/g, '');
|
const digits = phoneString.replace(/\D/g, '');
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@ export const BE_AUTH_LOGIN_URL = `${BASE_URL}/Auth/login`
|
|||||||
export const BE_AUTH_REFRESH_JWT_URL = `${BASE_URL}/Auth/refreshJWT`
|
export const BE_AUTH_REFRESH_JWT_URL = `${BASE_URL}/Auth/refreshJWT`
|
||||||
export const BE_AUTH_LOGOUT_URL = `${BASE_URL}/Auth/logout`
|
export const BE_AUTH_LOGOUT_URL = `${BASE_URL}/Auth/logout`
|
||||||
export const BE_AUTH_PROFILES_URL = `${BASE_URL}/Auth/profiles`
|
export const BE_AUTH_PROFILES_URL = `${BASE_URL}/Auth/profiles`
|
||||||
|
export const BE_AUTH_PROFILES_ROLES_URL = `${BASE_URL}/Auth/profileRoles`
|
||||||
export const BE_AUTH_CSRF_URL = `${BASE_URL}/Auth/csrf`
|
export const BE_AUTH_CSRF_URL = `${BASE_URL}/Auth/csrf`
|
||||||
export const BE_AUTH_INFO_SESSION = `${BASE_URL}/Auth/infoSession`
|
export const BE_AUTH_INFO_SESSION = `${BASE_URL}/Auth/infoSession`
|
||||||
|
|
||||||
@ -79,6 +80,9 @@ export const FE_ADMIN_CLASSES_URL = `/admin/classes`
|
|||||||
//ADMIN/STRUCTURE URL
|
//ADMIN/STRUCTURE URL
|
||||||
export const FE_ADMIN_STRUCTURE_URL = `/admin/structure`
|
export const FE_ADMIN_STRUCTURE_URL = `/admin/structure`
|
||||||
|
|
||||||
|
//ADMIN/DIRECTORY URL
|
||||||
|
export const FE_ADMIN_DIRECTORY_URL = `/admin/directory`
|
||||||
|
|
||||||
//ADMIN/GRADES URL
|
//ADMIN/GRADES URL
|
||||||
export const FE_ADMIN_GRADES_URL = `/admin/grades`
|
export const FE_ADMIN_GRADES_URL = `/admin/grades`
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user