diff --git a/Back-End/Subscriptions/models.py b/Back-End/Subscriptions/models.py
index b183107..582cc67 100644
--- a/Back-End/Subscriptions/models.py
+++ b/Back-End/Subscriptions/models.py
@@ -182,6 +182,10 @@ class Student(models.Model):
return self.birth_date.strftime('%d-%m-%Y')
return None
+def registration_file_path(instance, filename):
+ # Génère le chemin : registration_files/dossier_rf_{student_id}/filename
+ return f'registration_files/dossier_rf_{instance.student_id}/{filename}'
+
class RegistrationForm(models.Model):
"""
Gère le dossier d’inscription lié à un élève donné.
@@ -201,7 +205,11 @@ class RegistrationForm(models.Model):
last_update = models.DateTimeField(auto_now=True)
notes = models.CharField(max_length=200, blank=True)
registration_link_code = models.CharField(max_length=200, default="", blank=True)
- registration_file = models.FileField(upload_to=settings.DOCUMENT_DIR, default="", blank=True)
+ registration_file = models.FileField(
+ upload_to=registration_file_path,
+ null=True,
+ blank=True
+ )
associated_rf = models.CharField(max_length=200, default="", blank=True)
def __str__(self):
diff --git a/Back-End/Subscriptions/util.py b/Back-End/Subscriptions/util.py
index e76d06b..622bac5 100644
--- a/Back-End/Subscriptions/util.py
+++ b/Back-End/Subscriptions/util.py
@@ -93,31 +93,57 @@ def getArgFromRequest(_argument, _request):
def merge_files_pdf(filenames, output_filename):
"""
- Insère plusieurs fichiers PDF dans un seul document de sortie.
+ Fusionne plusieurs fichiers PDF en un seul document.
+ Vérifie l'existence des fichiers sources avant la fusion.
"""
merger = pymupdf.open()
+ valid_files = []
+
+ # Vérifier l'existence des fichiers et ne garder que ceux qui existent
for filename in filenames:
+ if os.path.exists(filename):
+ valid_files.append(filename)
+
+ # Fusionner les fichiers valides
+ for filename in valid_files:
merger.insert_file(filename)
+
+ # S'assurer que le dossier de destination existe
+ os.makedirs(os.path.dirname(output_filename), exist_ok=True)
+
+ # Sauvegarder le fichier fusionné
merger.save(output_filename)
merger.close()
-def rfToPDF(registerForm,filename):
+ return output_filename
+
+def rfToPDF(registerForm, filename):
"""
- Génère le PDF d’un dossier d’inscription et l’associe au RegistrationForm.
+ Génère le PDF d'un dossier d'inscription et l'associe au RegistrationForm.
"""
- # Ajout du fichier d'inscriptions
data = {
- 'pdf_title': "Dossier d'inscription de %s"%registerForm.student.first_name,
+ 'pdf_title': f"Dossier d'inscription de {registerForm.student.first_name}",
'signatureDate': convertToStr(_now(), '%d-%m-%Y'),
'signatureTime': convertToStr(_now(), '%H:%M'),
- 'student':registerForm.student,
+ 'student': registerForm.student,
}
- PDFFileName = filename
+
+ # S'assurer que le dossier parent existe
+ os.makedirs(os.path.dirname(filename), exist_ok=True)
+
+ # Générer le PDF
pdf = renderers.render_to_pdf('pdfs/dossier_inscription.html', data)
- pathFichier = Path(filename)
- if os.path.exists(str(pathFichier)):
- print(f'File exists : {str(pathFichier)}')
- os.remove(str(pathFichier))
- receipt_file = BytesIO(pdf.content)
- registerForm.fichierInscription = File(receipt_file, PDFFileName)
- registerForm.fichierInscription.save()
\ No newline at end of file
+
+ # Écrire le fichier directement
+ with open(filename, 'wb') as f:
+ f.write(pdf.content)
+
+ # Mettre à jour le champ registration_file du registerForm
+ with open(filename, 'rb') as f:
+ registerForm.registration_file.save(
+ os.path.basename(filename),
+ File(f),
+ save=True
+ )
+
+ return registerForm.registration_file
\ No newline at end of file
diff --git a/Back-End/Subscriptions/views.py b/Back-End/Subscriptions/views.py
index 5a29bd8..d635bf7 100644
--- a/Back-End/Subscriptions/views.py
+++ b/Back-End/Subscriptions/views.py
@@ -179,20 +179,37 @@ class RegisterFormView(APIView):
registerForm = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=_id)
if _status == RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW:
- # Le parent a complété le dossier d'inscription, il est soumis à validation par l'école
- json.dumps(studentForm_data)
- #Génération de la fiche d'inscription au format PDF
- PDFFileName = "rf_%s_%s.pdf"%(registerForm.student.last_name, registerForm.student.first_name)
- path = Path(f"registration_files/dossier_rf_{registerForm.pk}/{PDFFileName}")
- registerForm.fichierInscription = util.rfToPDF(registerForm, path)
- # Récupération des fichiers d'inscription
- fileNames = RegistrationFile.get_files_from_rf(registerForm.pk)
- fileNames.insert(0,path)
- # Création du fichier PDF Fusionné avec le dossier complet
- output_path = f"registration_files/dossier_rf_{registerForm.pk}/dossier_{registerForm.pk}.pdf"
- util.merge_files_pdf(fileNames, output_path)
- # Mise à jour de l'automate
- updateStateMachine(registerForm, 'saisiDI')
+ try:
+ # Génération de la fiche d'inscription au format PDF
+ base_dir = f"registration_files/dossier_rf_{registerForm.pk}"
+ os.makedirs(base_dir, exist_ok=True)
+
+ # Fichier PDF initial
+ initial_pdf = f"{base_dir}/rf_{registerForm.student.last_name}_{registerForm.student.first_name}.pdf"
+ registerForm.registration_file = util.rfToPDF(registerForm, initial_pdf)
+ registerForm.save()
+
+ # Récupération des fichiers d'inscription
+ fileNames = RegistrationFile.get_files_from_rf(registerForm.pk)
+ if registerForm.registration_file:
+ fileNames.insert(0, registerForm.registration_file.path)
+
+ # Création du fichier PDF Fusionné
+ merged_pdf = f"{base_dir}/dossier_complet_{registerForm.pk}.pdf"
+ util.merge_files_pdf(fileNames, merged_pdf)
+
+ # Mise à jour du champ registration_file avec le fichier fusionné
+ with open(merged_pdf, 'rb') as f:
+ registerForm.registration_file.save(
+ os.path.basename(merged_pdf),
+ File(f),
+ save=True
+ )
+
+ # Mise à jour de l'automate
+ updateStateMachine(registerForm, 'saisiDI')
+ except Exception as e:
+ return JsonResponse({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
elif _status == RegistrationForm.RegistrationFormStatus.RF_VALIDATED:
# L'école a validé le dossier d'inscription
# Mise à jour de l'automate
diff --git a/Front-End/src/app/[locale]/admin/subscriptions/editInscription/page.js b/Front-End/src/app/[locale]/admin/subscriptions/editInscription/page.js
index 35d0520..510e121 100644
--- a/Front-End/src/app/[locale]/admin/subscriptions/editInscription/page.js
+++ b/Front-End/src/app/[locale]/admin/subscriptions/editInscription/page.js
@@ -16,29 +16,10 @@ export default function Page() {
const studentId = searchParams.get('studentId'); // Changé de codeDI à studentId
const [initialData, setInitialData] = useState(null);
- const [isLoading, setIsLoading] = useState(true);
+
const [formErrors, setFormErrors] = useState({});
const csrfToken = useCsrfToken();
- useEffect(() => {
- if (useFakeData) {
- setInitialData(mockStudent);
- } else {
- fetchRegisterForm(studentId)
- .then(data => {
- console.log('Fetched data:', data); // Pour le débogage
- const formattedData = {
- ...data,
- guardians: data.guardians || []
- };
- setInitialData(formattedData);
- })
- .catch(error => {
- console.error('Error fetching student data:', error);
- });
- }
- setIsLoading(false);
- }, [studentId]); // Dépendance changée à studentId
const handleSubmit = (data) => {
if (useFakeData) {
@@ -64,11 +45,10 @@ export default function Page() {
return (
);
diff --git a/Front-End/src/app/[locale]/admin/subscriptions/page.js b/Front-End/src/app/[locale]/admin/subscriptions/page.js
index 5ddb2da..516916d 100644
--- a/Front-End/src/app/[locale]/admin/subscriptions/page.js
+++ b/Front-End/src/app/[locale]/admin/subscriptions/page.js
@@ -320,99 +320,79 @@ useEffect(()=>{
};
const createRF = (updatedData) => {
- console.log('createRF updatedData:', updatedData);
-
if (updatedData.selectedGuardians.length !== 0) {
const selectedGuardiansIds = updatedData.selectedGuardians.map(guardianId => guardianId)
-
const data = {
- student: {
- last_name: updatedData.studentLastName,
- first_name: updatedData.studentFirstName,
- },
- idGuardians: selectedGuardiansIds
+ student: {
+ last_name: updatedData.studentLastName,
+ first_name: updatedData.studentFirstName,
+ },
+ idGuardians: selectedGuardiansIds
};
- createRegisterForm(data,csrfToken)
- .then(data => {
- console.log('Success:', data);
- setRegistrationFormsDataPending(prevState => {
- if (prevState) {
- return [...prevState, data];
+ createRegisterForm(data, csrfToken)
+ .then(data => {
+ // 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);
}
- return [data];
- });
- setTotalPending(totalPending+1);
- if (updatedData.autoMail) {
- sendConfirmRegisterForm(data.student.id, updatedData.studentLastName, updatedData.studentFirstName);
- }
- })
- .catch((error) => {
+ closeModal();
+ // Forcer le rechargement complet des données
+ setReloadFetch(true);
+ })
+ .catch((error) => {
console.error('Error:', error);
- });
- }
- else {
- // Création d'un profil associé à l'adresse mail du responsable saisie
- // Le profil est inactif
- const data = {
- email: updatedData.guardianEmail,
- password: 'Provisoire01!',
- username: updatedData.guardianEmail,
- is_active: 0, // On rend le profil inactif : impossible de s'y connecter dans la fenêtre du login tant qu'il ne s'est pas inscrit
- droit:2 // Profil PARENT
- }
- createProfile(data,csrfToken)
+ });
+ } else {
+ const data = {
+ email: updatedData.guardianEmail,
+ password: 'Provisoire01!',
+ username: updatedData.guardianEmail,
+ is_active: 0,
+ droit: 2
+ }
+
+ createProfile(data, csrfToken)
.then(response => {
- console.log('Success:', response);
- if (response.id) {
- let idProfile = response.id;
+ if (response.id) {
+ const data = {
+ student: {
+ last_name: updatedData.studentLastName,
+ first_name: updatedData.studentFirstName,
+ guardians: [{
+ email: updatedData.guardianEmail,
+ phone: updatedData.guardianPhone,
+ associated_profile: response.id
+ }],
+ sibling: []
+ }
+ };
- const data = {
- student: {
- last_name: updatedData.studentLastName,
- first_name: updatedData.studentFirstName,
- guardians: [
- {
- email: updatedData.guardianEmail,
- phone: updatedData.guardianPhone,
- associated_profile: idProfile // Association entre le responsable de l'élève et le profil créé par défaut précédemment
- }
- ],
- sibling: []
- }
- };
-
- createRegisterForm(data,csrfToken)
- .then(data => {
- console.log('Success:', data);
- setRegistrationFormsDataPending(prevState => {
- if (prevState && prevState.length > 0) {
- return [...prevState, data];
- }
- return prevState;
- });
- setTotalPending(totalPending+1);
- if (updatedData.autoMail) {
- sendConfirmRegisterForm(data.student.id, updatedData.studentLastName, updatedData.studentFirstName);
- }
- })
- .catch((error) => {
- console.error('Error:', error);
- });
- }
+ createRegisterForm(data, csrfToken)
+ .then(data => {
+ // 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();
+ // Forcer le rechargement complet des données
+ setReloadFetch(true);
+ })
+ .catch((error) => {
+ console.error('Error:', error);
+ });
+ }
})
.catch(error => {
- console.error('Error fetching data:', error);
- error = error.errorMessage;
- console.log(error);
+ console.error('Error:', error);
});
}
- closeModal();
- setReloadFetch(true);
}
-
-
const columns = [
{ name: t('studentName'), transform: (row) => row.student.last_name },
{ name: t('studentFistName'), transform: (row) => row.student.first_name },
@@ -426,11 +406,11 @@ const columns = [
)
},
{ name: t('files'), transform: (row) =>
- (row.registerForms != null) &&(
+ (row.registration_file != null) &&(
) },
@@ -507,11 +487,11 @@ const columnsSubscribed = [
)
},
{ name: t('files'), transform: (row) =>
- (row.registerForm != null) &&(
+ (row.registration_file != null) &&(
) },
@@ -677,7 +657,7 @@ const handleFileUpload = ({file, name, is_required, order}) => {
text={(
<>
{t('subscribeFiles')}
- ({totalSubscribed})
+ ({fichiers.length})
>
)}
active={activeTab === 'subscribeFiles'}
@@ -735,12 +715,14 @@ const handleFileUpload = ({file, name, is_required, order}) => {
{/*SI STATE == subscribeFiles */}
{activeTab === 'subscribeFiles' && (
-
+
+
+
{
- if (!studentId || !idProfil) {
- console.error('Missing studentId or idProfil');
- return;
- }
- if (useFakeData) {
- setInitialData(mockStudent);
- setLastGuardianId(999);
- setIsLoading(false);
- } else {
- Promise.all([
- // Fetch eleve data
- fetchRegisterForm(studentId),
- // Fetch last guardian ID
- fetchLastGuardian()
- ])
- .then(async ([studentData, guardianData]) => {
- const formattedData = {
- ...studentData,
- guardians: studentData.guardians || []
- };
-
- setInitialData(formattedData);
- setLastGuardianId(guardianData.lastid);
-
- let profils = studentData.profils;
- const currentProf = profils.find(profil => profil.id === idProfil);
- if (currentProf) {
- setCurrentProfil(currentProf);
- }
- })
- .catch(error => {
- console.error('Error fetching data:', error);
- })
- .finally(() => {
- setIsLoading(false);
- });
- }
- }, [studentId, idProfil]);
const handleSubmit = async (data) => {
if (useFakeData) {
console.log('Fake submit:', data);
return;
}
-
try {
-
const result = await editRegisterForm(studentId, data, csrfToken);
console.log('Success:', result);
router.push(FE_PARENTS_HOME_URL);
@@ -80,7 +37,7 @@ export default function Page() {
return (
{
- return fetch(`${BE_SUBSCRIPTION_STUDENT_URL}/${id}`) // Utilisation de studentId au lieu de codeDI
+ return fetch(`${BE_SUBSCRIPTION_REGISTERFORM_URL}/${id}`) // Utilisation de studentId au lieu de codeDI
.then(requestResponseHandler)
}
export const fetchLastGuardian = () =>{
@@ -98,31 +98,36 @@ export const sendRegisterForm = (id) => {
}
-export const fetchRegisterFormFileTemplate = () => {
- const request = new Request(
- `${BE_SUBSCRIPTION_REGISTRATIONFORMFILE_TEMPLATE_URL}`,
- {
- method:'GET',
- headers: {
- 'Content-Type':'application/json'
- },
- }
- );
- return fetch(request).then(requestResponseHandler)
+
+
+export const fetchRegisterFormFile = (id = null) => {
+ let url = `${BE_SUBSCRIPTION_REGISTRATIONFORMFILE_URL}`
+ if (id) {
+ url = `${BE_SUBSCRIPTION_REGISTRATIONFORMFILE_URL}/${id}`;
+ }
+ const request = new Request(
+ `${url}`,
+ {
+ method:'GET',
+ headers: {
+ 'Content-Type':'application/json'
+ },
+ }
+ );
+ return fetch(request).then(requestResponseHandler)
};
-export const fetchRegisterFormFile = (id) => {
- const request = new Request(
- `${BE_SUBSCRIPTION_REGISTRATIONFORMFILE_URL}/${id}`,
- {
- method:'GET',
- headers: {
- 'Content-Type':'application/json'
- },
- }
- );
- return fetch(request).then(requestResponseHandler)
-};
+export const editRegistrationFormFile= (fileId, data, csrfToken) => {
+ return fetch(`${BE_SUBSCRIPTION_REGISTRATIONFORMFILE_URL}/${fileId}`, {
+ method: 'PUT',
+ body: data,
+ headers: {
+ 'X-CSRFToken': csrfToken,
+ },
+ credentials: 'include',
+ })
+ .then(requestResponseHandler)
+}
export const createRegistrationFormFile = (data,csrfToken) => {
@@ -137,6 +142,33 @@ export const createRegistrationFormFile = (data,csrfToken) => {
.then(requestResponseHandler)
}
+export const deleteRegisterFormFile= (fileId,csrfToken) => {
+ return fetch(`${BE_SUBSCRIPTION_REGISTRATIONFORMFILE_URL}/${fileId}`, {
+ method: 'DELETE',
+ headers: {
+ 'X-CSRFToken': csrfToken,
+ },
+ credentials: 'include',
+ })
+}
+
+export const fetchRegisterFormFileTemplate = (id = null) => {
+ let url = `${BE_SUBSCRIPTION_REGISTRATIONFORMFILE_TEMPLATE_URL}`;
+ if(id){
+ url = `${BE_SUBSCRIPTION_REGISTRATIONFORMFILE_TEMPLATE_URL}/${id}`;
+ }
+ const request = new Request(
+ `${url}`,
+ {
+ method:'GET',
+ headers: {
+ 'Content-Type':'application/json'
+ },
+ }
+ );
+ return fetch(request).then(requestResponseHandler)
+};
+
export const createRegistrationFormFileTemplate = (data,csrfToken) => {
return fetch(`${BE_SUBSCRIPTION_REGISTRATIONFORMFILE_TEMPLATE_URL}`, {
diff --git a/Front-End/src/components/AffectationClasseForm.js b/Front-End/src/components/AffectationClasseForm.js
index d118c56..b96db19 100644
--- a/Front-End/src/components/AffectationClasseForm.js
+++ b/Front-End/src/components/AffectationClasseForm.js
@@ -1,9 +1,9 @@
import React, { useState } from 'react';
-const AffectationClasseForm = ({ eleve, onSubmit, classes }) => {
+const AffectationClasseForm = ({ eleve = {}, onSubmit, classes }) => {
const [formData, setFormData] = useState({
- classeAssocie_id: eleve.classeAssocie_id || null,
+ classeAssocie_id: eleve?.classeAssocie_id || null,
});
const handleChange = (e) => {
diff --git a/Front-End/src/components/FileStatusLabel.js b/Front-End/src/components/FileStatusLabel.js
new file mode 100644
index 0000000..29330c5
--- /dev/null
+++ b/Front-End/src/components/FileStatusLabel.js
@@ -0,0 +1,33 @@
+import React from 'react';
+import { Check, Clock } from 'lucide-react';
+
+const FileStatusLabel = ({ status }) => {
+ const getStatusConfig = () => {
+ switch (status) {
+ case 'sent':
+ return {
+ label: 'Envoyé',
+ className: 'bg-green-50 text-green-600',
+ icon:
+ };
+ case 'pending':
+ default:
+ return {
+ label: 'En attente',
+ className: 'bg-orange-50 text-orange-600',
+ icon:
+ };
+ }
+ };
+
+ const { label, className, icon } = getStatusConfig();
+
+ return (
+
+ {icon}
+ {label}
+
+ );
+};
+
+export default FileStatusLabel;
diff --git a/Front-End/src/components/Inscription/InscriptionFormShared.js b/Front-End/src/components/Inscription/InscriptionFormShared.js
index 051f749..34aa4c3 100644
--- a/Front-End/src/components/Inscription/InscriptionFormShared.js
+++ b/Front-End/src/components/Inscription/InscriptionFormShared.js
@@ -1,3 +1,4 @@
+// Import des dépendances nécessaires
import React, { useState, useEffect } from 'react';
import InputText from '@/components/InputText';
import SelectChoice from '@/components/SelectChoice';
@@ -6,12 +7,14 @@ import Loader from '@/components/Loader';
import Button from '@/components/Button';
import DjangoCSRFToken from '@/components/DjangoCSRFToken';
import Table from '@/components/Table';
-import { fetchRegisterFormFileTemplate, createRegistrationFormFile } from '@/app/lib/subscriptionAction';
-import { Download, Upload } from 'lucide-react';
+import { fetchRegisterFormFileTemplate, createRegistrationFormFile, fetchRegisterForm, deleteRegisterFormFile } from '@/app/lib/subscriptionAction';
+import { Download, Upload, Trash2, Eye } from 'lucide-react';
import { BASE_URL } from '@/utils/Url';
import DraggableFileUpload from '@/app/[locale]/admin/subscriptions/components/DraggableFileUpload';
import Modal from '@/components/Modal';
+import FileStatusLabel from '@/components/FileStatusLabel';
+// Définition des niveaux scolaires disponibles
const levels = [
{ value:'1', label: 'TPS - Très Petite Section'},
{ value:'2', label: 'PS - Petite Section'},
@@ -19,32 +22,28 @@ const levels = [
{ value:'4', label: 'GS - Grande Section'},
];
+/**
+ * Composant de formulaire d'inscription partagé
+ * @param {string} studentId - ID de l'étudiant
+ * @param {string} csrfToken - Token CSRF pour la sécurité
+ * @param {function} onSubmit - Fonction de soumission du formulaire
+ * @param {string} cancelUrl - URL de redirection en cas d'annulation
+ * @param {object} errors - Erreurs de validation du formulaire
+ */
export default function InscriptionFormShared({
- initialData,
+ studentId,
csrfToken,
onSubmit,
cancelUrl,
- isLoading = false,
errors = {} // Nouvelle prop pour les erreurs
}) {
+ // États pour gérer les données du formulaire
+ const [isLoading, setIsLoading] = useState(true);
+ const [formData, setFormData] = useState({});
- const [formData, setFormData] = useState(() => ({
- id: initialData?.id || '',
- last_name: initialData?.last_name || '',
- first_name: initialData?.first_name || '',
- address: initialData?.address || '',
- birth_date: initialData?.birth_date || '',
- birth_place: initialData?.birth_place || '',
- birth_postal_code: initialData?.birth_postal_code || '',
- nationality: initialData?.nationality || '',
- attending_physician: initialData?.attending_physician || '',
- level: initialData?.level || ''
- }));
-
- const [guardians, setGuardians] = useState(() =>
- initialData?.guardians || []
- );
+ const [guardians, setGuardians] = useState([]);
+ // États pour la gestion des fichiers
const [uploadedFiles, setUploadedFiles] = useState([]);
const [fileTemplates, setFileTemplates] = useState([]);
const [fileName, setFileName] = useState("");
@@ -52,50 +51,104 @@ export default function InscriptionFormShared({
const [showUploadModal, setShowUploadModal] = useState(false);
const [currentTemplateId, setCurrentTemplateId] = useState(null);
+ // Chargement initial des données
// Mettre à jour les données quand initialData change
useEffect(() => {
- if (initialData) {
- setFormData({
- id: initialData.id || '',
- last_name: initialData.last_name || '',
- first_name: initialData.first_name || '',
- address: initialData.address || '',
- birth_date: initialData.birth_date || '',
- birth_place: initialData.birth_place || '',
- birth_postal_code: initialData.birth_postal_code || '',
- nationality: initialData.nationality || '',
- attending_physician: initialData.attending_physician || '',
- level: initialData.level || ''
+ if (studentId) {
+ fetchRegisterForm(studentId).then((data) => {
+ console.log(data);
+
+ setFormData({
+ id: data?.student?.id || '',
+ last_name: data?.student?.last_name || '',
+ first_name: data?.student?.first_name || '',
+ address: data?.student?.address || '',
+ birth_date: data?.student?.birth_date || '',
+ birth_place: data?.student?.birth_place || '',
+ birth_postal_code: data?.student?.birth_postal_code || '',
+ nationality: data?.student?.nationality || '',
+ attending_physician: data?.student?.attending_physician || '',
+ level: data?.student?.level || ''
+ });
+ setGuardians(data?.student?.guardians || []);
+ setUploadedFiles(data.registration_files || []);
});
- setGuardians(initialData.guardians || []);
+
fetchRegisterFormFileTemplate().then((data) => {
setFileTemplates(data);
});
+ setIsLoading(false);
}
- }, [initialData]);
+ }, [studentId]);
+ // Fonctions de gestion du formulaire et des fichiers
const updateFormField = (field, value) => {
setFormData(prev => ({...prev, [field]: value}));
};
+ // Gestion du téléversement de fichiers
const handleFileUpload = async (file, fileName) => {
+ if (!file || !currentTemplateId || !formData.id) {
+ console.error('Missing required data for upload');
+ return;
+ }
+
const data = new FormData();
data.append('file', file);
- data.append('name',fileName);
+ data.append('name', fileName);
data.append('template', currentTemplateId);
data.append('register_form', formData.id);
try {
- await createRegistrationFormFile(data, csrfToken);
- // Optionnellement, rafraîchir la liste des fichiers
- fetchRegisterFormFileTemplate().then((data) => {
- setFileTemplates(data);
- });
+ const response = await createRegistrationFormFile(data, csrfToken);
+ if (response) {
+ setUploadedFiles(prev => {
+ const newFiles = prev.filter(f => parseInt(f.template) !== currentTemplateId);
+ return [...newFiles, {
+ name: fileName,
+ template: currentTemplateId,
+ file: response.file
+ }];
+ });
+
+ // Rafraîchir les données du formulaire pour avoir les fichiers à jour
+ if (studentId) {
+ fetchRegisterForm(studentId).then((data) => {
+ setUploadedFiles(data.registration_files || []);
+ });
+ }
+ }
} catch (error) {
console.error('Error uploading file:', error);
}
};
+ // Vérification si un fichier est déjà uploadé
+ const isFileUploaded = (templateId) => {
+ return uploadedFiles.find(template =>
+ template.template === templateId
+ );
+ };
+
+ // Récupération d'un fichier uploadé
+ const getUploadedFile = (templateId) => {
+ return uploadedFiles.find(file => parseInt(file.template) === templateId);
+ };
+
+ // Suppression d'un fichier
+ const handleDeleteFile = async (templateId) => {
+ const fileToDelete = getUploadedFile(templateId);
+ if (!fileToDelete) return;
+
+ try {
+ await deleteRegisterFormFile(fileToDelete.id, csrfToken);
+ setUploadedFiles(prev => prev.filter(f => parseInt(f.template) !== templateId));
+ } catch (error) {
+ console.error('Error deleting file:', error);
+ }
+ };
+
+ // Soumission du formulaire
const handleSubmit = (e) => {
e.preventDefault();
const data ={
@@ -107,36 +160,70 @@ export default function InscriptionFormShared({
onSubmit(data);
};
+ // Récupération des messages d'erreur
const getError = (field) => {
return errors?.student?.[field]?.[0];
};
- const getGuardianError = (index, field) => {
- return errors?.student?.guardians?.[index]?.[field]?.[0];
- };
-
+ // Configuration des colonnes pour le tableau des fichiers
const columns = [
{ name: 'Nom du fichier', transform: (row) => row.name },
{ name: 'Fichier à Remplir', transform: (row) => row.is_required ? 'Oui' : 'Non' },
{ name: 'Fichier de référence', transform: (row) => row.file && },
- { name: 'Actions', transform: (row) => (
-
- {row.is_required &&
-
- ) },
+ );
+ }},
];
+ // Affichage du loader pendant le chargement
if (isLoading) return ;
+ // Rendu du composant
return (
{/* Section Fichiers d'inscription */}
-
-
Fichiers à remplir
-
{}}
- />
-
+ {fileTemplates.length > 0 && (
+
+
Fichiers à remplir
+
{}}
+ />
+
+ )}
{/* Boutons de contrôle */}
@@ -263,44 +352,52 @@ export default function InscriptionFormShared({
- (
- <>
- {
- setFile(selectedFile);
- setFileName(selectedFile.name);
- }}
- >
-
-
-
-
- {
- setShowUploadModal(false);
- setCurrentTemplateId(null);
+ {fileTemplates.length > 0 && (
+ (
+ <>
+ {
+ if (selectedFile) {
+ setFile(selectedFile);
+ setFileName(selectedFile.name);
+ }
}}
/>
- {
- setShowUploadModal(false);
- handleFileUpload(file, fileName);
- setCurrentTemplateId(null);
- }}
- primary={true}
- />
-
- >
- )}
- />
+
+ {
+ setShowUploadModal(false);
+ setCurrentTemplateId(null);
+ setFile(null);
+ setFileName("");
+ }}
+ />
+ {
+ if (file && fileName) {
+ handleFileUpload(file, fileName);
+ setShowUploadModal(false);
+ setCurrentTemplateId(null);
+ setFile(null);
+ setFileName("");
+ }
+ }}
+ primary={true}
+ disabled={!file || !fileName}
+ />
+
+ >
+ )}
+ />
+ )}
);
}
\ No newline at end of file
diff --git a/Front-End/src/components/Inscription/ResponsableInputFields.js b/Front-End/src/components/Inscription/ResponsableInputFields.js
index edaf92d..4cdb49b 100644
--- a/Front-End/src/components/Inscription/ResponsableInputFields.js
+++ b/Front-End/src/components/Inscription/ResponsableInputFields.js
@@ -4,6 +4,7 @@ import Button from '@/components/Button';
import React from 'react';
import { useTranslations } from 'next-intl';
import 'react-phone-number-input/style.css'
+import { Trash2, Plus } from 'lucide-react';
export default function ResponsableInputFields({guardians, onGuardiansChange, addGuardian, deleteGuardian, errors = []}) {
const t = useTranslations('ResponsableInputFields');
@@ -19,10 +20,9 @@ export default function ResponsableInputFields({guardians, onGuardiansChange, ad
{t('responsable')} {index+1}
{guardians.length > 1 && (
- deleteGuardian(index)}
- className="w-32"
/>
)}
@@ -102,13 +102,9 @@ export default function ResponsableInputFields({guardians, onGuardiansChange, ad
))}
- addGuardian(e)}
- primary
- icon={}
- type="button"
- className="w-64"
/>
diff --git a/Front-End/src/hooks/useCsrfToken.js b/Front-End/src/hooks/useCsrfToken.js
index 284dc8b..1489d70 100644
--- a/Front-End/src/hooks/useCsrfToken.js
+++ b/Front-End/src/hooks/useCsrfToken.js
@@ -14,7 +14,7 @@ const useCsrfToken = () => {
if (data) {
if(data.csrfToken != token) {
setToken(data.csrfToken);
- console.log('------------> CSRF Token reçu:', data.csrfToken);
+ //console.log('------------> CSRF Token reçu:', data.csrfToken);
}
}
})