mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: Formulaire de création RF sur une seule pag
This commit is contained in:
@ -44,6 +44,8 @@ from Auth.serializers import ProfileSerializer, ProfileRoleSerializer
|
|||||||
from Establishment.serializers import EstablishmentSerializer
|
from Establishment.serializers import EstablishmentSerializer
|
||||||
from Subscriptions.serializers import RegistrationFormSerializer, StudentSerializer
|
from Subscriptions.serializers import RegistrationFormSerializer, StudentSerializer
|
||||||
|
|
||||||
|
from Subscriptions.util import getCurrentSchoolYear, getNextSchoolYear # Import des fonctions nécessaires
|
||||||
|
|
||||||
# Définir le chemin vers le dossier mock_datas
|
# Définir le chemin vers le dossier mock_datas
|
||||||
MOCK_DATAS_PATH = os.path.join(settings.BASE_DIR, 'School', 'management', 'mock_datas')
|
MOCK_DATAS_PATH = os.path.join(settings.BASE_DIR, 'School', 'management', 'mock_datas')
|
||||||
|
|
||||||
@ -403,11 +405,15 @@ class Command(BaseCommand):
|
|||||||
fees = Fee.objects.filter(id__in=[1, 2, 3, 4])
|
fees = Fee.objects.filter(id__in=[1, 2, 3, 4])
|
||||||
discounts = Discount.objects.filter(id__in=[1])
|
discounts = Discount.objects.filter(id__in=[1])
|
||||||
|
|
||||||
|
# Déterminer l'année scolaire (soit l'année en cours, soit l'année prochaine)
|
||||||
|
school_year = random.choice([getCurrentSchoolYear(), getNextSchoolYear()])
|
||||||
|
|
||||||
# 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": profile_role.establishment,
|
"establishment": profile_role.establishment,
|
||||||
"status": fake.random_int(min=1, max=3)
|
"status": fake.random_int(min=1, max=3),
|
||||||
|
"school_year": school_year # Ajouter l'année scolaire
|
||||||
}
|
}
|
||||||
|
|
||||||
# Créer ou mettre à jour le formulaire d'inscription
|
# Créer ou mettre à jour le formulaire d'inscription
|
||||||
@ -420,7 +426,7 @@ class Command(BaseCommand):
|
|||||||
if created:
|
if created:
|
||||||
register_form.fees.set(fees)
|
register_form.fees.set(fees)
|
||||||
register_form.discounts.set(discounts)
|
register_form.discounts.set(discounts)
|
||||||
self.stdout.write(self.style.SUCCESS(f'RegistrationForm for student {student.last_name} created successfully'))
|
self.stdout.write(self.style.SUCCESS(f'RegistrationForm for student {student.last_name} created successfully with school year {school_year}'))
|
||||||
else:
|
else:
|
||||||
self.stdout.write(self.style.SUCCESS(f'RegistrationForm for student {student.last_name} already exists'))
|
self.stdout.write(self.style.SUCCESS(f'RegistrationForm for student {student.last_name} already exists'))
|
||||||
|
|
||||||
|
|||||||
@ -25,8 +25,8 @@ class Guardian(models.Model):
|
|||||||
"""
|
"""
|
||||||
Représente un responsable légal (parent/tuteur) d’un élève.
|
Représente un responsable légal (parent/tuteur) d’un élève.
|
||||||
"""
|
"""
|
||||||
last_name = models.CharField(max_length=200, default="")
|
last_name = models.CharField(max_length=200, null=True, blank=True)
|
||||||
first_name = models.CharField(max_length=200, default="")
|
first_name = models.CharField(max_length=200, null=True, blank=True)
|
||||||
birth_date = models.DateField(null=True, blank=True)
|
birth_date = models.DateField(null=True, blank=True)
|
||||||
address = models.CharField(max_length=200, default="", blank=True)
|
address = models.CharField(max_length=200, default="", blank=True)
|
||||||
phone = models.CharField(max_length=200, default="", blank=True)
|
phone = models.CharField(max_length=200, default="", blank=True)
|
||||||
@ -49,8 +49,8 @@ class Sibling(models.Model):
|
|||||||
"""
|
"""
|
||||||
Représente un frère ou une sœur d’un élève.
|
Représente un frère ou une sœur d’un élève.
|
||||||
"""
|
"""
|
||||||
last_name = models.CharField(max_length=200, default="")
|
last_name = models.CharField(max_length=200, null=True, blank=True)
|
||||||
first_name = models.CharField(max_length=200, default="")
|
first_name = models.CharField(max_length=200, null=True, blank=True)
|
||||||
birth_date = models.DateField(null=True, blank=True)
|
birth_date = models.DateField(null=True, blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@ -218,6 +218,7 @@ class RegistrationForm(models.Model):
|
|||||||
student = models.OneToOneField(Student, on_delete=models.CASCADE, primary_key=True)
|
student = models.OneToOneField(Student, on_delete=models.CASCADE, primary_key=True)
|
||||||
status = models.IntegerField(choices=RegistrationFormStatus, default=RegistrationFormStatus.RF_IDLE)
|
status = models.IntegerField(choices=RegistrationFormStatus, default=RegistrationFormStatus.RF_IDLE)
|
||||||
last_update = models.DateTimeField(auto_now=True)
|
last_update = models.DateTimeField(auto_now=True)
|
||||||
|
school_year = models.CharField(max_length=9, default="", blank=True)
|
||||||
notes = models.CharField(max_length=200, blank=True)
|
notes = models.CharField(max_length=200, blank=True)
|
||||||
registration_link_code = models.CharField(max_length=200, default="", blank=True)
|
registration_link_code = models.CharField(max_length=200, default="", blank=True)
|
||||||
registration_file = models.FileField(
|
registration_file = models.FileField(
|
||||||
|
|||||||
@ -343,7 +343,7 @@ class GuardianByDICreationSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Guardian
|
model = Guardian
|
||||||
fields = ['id', 'last_name', 'first_name', 'associated_profile_email']
|
fields = ['id', 'last_name', 'first_name', 'associated_profile_email', 'phone']
|
||||||
|
|
||||||
def get_associated_profile_email(self, obj):
|
def get_associated_profile_email(self, obj):
|
||||||
if obj.profile_role and obj.profile_role.profile:
|
if obj.profile_role and obj.profile_role.profile:
|
||||||
@ -356,7 +356,7 @@ class StudentByRFCreationSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Student
|
model = Student
|
||||||
fields = ['id', 'last_name', 'first_name', 'guardians']
|
fields = ['id', 'last_name', 'first_name', 'guardians', 'level']
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(StudentByRFCreationSerializer, self).__init__(*args, **kwargs)
|
super(StudentByRFCreationSerializer, self).__init__(*args, **kwargs)
|
||||||
|
|||||||
@ -175,3 +175,44 @@ def delete_registration_files(registerForm):
|
|||||||
|
|
||||||
if os.path.exists(base_dir):
|
if os.path.exists(base_dir):
|
||||||
shutil.rmtree(base_dir)
|
shutil.rmtree(base_dir)
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
def getCurrentSchoolYear():
|
||||||
|
"""
|
||||||
|
Retourne l'année scolaire en cours au format "YYYY-YYYY".
|
||||||
|
Exemple : Si nous sommes en octobre 2023, retourne "2023-2024".
|
||||||
|
"""
|
||||||
|
now = datetime.now()
|
||||||
|
current_year = now.year
|
||||||
|
current_month = now.month
|
||||||
|
|
||||||
|
# Si nous sommes avant septembre, l'année scolaire a commencé l'année précédente
|
||||||
|
start_year = current_year if current_month >= 9 else current_year - 1
|
||||||
|
return f"{start_year}-{start_year + 1}"
|
||||||
|
|
||||||
|
def getNextSchoolYear():
|
||||||
|
"""
|
||||||
|
Retourne l'année scolaire suivante au format "YYYY-YYYY".
|
||||||
|
Exemple : Si nous sommes en octobre 2023, retourne "2024-2025".
|
||||||
|
"""
|
||||||
|
current_school_year = getCurrentSchoolYear()
|
||||||
|
start_year, end_year = map(int, current_school_year.split('-'))
|
||||||
|
return f"{start_year + 1}-{end_year + 1}"
|
||||||
|
|
||||||
|
|
||||||
|
def getHistoricalYears(count=5):
|
||||||
|
"""
|
||||||
|
Retourne un tableau des années scolaires passées au format "YYYY-YYYY".
|
||||||
|
Exemple : ["2022-2023", "2021-2022", "2020-2021"].
|
||||||
|
:param count: Le nombre d'années scolaires passées à inclure.
|
||||||
|
"""
|
||||||
|
current_school_year = getCurrentSchoolYear()
|
||||||
|
start_year = int(current_school_year.split('-')[0])
|
||||||
|
|
||||||
|
historical_years = []
|
||||||
|
for i in range(1, count + 1):
|
||||||
|
historical_start_year = start_year - i
|
||||||
|
historical_years.append(f"{historical_start_year}-{historical_start_year + 1}")
|
||||||
|
|
||||||
|
return historical_years
|
||||||
@ -33,7 +33,7 @@ class RegisterFormView(APIView):
|
|||||||
|
|
||||||
@swagger_auto_schema(
|
@swagger_auto_schema(
|
||||||
manual_parameters=[
|
manual_parameters=[
|
||||||
openapi.Parameter('filter', openapi.IN_QUERY, description="filtre", type=openapi.TYPE_STRING, enum=['pending', 'archived', 'subscribed'], required=True),
|
openapi.Parameter('filter', openapi.IN_QUERY, description="filtre", type=openapi.TYPE_STRING, enum=['current_year', 'next_year', 'historical'], required=True),
|
||||||
openapi.Parameter('search', openapi.IN_QUERY, description="search", type=openapi.TYPE_STRING, required=False),
|
openapi.Parameter('search', openapi.IN_QUERY, description="search", type=openapi.TYPE_STRING, required=False),
|
||||||
openapi.Parameter('page_size', openapi.IN_QUERY, description="limite de page lors de la pagination", type=openapi.TYPE_INTEGER, required=False),
|
openapi.Parameter('page_size', openapi.IN_QUERY, description="limite de page lors de la pagination", type=openapi.TYPE_INTEGER, required=False),
|
||||||
openapi.Parameter('establishment_id', openapi.IN_QUERY, description="ID de l'établissement", type=openapi.TYPE_INTEGER, required=True),
|
openapi.Parameter('establishment_id', openapi.IN_QUERY, description="ID de l'établissement", type=openapi.TYPE_INTEGER, required=True),
|
||||||
@ -51,7 +51,7 @@ class RegisterFormView(APIView):
|
|||||||
"last_name": "Doe",
|
"last_name": "Doe",
|
||||||
"date_of_birth": "2010-01-01"
|
"date_of_birth": "2010-01-01"
|
||||||
},
|
},
|
||||||
"status": "pending",
|
"status": "current_year",
|
||||||
"last_update": "10-02-2025 10:00"
|
"last_update": "10-02-2025 10:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -62,7 +62,7 @@ class RegisterFormView(APIView):
|
|||||||
"last_name": "Doe",
|
"last_name": "Doe",
|
||||||
"date_of_birth": "2011-02-02"
|
"date_of_birth": "2011-02-02"
|
||||||
},
|
},
|
||||||
"status": "archived",
|
"status": "historical",
|
||||||
"last_update": "09-02-2025 09:00"
|
"last_update": "09-02-2025 09:00"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -85,14 +85,19 @@ class RegisterFormView(APIView):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
page_size = settings.NB_RESULT_PER_PAGE
|
page_size = settings.NB_RESULT_PER_PAGE
|
||||||
|
|
||||||
# Récupérer les dossier d'inscriptions en fonction du filtre
|
# Récupérer les années scolaires
|
||||||
|
current_year = util.getCurrentSchoolYear()
|
||||||
|
next_year = util.getNextSchoolYear()
|
||||||
|
historical_years = util.getHistoricalYears()
|
||||||
|
|
||||||
|
# Récupérer les dossiers d'inscriptions en fonction du filtre
|
||||||
registerForms_List = None
|
registerForms_List = None
|
||||||
if filter == 'pending':
|
if filter == 'current_year':
|
||||||
exclude_states = [RegistrationForm.RegistrationFormStatus.RF_VALIDATED, RegistrationForm.RegistrationFormStatus.RF_ARCHIVED]
|
registerForms_List = RegistrationForm.objects.filter(school_year=current_year)
|
||||||
registerForms_List = bdd.searchObjects(RegistrationForm, search, _excludeStates=exclude_states)
|
elif filter == 'next_year':
|
||||||
elif filter == 'archived':
|
registerForms_List = RegistrationForm.objects.filter(school_year=next_year)
|
||||||
registerForms_List = bdd.getObjects(RegistrationForm, 'status', RegistrationForm.RegistrationFormStatus.RF_ARCHIVED)
|
elif filter == 'historical':
|
||||||
elif filter == 'subscribed':
|
registerForms_List = RegistrationForm.objects.filter(school_year__in=historical_years)
|
||||||
registerForms_List = bdd.getObjects(RegistrationForm, 'status', RegistrationForm.RegistrationFormStatus.RF_VALIDATED)
|
registerForms_List = bdd.getObjects(RegistrationForm, 'status', RegistrationForm.RegistrationFormStatus.RF_VALIDATED)
|
||||||
else:
|
else:
|
||||||
registerForms_List = None
|
registerForms_List = None
|
||||||
@ -126,7 +131,7 @@ class RegisterFormView(APIView):
|
|||||||
"last_name": "Doe",
|
"last_name": "Doe",
|
||||||
"date_of_birth": "2010-01-01"
|
"date_of_birth": "2010-01-01"
|
||||||
},
|
},
|
||||||
"status": "pending",
|
"status": "current_year",
|
||||||
"last_update": "10-02-2025 10:00",
|
"last_update": "10-02-2025 10:00",
|
||||||
"codeLienInscription": "ABC123XYZ456"
|
"codeLienInscription": "ABC123XYZ456"
|
||||||
}
|
}
|
||||||
@ -515,3 +520,4 @@ def get_parent_file_templates_by_rf(request, id):
|
|||||||
return JsonResponse(serializer.data, safe=False)
|
return JsonResponse(serializer.data, safe=False)
|
||||||
except RegistrationParentFileTemplate.DoesNotExist:
|
except RegistrationParentFileTemplate.DoesNotExist:
|
||||||
return JsonResponse({'error': 'Aucune pièce à fournir trouvée pour ce dossier d\'inscription'}, status=status.HTTP_404_NOT_FOUND)
|
return JsonResponse({'error': 'Aucune pièce à fournir trouvée pour ce dossier d\'inscription'}, status=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
@ -30,5 +30,6 @@
|
|||||||
"classe": "Class",
|
"classe": "Class",
|
||||||
"registrationFileStatus": "Registration file status",
|
"registrationFileStatus": "Registration file status",
|
||||||
"files": "Files",
|
"files": "Files",
|
||||||
"subscribeFiles": "Subscribe files"
|
"subscribeFiles": "Subscribe files",
|
||||||
|
"historical": "Historical"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,5 +30,6 @@
|
|||||||
"classe": "Classe",
|
"classe": "Classe",
|
||||||
"registrationFileStatus": "État du dossier d'inscription",
|
"registrationFileStatus": "État du dossier d'inscription",
|
||||||
"files": "Fichiers",
|
"files": "Fichiers",
|
||||||
"subscribeFiles": "Fichiers d'inscription"
|
"subscribeFiles": "Fichiers d'inscription",
|
||||||
|
"historical": "Historique"
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -25,40 +25,24 @@ import InscriptionForm from '@/components/Inscription/InscriptionForm';
|
|||||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
PENDING,
|
CURRENT_YEAR,
|
||||||
SUBSCRIBED,
|
NEXT_YEAR,
|
||||||
ARCHIVED,
|
HISTORICAL,
|
||||||
fetchRegisterForms,
|
fetchRegisterForms,
|
||||||
createRegisterForm,
|
|
||||||
sendRegisterForm,
|
sendRegisterForm,
|
||||||
archiveRegisterForm,
|
archiveRegisterForm,
|
||||||
fetchStudents,
|
|
||||||
editRegisterForm,
|
editRegisterForm,
|
||||||
editRegisterFormWithBinaryFile,
|
editRegisterFormWithBinaryFile,
|
||||||
} from '@/app/actions/subscriptionAction';
|
} from '@/app/actions/subscriptionAction';
|
||||||
|
|
||||||
import {
|
import { fetchClasses, updateDatas } from '@/app/actions/schoolAction';
|
||||||
fetchRegistrationSchoolFileMasters,
|
|
||||||
fetchRegistrationParentFileMasters,
|
|
||||||
createRegistrationSchoolFileTemplate,
|
|
||||||
createRegistrationParentFileTemplate,
|
|
||||||
fetchRegistrationFileGroups,
|
|
||||||
cloneTemplate,
|
|
||||||
} from '@/app/actions/registerFileGroupAction';
|
|
||||||
|
|
||||||
import {
|
|
||||||
fetchClasses,
|
|
||||||
fetchRegistrationDiscounts,
|
|
||||||
fetchTuitionDiscounts,
|
|
||||||
fetchRegistrationFees,
|
|
||||||
fetchTuitionFees,
|
|
||||||
} from '@/app/actions/schoolAction';
|
|
||||||
|
|
||||||
import { fetchProfiles } from '@/app/actions/authAction';
|
import { fetchProfiles } from '@/app/actions/authAction';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FE_ADMIN_SUBSCRIPTIONS_EDIT_URL,
|
FE_ADMIN_SUBSCRIPTIONS_EDIT_URL,
|
||||||
FE_ADMIN_SUBSCRIPTIONS_VALIDATE_URL,
|
FE_ADMIN_SUBSCRIPTIONS_VALIDATE_URL,
|
||||||
|
FE_ADMIN_SUBSCRIPTIONS_CREATE_URL,
|
||||||
BASE_URL,
|
BASE_URL,
|
||||||
} from '@/utils/Url';
|
} from '@/utils/Url';
|
||||||
|
|
||||||
@ -68,41 +52,41 @@ import logger from '@/utils/logger';
|
|||||||
import { PhoneLabel } from '@/components/PhoneLabel';
|
import { PhoneLabel } from '@/components/PhoneLabel';
|
||||||
import FileUpload from '@/components/FileUpload';
|
import FileUpload from '@/components/FileUpload';
|
||||||
import FilesModal from '@/components/Inscription/FilesModal';
|
import FilesModal from '@/components/Inscription/FilesModal';
|
||||||
|
import {
|
||||||
|
getCurrentSchoolYear,
|
||||||
|
getNextSchoolYear,
|
||||||
|
getHistoricalYears,
|
||||||
|
} from '@/utils/Date';
|
||||||
|
|
||||||
export default function Page({ params: { locale } }) {
|
export default function Page({ params: { locale } }) {
|
||||||
const t = useTranslations('subscriptions');
|
const t = useTranslations('subscriptions');
|
||||||
const [registrationForms, setRegistrationForms] = useState([]);
|
const [registrationForms, setRegistrationForms] = useState([]);
|
||||||
const [registrationFormsDataPending, setRegistrationFormsDataPending] =
|
const [
|
||||||
|
registrationFormsDataCurrentYear,
|
||||||
|
setRegistrationFormsDataCurrentYear,
|
||||||
|
] = useState([]);
|
||||||
|
const [registrationFormsDataNextYear, setRegistrationFormsDataNextYear] =
|
||||||
useState([]);
|
useState([]);
|
||||||
const [registrationFormsDataSubscribed, setRegistrationFormsDataSubscribed] =
|
const [registrationFormsDataHistorical, setRegistrationFormsDataHistorical] =
|
||||||
useState([]);
|
useState([]);
|
||||||
const [registrationFormsDataArchived, setRegistrationFormsDataArchived] =
|
const currentSchoolYear = getCurrentSchoolYear(); // Exemple : "2024-2025"
|
||||||
useState([]);
|
const nextSchoolYear = getNextSchoolYear(); // Exemple : "2025-2026"
|
||||||
// const [filter, setFilter] = useState('*');
|
const historicalYears = getHistoricalYears();
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [alertPage, setAlertPage] = useState(false);
|
const [alertPage, setAlertPage] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [activeTab, setActiveTab] = useState('pending');
|
const [activeTab, setActiveTab] = useState('currentYear');
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [totalPages, setTotalPages] = useState(1);
|
const [totalPages, setTotalPages] = useState(1);
|
||||||
const [totalPending, setTotalPending] = useState(0);
|
const [totalCurrentYear, setTotalCurrentYear] = useState(0);
|
||||||
const [totalSubscribed, setTotalSubscribed] = useState(0);
|
const [totalSubscribed, setTotalNextYear] = useState(0);
|
||||||
const [totalArchives, setTotalArchives] = useState(0);
|
const [totalHistorical, setTotalHistorical] = useState(0);
|
||||||
const [itemsPerPage, setItemsPerPage] = useState(10); // Définir le nombre d'éléments par page
|
const [itemsPerPage, setItemsPerPage] = useState(10); // Définir le nombre d'éléments par page
|
||||||
|
|
||||||
const [schoolFileMasters, setSchoolFileMasters] = useState([]);
|
|
||||||
const [parentFileMasters, setParentFileMasters] = useState([]);
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [student, setStudent] = useState('');
|
const [student, setStudent] = useState('');
|
||||||
const [classes, setClasses] = useState([]);
|
const [classes, setClasses] = useState([]);
|
||||||
const [students, setEleves] = useState([]);
|
|
||||||
const [reloadFetch, setReloadFetch] = useState(false);
|
const [reloadFetch, setReloadFetch] = useState(false);
|
||||||
|
|
||||||
const [registrationDiscounts, setRegistrationDiscounts] = useState([]);
|
|
||||||
const [tuitionDiscounts, setTuitionDiscounts] = useState([]);
|
|
||||||
const [registrationFees, setRegistrationFees] = useState([]);
|
|
||||||
const [tuitionFees, setTuitionFees] = useState([]);
|
|
||||||
const [groups, setGroups] = useState([]);
|
|
||||||
const [profiles, setProfiles] = useState([]);
|
const [profiles, setProfiles] = useState([]);
|
||||||
const [isOpenAddGuardian, setIsOpenAddGuardian] = useState(false);
|
const [isOpenAddGuardian, setIsOpenAddGuardian] = useState(false);
|
||||||
|
|
||||||
@ -132,14 +116,6 @@ export default function Page({ params: { locale } }) {
|
|||||||
setIsSepaUploadModalOpen(false);
|
setIsSepaUploadModalOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const openModal = () => {
|
|
||||||
setIsOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const closeModal = () => {
|
|
||||||
setIsOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const openFilesModal = (row) => {
|
const openFilesModal = (row) => {
|
||||||
setSelectedRegisterForm(row || []);
|
setSelectedRegisterForm(row || []);
|
||||||
setIsFilesModalOpen(true);
|
setIsFilesModalOpen(true);
|
||||||
@ -160,11 +136,11 @@ export default function Page({ params: { locale } }) {
|
|||||||
if (data) {
|
if (data) {
|
||||||
const { registerForms, count, page_size } = data;
|
const { registerForms, count, page_size } = data;
|
||||||
if (registerForms) {
|
if (registerForms) {
|
||||||
setRegistrationFormsDataPending(registerForms);
|
setRegistrationFormsDataCurrentYear(registerForms);
|
||||||
}
|
}
|
||||||
const calculatedTotalPages =
|
const calculatedTotalPages =
|
||||||
count === 0 ? 1 : Math.ceil(count / page_size);
|
count === 0 ? 1 : Math.ceil(count / page_size);
|
||||||
setTotalPending(count);
|
setTotalCurrentYear(count);
|
||||||
setTotalPages(calculatedTotalPages);
|
setTotalPages(calculatedTotalPages);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -179,9 +155,9 @@ export default function Page({ params: { locale } }) {
|
|||||||
const registerFormSubscribedDataHandler = (data) => {
|
const registerFormSubscribedDataHandler = (data) => {
|
||||||
if (data) {
|
if (data) {
|
||||||
const { registerForms, count, page_size } = data;
|
const { registerForms, count, page_size } = data;
|
||||||
setTotalSubscribed(count);
|
setTotalNextYear(count);
|
||||||
if (registerForms) {
|
if (registerForms) {
|
||||||
setRegistrationFormsDataSubscribed(registerForms);
|
setRegistrationFormsDataNextYear(registerForms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -197,9 +173,9 @@ export default function Page({ params: { locale } }) {
|
|||||||
if (data) {
|
if (data) {
|
||||||
const { registerForms, count, page_size } = data;
|
const { registerForms, count, page_size } = data;
|
||||||
|
|
||||||
setTotalArchives(count);
|
setTotalHistorical(count);
|
||||||
if (registerForms) {
|
if (registerForms) {
|
||||||
setRegistrationFormsDataArchived(registerForms);
|
setRegistrationFormsDataHistorical(registerForms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -211,7 +187,7 @@ export default function Page({ params: { locale } }) {
|
|||||||
Promise.all([
|
Promise.all([
|
||||||
fetchRegisterForms(
|
fetchRegisterForms(
|
||||||
selectedEstablishmentId,
|
selectedEstablishmentId,
|
||||||
PENDING,
|
CURRENT_YEAR,
|
||||||
currentPage,
|
currentPage,
|
||||||
itemsPerPage,
|
itemsPerPage,
|
||||||
searchTerm
|
searchTerm
|
||||||
@ -225,59 +201,12 @@ export default function Page({ params: { locale } }) {
|
|||||||
})
|
})
|
||||||
.catch(requestErrorHandler),
|
.catch(requestErrorHandler),
|
||||||
|
|
||||||
fetchStudents(selectedEstablishmentId)
|
fetchRegisterForms(selectedEstablishmentId, NEXT_YEAR)
|
||||||
.then((studentsData) => {
|
|
||||||
setEleves(studentsData);
|
|
||||||
})
|
|
||||||
.catch(requestErrorHandler),
|
|
||||||
|
|
||||||
fetchRegisterForms(selectedEstablishmentId, SUBSCRIBED)
|
|
||||||
.then(registerFormSubscribedDataHandler)
|
.then(registerFormSubscribedDataHandler)
|
||||||
.catch(requestErrorHandler),
|
.catch(requestErrorHandler),
|
||||||
fetchRegisterForms(selectedEstablishmentId, ARCHIVED)
|
fetchRegisterForms(selectedEstablishmentId, HISTORICAL)
|
||||||
.then(registerFormArchivedDataHandler)
|
.then(registerFormArchivedDataHandler)
|
||||||
.catch(requestErrorHandler),
|
.catch(requestErrorHandler),
|
||||||
fetchRegistrationSchoolFileMasters()
|
|
||||||
.then((data) => {
|
|
||||||
setSchoolFileMasters(data);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
logger.debug(err.message);
|
|
||||||
}),
|
|
||||||
fetchRegistrationParentFileMasters()
|
|
||||||
.then((data) => {
|
|
||||||
setParentFileMasters(data);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
logger.debug(err.message);
|
|
||||||
}),
|
|
||||||
fetchRegistrationDiscounts(selectedEstablishmentId)
|
|
||||||
.then((data) => {
|
|
||||||
setRegistrationDiscounts(data);
|
|
||||||
})
|
|
||||||
.catch(requestErrorHandler),
|
|
||||||
fetchTuitionDiscounts(selectedEstablishmentId)
|
|
||||||
.then((data) => {
|
|
||||||
setTuitionDiscounts(data);
|
|
||||||
})
|
|
||||||
.catch(requestErrorHandler),
|
|
||||||
fetchRegistrationFees(selectedEstablishmentId)
|
|
||||||
.then((data) => {
|
|
||||||
setRegistrationFees(data);
|
|
||||||
})
|
|
||||||
.catch(requestErrorHandler),
|
|
||||||
fetchTuitionFees(selectedEstablishmentId)
|
|
||||||
.then((data) => {
|
|
||||||
setTuitionFees(data);
|
|
||||||
})
|
|
||||||
.catch(requestErrorHandler),
|
|
||||||
fetchRegistrationFileGroups(selectedEstablishmentId)
|
|
||||||
.then((data) => {
|
|
||||||
setGroups(data);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
logger.error('Error fetching file groups:', error);
|
|
||||||
}),
|
|
||||||
fetchProfiles()
|
fetchProfiles()
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
setProfiles(data);
|
setProfiles(data);
|
||||||
@ -307,27 +236,19 @@ export default function Page({ params: { locale } }) {
|
|||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
fetchRegisterForms(
|
fetchRegisterForms(
|
||||||
selectedEstablishmentId,
|
selectedEstablishmentId,
|
||||||
PENDING,
|
CURRENT_YEAR,
|
||||||
currentPage,
|
currentPage,
|
||||||
itemsPerPage,
|
itemsPerPage,
|
||||||
searchTerm
|
searchTerm
|
||||||
)
|
)
|
||||||
.then(registerFormPendingDataHandler)
|
.then(registerFormPendingDataHandler)
|
||||||
.catch(requestErrorHandler);
|
.catch(requestErrorHandler);
|
||||||
fetchRegisterForms(selectedEstablishmentId, SUBSCRIBED)
|
fetchRegisterForms(selectedEstablishmentId, NEXT_YEAR)
|
||||||
.then(registerFormSubscribedDataHandler)
|
.then(registerFormSubscribedDataHandler)
|
||||||
.catch(requestErrorHandler);
|
.catch(requestErrorHandler);
|
||||||
fetchRegisterForms(selectedEstablishmentId, ARCHIVED)
|
fetchRegisterForms(selectedEstablishmentId, HISTORICAL)
|
||||||
.then(registerFormArchivedDataHandler)
|
.then(registerFormArchivedDataHandler)
|
||||||
.catch(requestErrorHandler);
|
.catch(requestErrorHandler);
|
||||||
fetchRegistrationSchoolFileMasters()
|
|
||||||
.then((data) => {
|
|
||||||
setSchoolFileMasters(data);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
err = err.message;
|
|
||||||
logger.debug(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
setReloadFetch(false);
|
setReloadFetch(false);
|
||||||
@ -344,12 +265,12 @@ export default function Page({ params: { locale } }) {
|
|||||||
* UseEffect to update page count of tab
|
* UseEffect to update page count of tab
|
||||||
*/
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTab === 'pending') {
|
if (activeTab === 'currentYear') {
|
||||||
setTotalPages(Math.ceil(totalPending / itemsPerPage));
|
setTotalPages(Math.ceil(totalCurrentYear / itemsPerPage));
|
||||||
} else if (activeTab === 'subscribed') {
|
} else if (activeTab === 'nextYear') {
|
||||||
setTotalPages(Math.ceil(totalSubscribed / itemsPerPage));
|
setTotalPages(Math.ceil(totalSubscribed / itemsPerPage));
|
||||||
} else if (activeTab === 'archived') {
|
} else if (activeTab === 'historical') {
|
||||||
setTotalPages(Math.ceil(totalArchives / itemsPerPage));
|
setTotalPages(Math.ceil(totalHistorical / itemsPerPage));
|
||||||
}
|
}
|
||||||
}, [currentPage]);
|
}, [currentPage]);
|
||||||
|
|
||||||
@ -460,187 +381,6 @@ export default function Page({ params: { locale } }) {
|
|||||||
setCurrentPage(newPage);
|
setCurrentPage(newPage);
|
||||||
};
|
};
|
||||||
|
|
||||||
const createRF = (updatedData) => {
|
|
||||||
logger.debug('createRF updatedData:', updatedData);
|
|
||||||
|
|
||||||
const selectedRegistrationFeesIds =
|
|
||||||
updatedData.selectedRegistrationFees.map((feeId) => feeId);
|
|
||||||
const selectedRegistrationDiscountsIds =
|
|
||||||
updatedData.selectedRegistrationDiscounts.map((discountId) => discountId);
|
|
||||||
const selectedTuitionFeesIds = updatedData.selectedTuitionFees.map(
|
|
||||||
(feeId) => feeId
|
|
||||||
);
|
|
||||||
const selectedTuitionDiscountsIds =
|
|
||||||
updatedData.selectedTuitionDiscounts.map((discountId) => discountId);
|
|
||||||
const selectedFileGroup = updatedData.selectedFileGroup;
|
|
||||||
const allFeesIds = [
|
|
||||||
...selectedRegistrationFeesIds,
|
|
||||||
...selectedTuitionFeesIds,
|
|
||||||
];
|
|
||||||
const allDiscountsds = [
|
|
||||||
...selectedRegistrationDiscountsIds,
|
|
||||||
...selectedTuitionDiscountsIds,
|
|
||||||
];
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
student: {
|
|
||||||
last_name: updatedData.studentLastName,
|
|
||||||
first_name: updatedData.studentFirstName,
|
|
||||||
guardians:
|
|
||||||
updatedData.selectedGuardians.length !== 0
|
|
||||||
? updatedData.selectedGuardians.map((guardianId) => ({
|
|
||||||
id: guardianId,
|
|
||||||
}))
|
|
||||||
: (() => {
|
|
||||||
if (updatedData.isExistingParentProfile) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
profile_role_data: {
|
|
||||||
establishment: selectedEstablishmentId,
|
|
||||||
role_type: 2,
|
|
||||||
is_active: false,
|
|
||||||
profile: updatedData.existingProfileId, // Associer au profil existant
|
|
||||||
},
|
|
||||||
last_name: updatedData.guardianLastName,
|
|
||||||
first_name: updatedData.guardianFirstName,
|
|
||||||
birth_date: updatedData.guardianBirthDate,
|
|
||||||
address: updatedData.guardianAddress,
|
|
||||||
phone: updatedData.guardianPhone,
|
|
||||||
profession: updatedData.guardianProfession,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Si aucun profil existant n'est trouvé, créer un nouveau profil
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
profile_role_data: {
|
|
||||||
establishment: selectedEstablishmentId,
|
|
||||||
role_type: 2,
|
|
||||||
is_active: false,
|
|
||||||
profile_data: {
|
|
||||||
email: updatedData.guardianEmail,
|
|
||||||
password: 'Provisoire01!',
|
|
||||||
username: updatedData.guardianEmail,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
last_name: updatedData.guardianLastName,
|
|
||||||
first_name: updatedData.guardianFirstName,
|
|
||||||
birth_date: updatedData.guardianBirthDate,
|
|
||||||
address: updatedData.guardianAddress,
|
|
||||||
phone: updatedData.guardianPhone,
|
|
||||||
profession: updatedData.guardianProfession,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
})(),
|
|
||||||
sibling: [],
|
|
||||||
},
|
|
||||||
fees: allFeesIds,
|
|
||||||
discounts: allDiscountsds,
|
|
||||||
fileGroup: selectedFileGroup,
|
|
||||||
establishment: selectedEstablishmentId,
|
|
||||||
};
|
|
||||||
|
|
||||||
setIsLoading(true);
|
|
||||||
createRegisterForm(data, csrfToken)
|
|
||||||
.then((data) => {
|
|
||||||
// Cloner les schoolFileTemplates pour chaque templateMaster du fileGroup
|
|
||||||
const masters = schoolFileMasters.filter((file) =>
|
|
||||||
file.groups.includes(selectedFileGroup)
|
|
||||||
);
|
|
||||||
const parent_masters = parentFileMasters.filter((file) =>
|
|
||||||
file.groups.includes(selectedFileGroup)
|
|
||||||
);
|
|
||||||
|
|
||||||
const clonePromises = masters.map((templateMaster) => {
|
|
||||||
return cloneTemplate(
|
|
||||||
templateMaster.id,
|
|
||||||
updatedData.guardianEmail,
|
|
||||||
templateMaster.is_required
|
|
||||||
)
|
|
||||||
.then((clonedDocument) => {
|
|
||||||
// Sauvegarde des schoolFileTemplates clonés dans la base de données
|
|
||||||
const cloneData = {
|
|
||||||
name: `${templateMaster.name}_${updatedData.studentFirstName}_${updatedData.studentLastName}`,
|
|
||||||
slug: clonedDocument.slug,
|
|
||||||
id: clonedDocument.id,
|
|
||||||
master: templateMaster.id,
|
|
||||||
registration_form: data.student.id,
|
|
||||||
};
|
|
||||||
|
|
||||||
return createRegistrationSchoolFileTemplate(cloneData, csrfToken)
|
|
||||||
.then((response) => {
|
|
||||||
logger.debug('Template enregistré avec succès:', response);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
setIsLoading(false);
|
|
||||||
logger.error(
|
|
||||||
"Erreur lors de l'enregistrement du template:",
|
|
||||||
error
|
|
||||||
);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
setIsLoading(false);
|
|
||||||
logger.error('Error during cloning or sending:', error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Créer les parentFileTemplates pour chaque parentMaster
|
|
||||||
const parentClonePromises = parent_masters.map((parentMaster) => {
|
|
||||||
const parentTemplateData = {
|
|
||||||
master: parentMaster.id,
|
|
||||||
registration_form: data.student.id,
|
|
||||||
};
|
|
||||||
|
|
||||||
return createRegistrationParentFileTemplate(
|
|
||||||
parentTemplateData,
|
|
||||||
csrfToken
|
|
||||||
)
|
|
||||||
.then((response) => {
|
|
||||||
logger.debug('Parent template enregistré avec succès:', response);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
setIsLoading(false);
|
|
||||||
logger.error(
|
|
||||||
"Erreur lors de l'enregistrement du parent template:",
|
|
||||||
error
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Attendre que tous les clones (school et parent) soient créés
|
|
||||||
Promise.all([...clonePromises, ...parentClonePromises])
|
|
||||||
.then(() => {
|
|
||||||
// Mise à jour immédiate des données
|
|
||||||
setRegistrationFormsDataPending((prevState) => [
|
|
||||||
...(prevState || []),
|
|
||||||
data,
|
|
||||||
]);
|
|
||||||
setTotalPending((prev) => prev + 1);
|
|
||||||
if (updatedData.autoMail) {
|
|
||||||
sendConfirmRegisterForm(
|
|
||||||
data.student.id,
|
|
||||||
updatedData.studentLastName,
|
|
||||||
updatedData.studentFirstName
|
|
||||||
);
|
|
||||||
}
|
|
||||||
closeModal(); // Appeler closeModal ici après que tout soit terminé
|
|
||||||
// Forcer le rechargement complet des données
|
|
||||||
setReloadFetch(true);
|
|
||||||
setIsLoading(false);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
setIsLoading(false);
|
|
||||||
logger.error('Error during cloning or sending:', error);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
setIsLoading(false);
|
|
||||||
logger.error('Error:', error);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateRF = (updatedData) => {
|
const updateRF = (updatedData) => {
|
||||||
logger.debug('updateRF updatedData:', updatedData);
|
logger.debug('updateRF updatedData:', updatedData);
|
||||||
|
|
||||||
@ -700,11 +440,11 @@ export default function Page({ params: { locale } }) {
|
|||||||
editRegisterForm(student.id, data, csrfToken)
|
editRegisterForm(student.id, data, csrfToken)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
// Mise à jour immédiate des données
|
// Mise à jour immédiate des données
|
||||||
setRegistrationFormsDataPending((prevState) => [
|
setRegistrationFormsDataCurrentYear((prevState) => [
|
||||||
...(prevState || []),
|
...(prevState || []),
|
||||||
data,
|
data,
|
||||||
]);
|
]);
|
||||||
setTotalPending((prev) => prev + 1);
|
setTotalCurrentYear((prev) => prev + 1);
|
||||||
if (updatedData.autoMail) {
|
if (updatedData.autoMail) {
|
||||||
sendConfirmRegisterForm(
|
sendConfirmRegisterForm(
|
||||||
data.student.id,
|
data.student.id,
|
||||||
@ -980,7 +720,7 @@ export default function Page({ params: { locale } }) {
|
|||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
registrationForms.length === 0 &&
|
registrationForms.length === 0 &&
|
||||||
registrationFormsDataArchived.length === 0 &&
|
registrationFormsDataHistorical.length === 0 &&
|
||||||
alertPage
|
alertPage
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
@ -997,49 +737,54 @@ export default function Page({ params: { locale } }) {
|
|||||||
<div className="p-8">
|
<div className="p-8">
|
||||||
<div className="border-b border-gray-200 mb-6">
|
<div className="border-b border-gray-200 mb-6">
|
||||||
<div className="flex items-center gap-8">
|
<div className="flex items-center gap-8">
|
||||||
|
{/* Tab pour l'année scolaire en cours */}
|
||||||
<Tab
|
<Tab
|
||||||
text={
|
text={
|
||||||
<>
|
<>
|
||||||
{t('pending')}
|
{currentSchoolYear}
|
||||||
<span className="ml-2 text-sm text-gray-400">
|
<span className="ml-2 text-sm text-gray-400">
|
||||||
({totalPending})
|
({totalCurrentYear})
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
active={activeTab === 'pending'}
|
active={activeTab === 'currentYear'}
|
||||||
onClick={() => setActiveTab('pending')}
|
onClick={() => setActiveTab('currentYear')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Tab pour l'année scolaire prochaine */}
|
||||||
<Tab
|
<Tab
|
||||||
text={
|
text={
|
||||||
<>
|
<>
|
||||||
{t('subscribed')}
|
{nextSchoolYear}
|
||||||
<span className="ml-2 text-sm text-gray-400">
|
<span className="ml-2 text-sm text-gray-400">
|
||||||
({totalSubscribed})
|
({totalSubscribed})
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
active={activeTab === 'subscribed'}
|
active={activeTab === 'nextYear'}
|
||||||
onClick={() => setActiveTab('subscribed')}
|
onClick={() => setActiveTab('nextYear')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Tab pour l'historique */}
|
||||||
<Tab
|
<Tab
|
||||||
text={
|
text={
|
||||||
<>
|
<>
|
||||||
{t('archived')}
|
{t('historical')}
|
||||||
<span className="ml-2 text-sm text-gray-400">
|
<span className="ml-2 text-sm text-gray-400">
|
||||||
({totalArchives})
|
({totalHistorical})
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
active={activeTab === 'archived'}
|
active={activeTab === 'historical'}
|
||||||
onClick={() => setActiveTab('archived')}
|
onClick={() => setActiveTab('historical')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border-b border-gray-200 mb-6 w-full">
|
<div className="border-b border-gray-200 mb-6 w-full">
|
||||||
{/*SI STATE == pending || subscribe || archived */}
|
{activeTab === 'currentYear' ||
|
||||||
{activeTab === 'pending' ||
|
activeTab === 'nextYear' ||
|
||||||
activeTab === 'subscribed' ||
|
activeTab === 'historical' ? (
|
||||||
activeTab === 'archived' ? (
|
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className="flex justify-between items-center mb-4 w-full">
|
<div className="flex justify-between items-center mb-4 w-full">
|
||||||
<div className="relative flex-grow">
|
<div className="relative flex-grow">
|
||||||
@ -1056,7 +801,10 @@ export default function Page({ params: { locale } }) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={openModal}
|
onClick={() => {
|
||||||
|
const url = `${FE_ADMIN_SUBSCRIPTIONS_CREATE_URL}`;
|
||||||
|
router.push(url);
|
||||||
|
}}
|
||||||
className="flex items-center bg-emerald-600 text-white p-2 rounded-full shadow hover:bg-emerald-900 transition duration-200 ml-4"
|
className="flex items-center bg-emerald-600 text-white p-2 rounded-full shadow hover:bg-emerald-900 transition duration-200 ml-4"
|
||||||
>
|
>
|
||||||
<Plus className="w-5 h-5" />
|
<Plus className="w-5 h-5" />
|
||||||
@ -1068,18 +816,13 @@ export default function Page({ params: { locale } }) {
|
|||||||
<Table
|
<Table
|
||||||
key={`${currentPage}-${searchTerm}`}
|
key={`${currentPage}-${searchTerm}`}
|
||||||
data={
|
data={
|
||||||
activeTab === 'pending'
|
activeTab === 'currentYear'
|
||||||
? [
|
? registrationFormsDataCurrentYear
|
||||||
...registrationFormsDataPending,
|
: activeTab === 'nextYear'
|
||||||
...registrationFormsDataSubscribed,
|
? registrationFormsDataNextYear
|
||||||
]
|
: registrationFormsDataHistorical
|
||||||
: activeTab === 'subscribed'
|
|
||||||
? registrationFormsDataSubscribed
|
|
||||||
: registrationFormsDataArchived
|
|
||||||
}
|
|
||||||
columns={
|
|
||||||
activeTab === 'subscribed' ? columnsSubscribed : columns
|
|
||||||
}
|
}
|
||||||
|
columns={columns}
|
||||||
itemsPerPage={itemsPerPage}
|
itemsPerPage={itemsPerPage}
|
||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
totalPages={totalPages}
|
totalPages={totalPages}
|
||||||
@ -1102,27 +845,6 @@ export default function Page({ params: { locale } }) {
|
|||||||
onCancel={() => setConfirmPopupVisible(false)}
|
onCancel={() => setConfirmPopupVisible(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{isOpen && (
|
|
||||||
<Modal
|
|
||||||
isOpen={isOpen}
|
|
||||||
setIsOpen={setIsOpen}
|
|
||||||
title={"Nouveau dossier d'inscription"}
|
|
||||||
ContentComponent={() => (
|
|
||||||
<InscriptionForm
|
|
||||||
students={students}
|
|
||||||
registrationDiscounts={registrationDiscounts}
|
|
||||||
tuitionDiscounts={tuitionDiscounts}
|
|
||||||
registrationFees={registrationFees.filter(
|
|
||||||
(fee) => fee.is_active
|
|
||||||
)}
|
|
||||||
tuitionFees={tuitionFees.filter((fee) => fee.is_active)}
|
|
||||||
groups={groups}
|
|
||||||
profiles={profiles}
|
|
||||||
onSubmit={createRF}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isSepaUploadModalOpen && (
|
{isSepaUploadModalOpen && (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={isSepaUploadModalOpen}
|
isOpen={isSepaUploadModalOpen}
|
||||||
|
|||||||
@ -6,9 +6,9 @@ import {
|
|||||||
BE_SUBSCRIPTION_ABSENCES_URL,
|
BE_SUBSCRIPTION_ABSENCES_URL,
|
||||||
} from '@/utils/Url';
|
} from '@/utils/Url';
|
||||||
|
|
||||||
export const PENDING = 'pending';
|
export const CURRENT_YEAR = 'current_year';
|
||||||
export const SUBSCRIBED = 'subscribed';
|
export const NEXT_YEAR = 'next_year';
|
||||||
export const ARCHIVED = 'archived';
|
export const HISTORICAL = 'historical';
|
||||||
|
|
||||||
const requestResponseHandler = async (response) => {
|
const requestResponseHandler = async (response) => {
|
||||||
const body = await response.json();
|
const body = await response.json();
|
||||||
@ -23,7 +23,7 @@ const requestResponseHandler = async (response) => {
|
|||||||
|
|
||||||
export const fetchRegisterForms = (
|
export const fetchRegisterForms = (
|
||||||
establishment,
|
establishment,
|
||||||
filter = PENDING,
|
filter = CURRENT_YEAR,
|
||||||
page = '',
|
page = '',
|
||||||
pageSize = '',
|
pageSize = '',
|
||||||
search = ''
|
search = ''
|
||||||
|
|||||||
@ -6,8 +6,11 @@ export default function InputTextIcon({
|
|||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
errorMsg,
|
errorMsg,
|
||||||
|
errorLocalMsg,
|
||||||
placeholder,
|
placeholder,
|
||||||
className,
|
className,
|
||||||
|
required,
|
||||||
|
enable = true, // Nouvelle prop pour activer/désactiver le champ
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -17,9 +20,16 @@ export default function InputTextIcon({
|
|||||||
className="block text-sm font-medium text-gray-700"
|
className="block text-sm font-medium text-gray-700"
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
|
{required && <span className="text-red-500 ml-1">*</span>}
|
||||||
</label>
|
</label>
|
||||||
<div
|
<div
|
||||||
className={`mt-1 flex items-stretch border border-gray-200 rounded-md ${errorMsg ? 'border-red-500' : ''} hover:border-gray-400 focus-within:border-gray-500`}
|
className={`mt-1 flex items-center border rounded-md ${
|
||||||
|
errorMsg || errorLocalMsg
|
||||||
|
? 'border-red-500 hover:border-red-700'
|
||||||
|
: 'border-gray-200 hover:border-gray-400'
|
||||||
|
} ${!errorMsg && !errorLocalMsg ? 'focus-within:border-gray-500' : ''} ${
|
||||||
|
!enable ? 'bg-gray-100 cursor-not-allowed' : ''
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<span className="inline-flex items-center px-3 rounded-l-md bg-gray-50 text-gray-500 text-sm">
|
<span className="inline-flex items-center px-3 rounded-l-md bg-gray-50 text-gray-500 text-sm">
|
||||||
{IconItem && <IconItem />}
|
{IconItem && <IconItem />}
|
||||||
@ -30,8 +40,12 @@ export default function InputTextIcon({
|
|||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
name={name}
|
name={name}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={enable ? onChange : undefined}
|
||||||
className="flex-1 px-3 py-2 block w-full rounded-r-md sm:text-sm border-none focus:ring-0 outline-none"
|
className={`flex-1 px-3 py-2 block w-full sm:text-sm border-none focus:ring-0 outline-none rounded-md ${
|
||||||
|
!enable ? 'bg-gray-100 cursor-not-allowed' : ''
|
||||||
|
}`}
|
||||||
|
required={required}
|
||||||
|
readOnly={!enable ? 'readOnly' : ''}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{errorMsg && <p className="mt-2 text-sm text-red-600">{errorMsg}</p>}
|
{errorMsg && <p className="mt-2 text-sm text-red-600">{errorMsg}</p>}
|
||||||
|
|||||||
@ -14,6 +14,8 @@ import InputPhone from '../InputPhone';
|
|||||||
import { PhoneLabel } from '../PhoneLabel';
|
import { PhoneLabel } from '../PhoneLabel';
|
||||||
import CheckBox from '@/components/CheckBox';
|
import CheckBox from '@/components/CheckBox';
|
||||||
import RadioList from '@/components/RadioList';
|
import RadioList from '@/components/RadioList';
|
||||||
|
import SelectChoice from '@/components/SelectChoice';
|
||||||
|
import { getCurrentSchoolYear, getNextSchoolYear } from '@/utils/Date';
|
||||||
|
|
||||||
const InscriptionForm = ({
|
const InscriptionForm = ({
|
||||||
students,
|
students,
|
||||||
@ -52,6 +54,7 @@ const InscriptionForm = ({
|
|||||||
selectedTuitionDiscounts: [],
|
selectedTuitionDiscounts: [],
|
||||||
selectedTuitionFees: [],
|
selectedTuitionFees: [],
|
||||||
selectedFileGroup: null, // Ajout du groupe de fichiers sélectionné
|
selectedFileGroup: null, // Ajout du groupe de fichiers sélectionné
|
||||||
|
schoolYear: getCurrentSchoolYear(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -390,6 +393,24 @@ const InscriptionForm = ({
|
|||||||
|
|
||||||
{step === 1 && (
|
{step === 1 && (
|
||||||
<div className="mt-6">
|
<div className="mt-6">
|
||||||
|
{/* Sélection de l'année scolaire */}
|
||||||
|
<SelectChoice
|
||||||
|
name="schoolYear"
|
||||||
|
label="Année scolaire"
|
||||||
|
placeHolder="Sélectionnez une année scolaire"
|
||||||
|
choices={[
|
||||||
|
{ value: getCurrentSchoolYear(), label: getCurrentSchoolYear() },
|
||||||
|
{ value: getNextSchoolYear(), label: getNextSchoolYear() },
|
||||||
|
]}
|
||||||
|
selected={formData.schoolYear || getCurrentSchoolYear()}
|
||||||
|
callback={(e) =>
|
||||||
|
setFormData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
schoolYear: e.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
className="w-full mt-4"
|
||||||
|
/>
|
||||||
<InputTextIcon
|
<InputTextIcon
|
||||||
name="studentLastName"
|
name="studentLastName"
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
@ -8,23 +8,7 @@ import SectionHeader from '@/components/SectionHeader';
|
|||||||
import { User } from 'lucide-react';
|
import { User } from 'lucide-react';
|
||||||
import FileUpload from '@/components/FileUpload';
|
import FileUpload from '@/components/FileUpload';
|
||||||
import { BASE_URL } from '@/utils/Url';
|
import { BASE_URL } from '@/utils/Url';
|
||||||
|
import { levels, genders } from '@/utils/constants';
|
||||||
const levels = [
|
|
||||||
{ value: '1', label: 'TPS - Très Petite Section' },
|
|
||||||
{ value: '2', label: 'PS - Petite Section' },
|
|
||||||
{ value: '3', label: 'MS - Moyenne Section' },
|
|
||||||
{ value: '4', label: 'GS - Grande Section' },
|
|
||||||
{ value: '5', label: 'CP' },
|
|
||||||
{ value: '6', label: 'CE1' },
|
|
||||||
{ value: '7', label: 'CE2' },
|
|
||||||
{ value: '8', label: 'CM1' },
|
|
||||||
{ value: '9', label: 'CM2' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const genders = [
|
|
||||||
{ value: '1', label: 'Garçon' },
|
|
||||||
{ value: '2', label: 'Fille' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function StudentInfoForm({
|
export default function StudentInfoForm({
|
||||||
studentId,
|
studentId,
|
||||||
|
|||||||
@ -1,13 +1,20 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const SectionTitle = ({ title }) => {
|
const SectionTitle = ({ title, children }) => {
|
||||||
return (
|
return (
|
||||||
<div className="relative mb-4">
|
<div className="relative flex">
|
||||||
<div className="absolute inset-0 flex items-center">
|
{/* Liseré vertical */}
|
||||||
<div className="w-full border-t border-gray-300"></div>
|
<div className="w-1 bg-emerald-400"></div>
|
||||||
|
|
||||||
|
{/* Contenu de la section */}
|
||||||
|
<div className="flex-1 pl-6">
|
||||||
|
{/* Titre avec liseré horizontal */}
|
||||||
|
<div className="flex items-center mb-4">
|
||||||
|
<h2 className="text-emerald-700 font-bold text-xl">{title}</h2>
|
||||||
|
<div className="flex-1 h-0.5 bg-emerald-200 ml-4"></div>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative flex justify-center">
|
{/* Contenu passé en children */}
|
||||||
<div className="px-4 bg-white text-gray-500">{title}</div>
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -345,15 +345,17 @@ const DiscountsSection = ({
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4 mt-8">
|
<div className="space-y-4">
|
||||||
|
{!subscriptionMode && (
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
icon={Tag}
|
icon={Tag}
|
||||||
discountStyle={true}
|
discountStyle={true}
|
||||||
title={`${type == 0 ? "Liste des réductions sur les frais d'inscription" : 'Liste des réductions sur les frais de scolarité'}`}
|
title={`${type == 0 ? "Liste des réductions sur les frais d'inscription" : 'Liste des réductions sur les frais de scolarité'}`}
|
||||||
description={`${subscriptionMode ? 'Sélectionnez' : 'Gérez'} ${type == 0 ? " vos réductions sur les frais d'inscription" : ' vos réductions sur les frais de scolarité'}`}
|
description={`'Gérez' ${type == 0 ? " vos réductions sur les frais d'inscription" : ' vos réductions sur les frais de scolarité'}`}
|
||||||
button={!subscriptionMode}
|
button={!subscriptionMode}
|
||||||
onClick={handleAddDiscount}
|
onClick={handleAddDiscount}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
<Table
|
<Table
|
||||||
data={newDiscount ? [newDiscount, ...discounts] : discounts}
|
data={newDiscount ? [newDiscount, ...discounts] : discounts}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
|
|||||||
@ -321,13 +321,15 @@ const FeesSection = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
|
{!subscriptionMode && (
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
icon={CreditCard}
|
icon={CreditCard}
|
||||||
title={`${type == 0 ? "Liste des frais d'inscription" : 'Liste des frais de scolarité'}`}
|
title={`${type == 0 ? "Liste des frais d'inscription" : 'Liste des frais de scolarité'}`}
|
||||||
description={`${subscriptionMode ? 'Sélectionnez' : 'Gérez'} ${type == 0 ? " vos frais d'inscription" : ' vos frais de scolarité'}`}
|
description={`'Gérez'${type == 0 ? " vos frais d'inscription" : ' vos frais de scolarité'}`}
|
||||||
button={!subscriptionMode}
|
button={!subscriptionMode}
|
||||||
onClick={handleAddFee}
|
onClick={handleAddFee}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
<Table
|
<Table
|
||||||
data={newFee ? [newFee, ...fees] : fees}
|
data={newFee ? [newFee, ...fees] : fees}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
|
|||||||
@ -99,3 +99,45 @@ export const isWeekend = (date) => {
|
|||||||
const day = date.getDay();
|
const day = date.getDay();
|
||||||
return day === 0 || day === 6;
|
return day === 0 || day === 6;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne l'année scolaire en cours au format "YYYY-YYYY".
|
||||||
|
* Exemple : Si nous sommes en octobre 2023, retourne "2023-2024".
|
||||||
|
*/
|
||||||
|
export function getCurrentSchoolYear() {
|
||||||
|
const now = new Date();
|
||||||
|
const currentYear = now.getFullYear();
|
||||||
|
const currentMonth = now.getMonth() + 1; // Les mois sont indexés à partir de 0
|
||||||
|
|
||||||
|
// Si nous sommes avant septembre, l'année scolaire a commencé l'année précédente
|
||||||
|
const startYear = currentMonth >= 9 ? currentYear : currentYear - 1;
|
||||||
|
return `${startYear}-${startYear + 1}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne l'année scolaire suivante au format "YYYY-YYYY".
|
||||||
|
* Exemple : Si nous sommes en octobre 2023, retourne "2024-2025".
|
||||||
|
*/
|
||||||
|
export function getNextSchoolYear() {
|
||||||
|
const currentSchoolYear = getCurrentSchoolYear();
|
||||||
|
const [startYear, endYear] = currentSchoolYear.split('-').map(Number);
|
||||||
|
return `${startYear + 1}-${endYear + 1}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne un tableau des années scolaires passées au format "YYYY-YYYY".
|
||||||
|
* Exemple : ["2022-2023", "2021-2022", "2020-2021"].
|
||||||
|
* @param {number} count - Le nombre d'années scolaires passées à inclure.
|
||||||
|
*/
|
||||||
|
export function getHistoricalYears(count = 5) {
|
||||||
|
const currentSchoolYear = getCurrentSchoolYear();
|
||||||
|
const [startYear] = currentSchoolYear.split('-').map(Number);
|
||||||
|
|
||||||
|
const historicalYears = [];
|
||||||
|
for (let i = 1; i <= count; i++) {
|
||||||
|
const historicalStartYear = startYear - i;
|
||||||
|
historicalYears.push(`${historicalStartYear}-${historicalStartYear + 1}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return historicalYears;
|
||||||
|
}
|
||||||
|
|||||||
@ -68,6 +68,7 @@ export const FE_ADMIN_HOME_URL = `/admin`;
|
|||||||
|
|
||||||
// ADMIN/SUBSCRIPTIONS URL
|
// ADMIN/SUBSCRIPTIONS URL
|
||||||
export const FE_ADMIN_SUBSCRIPTIONS_URL = `/admin/subscriptions`;
|
export const FE_ADMIN_SUBSCRIPTIONS_URL = `/admin/subscriptions`;
|
||||||
|
export const FE_ADMIN_SUBSCRIPTIONS_CREATE_URL = `/admin/subscriptions/createSubscription`;
|
||||||
export const FE_ADMIN_SUBSCRIPTIONS_EDIT_URL = `/admin/subscriptions/editInscription`;
|
export const FE_ADMIN_SUBSCRIPTIONS_EDIT_URL = `/admin/subscriptions/editInscription`;
|
||||||
export const FE_ADMIN_SUBSCRIPTIONS_VALIDATE_URL = `/admin/subscriptions/validateSubscription`;
|
export const FE_ADMIN_SUBSCRIPTIONS_VALIDATE_URL = `/admin/subscriptions/validateSubscription`;
|
||||||
|
|
||||||
|
|||||||
16
Front-End/src/utils/constants.js
Normal file
16
Front-End/src/utils/constants.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export const levels = [
|
||||||
|
{ value: '1', label: 'TPS - Très Petite Section' },
|
||||||
|
{ value: '2', label: 'PS - Petite Section' },
|
||||||
|
{ value: '3', label: 'MS - Moyenne Section' },
|
||||||
|
{ value: '4', label: 'GS - Grande Section' },
|
||||||
|
{ value: '5', label: 'CP' },
|
||||||
|
{ value: '6', label: 'CE1' },
|
||||||
|
{ value: '7', label: 'CE2' },
|
||||||
|
{ value: '8', label: 'CM1' },
|
||||||
|
{ value: '9', label: 'CM2' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const genders = [
|
||||||
|
{ value: '1', label: 'Garçon' },
|
||||||
|
{ value: '2', label: 'Fille' },
|
||||||
|
];
|
||||||
Reference in New Issue
Block a user