fix: Application du formattage sur les fichiers modifiés

This commit is contained in:
N3WT DE COMPET
2025-04-27 09:48:28 +02:00
parent 905b95f3a3
commit 001a5bc83c
10 changed files with 486 additions and 306 deletions

View File

@ -54,9 +54,7 @@ import {
fetchTuitionFees, fetchTuitionFees,
} from '@/app/actions/schoolAction'; } from '@/app/actions/schoolAction';
import { import { fetchProfiles } from '@/app/actions/authAction';
fetchProfiles,
} from '@/app/actions/authAction';
import { import {
BASE_URL, BASE_URL,
@ -145,7 +143,7 @@ export default function Page({ params: { locale } }) {
const files = []; const files = [];
if (row.registration_file) { if (row.registration_file) {
files.push({ files.push({
name: 'Fichier d\'inscription', name: "Fichier d'inscription",
url: `${BASE_URL}${row.registration_file}`, url: `${BASE_URL}${row.registration_file}`,
}); });
} }
@ -164,7 +162,7 @@ export default function Page({ params: { locale } }) {
setSelectedRowFiles([]); setSelectedRowFiles([]);
}; };
const requestErrorHandler = (err)=>{ const requestErrorHandler = (err) => {
logger.error('Error fetching data:', err); logger.error('Error fetching data:', err);
}; };
@ -585,7 +583,7 @@ export default function Page({ params: { locale } }) {
}) })
.catch((error) => { .catch((error) => {
logger.error( logger.error(
'Erreur lors de l\'enregistrement du template:', "Erreur lors de l'enregistrement du template:",
error error
); );
}); });
@ -607,14 +605,11 @@ export default function Page({ params: { locale } }) {
csrfToken csrfToken
) )
.then((response) => { .then((response) => {
logger.debug( logger.debug('Parent template enregistré avec succès:', response);
'Parent template enregistré avec succès:',
response
);
}) })
.catch((error) => { .catch((error) => {
logger.error( logger.error(
'Erreur lors de l\'enregistrement du parent template:', "Erreur lors de l'enregistrement du parent template:",
error error
); );
}); });
@ -1166,45 +1161,45 @@ export default function Page({ params: { locale } }) {
/> />
)} )}
{isOpenAddGuardian && ( {isOpenAddGuardian && (
<Modal <Modal
isOpen={isOpenAddGuardian} isOpen={isOpenAddGuardian}
setIsOpen={setIsOpenAddGuardian} setIsOpen={setIsOpenAddGuardian}
title="Ajouter un responsable" title="Ajouter un responsable"
ContentComponent={() => ( ContentComponent={() => (
<InscriptionForm <InscriptionForm
students={students} students={students}
profiles={profiles} profiles={profiles}
onSubmit={updateRF} onSubmit={updateRF}
currentStep={2} currentStep={2}
showOnlyStep2={true} showOnlyStep2={true}
/> />
)} )}
/> />
)} )}
{isFilesModalOpen && ( {isFilesModalOpen && (
<Modal <Modal
isOpen={isFilesModalOpen} isOpen={isFilesModalOpen}
setIsOpen={setIsFilesModalOpen} setIsOpen={setIsFilesModalOpen}
title="Fichiers disponibles" title="Fichiers disponibles"
ContentComponent={() => ( ContentComponent={() => (
<ul className="space-y-4"> <ul className="space-y-4">
{selectedRowFiles.map((file, index) => ( {selectedRowFiles.map((file, index) => (
<li key={index} className="flex items-center gap-2"> <li key={index} className="flex items-center gap-2">
<FileText className="w-5 h-5 text-gray-500" /> <FileText className="w-5 h-5 text-gray-500" />
<a <a
href={file.url} href={file.url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-blue-500 hover:text-blue-700 underline" className="text-blue-500 hover:text-blue-700 underline"
> >
{file.name} {file.name}
</a> </a>
</li> </li>
))} ))}
</ul> </ul>
)} )}
/> />
)} )}
</div> </div>
); );
} }

View File

@ -23,12 +23,12 @@ export default function Page() {
const handleAcceptRF = (data) => { const handleAcceptRF = (data) => {
logger.debug('Mise à jour du RF avec les données:', data); logger.debug('Mise à jour du RF avec les données:', data);
const {status, sepa_file, fusionParam} = data const { status, sepa_file, fusionParam } = data;
const formData = new FormData(); const formData = new FormData();
formData.append('status', status); // Ajoute le statut formData.append('status', status); // Ajoute le statut
formData.append('sepa_file', sepa_file); // Ajoute le fichier SEPA formData.append('sepa_file', sepa_file); // Ajoute le fichier SEPA
formData.append('fusion', fusionParam); formData.append('fusion', fusionParam);
// Appeler l'API pour mettre à jour le RF // Appeler l'API pour mettre à jour le RF
sendSEPARegisterForm(studentId, formData, csrfToken) sendSEPARegisterForm(studentId, formData, csrfToken)
.then((response) => { .then((response) => {

View File

@ -2,7 +2,11 @@ import React, { useState, useRef } from 'react';
import { CloudUpload } from 'lucide-react'; import { CloudUpload } from 'lucide-react';
import logger from '@/utils/logger'; import logger from '@/utils/logger';
export default function FileUpload({ selectionMessage, onFileSelect, uploadedFileName }) { export default function FileUpload({
selectionMessage,
onFileSelect,
uploadedFileName,
}) {
const [localFileName, setLocalFileName] = useState(uploadedFileName || ''); const [localFileName, setLocalFileName] = useState(uploadedFileName || '');
const fileInputRef = useRef(null); // Utilisation de useRef pour cibler l'input const fileInputRef = useRef(null); // Utilisation de useRef pour cibler l'input
@ -34,7 +38,8 @@ export default function FileUpload({ selectionMessage, onFileSelect, uploadedFil
onDragOver={(e) => e.preventDefault()} onDragOver={(e) => e.preventDefault()}
onDrop={handleFileDrop} onDrop={handleFileDrop}
> >
<CloudUpload className="w-12 h-12 text-emerald-500 mb-4" /> {/* Icône de cloud */} <CloudUpload className="w-12 h-12 text-emerald-500 mb-4" />{' '}
{/* Icône de cloud */}
<input <input
type="file" type="file"
accept=".pdf" accept=".pdf"
@ -43,8 +48,12 @@ export default function FileUpload({ selectionMessage, onFileSelect, uploadedFil
ref={fileInputRef} // Attachement de la référence ref={fileInputRef} // Attachement de la référence
/> />
<label htmlFor="fileInput" className="text-center text-gray-500"> <label htmlFor="fileInput" className="text-center text-gray-500">
<p className="text-lg font-semibold text-gray-800">Déposez votre fichier ici</p> <p className="text-lg font-semibold text-gray-800">
<p className="text-sm text-gray-500 mt-2">ou cliquez pour sélectionner un fichier PDF</p> Déposez votre fichier ici
</p>
<p className="text-sm text-gray-500 mt-2">
ou cliquez pour sélectionner un fichier PDF
</p>
</label> </label>
</div> </div>
{localFileName && ( {localFileName && (
@ -57,4 +66,4 @@ export default function FileUpload({ selectionMessage, onFileSelect, uploadedFil
)} )}
</div> </div>
); );
} }

View File

@ -65,13 +65,13 @@ export default function InscriptionFormShared({
const [uploadedFiles, setUploadedFiles] = useState([]); const [uploadedFiles, setUploadedFiles] = useState([]);
const [schoolFileTemplates, setSchoolFileTemplates] = useState([]); const [schoolFileTemplates, setSchoolFileTemplates] = useState([]);
const [parentFileTemplates, setParentFileTemplates] = useState([]); const [parentFileTemplates, setParentFileTemplates] = useState([]);
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(5);
const [isSignatureComplete, setIsSignatureComplete] = useState(false);
const [isPage1Valid, setIsPage1Valid] = useState(false); const [isPage1Valid, setIsPage1Valid] = useState(false);
const [isPage2Valid, setIsPage2Valid] = useState(false); const [isPage2Valid, setIsPage2Valid] = useState(false);
const [isPage3Valid, setIsPage3Valid] = useState(false); const [isPage3Valid, setIsPage3Valid] = useState(false);
const [isPage4Valid, setIsPage4Valid] = useState(false); const [isPage4Valid, setIsPage4Valid] = useState(false);
const [isPage5Valid, setIsPage5Valid] = useState(false);
const [hasInteracted, setHasInteracted] = useState(false); const [hasInteracted, setHasInteracted] = useState(false);
@ -83,7 +83,7 @@ export default function InscriptionFormShared({
const firstUnsignedIndex = schoolFileTemplates.findIndex( const firstUnsignedIndex = schoolFileTemplates.findIndex(
(template) => template.file === null (template) => template.file === null
); );
// Mettre à jour l'index du template actuel // Mettre à jour l'index du template actuel
if (firstUnsignedIndex !== -1) { if (firstUnsignedIndex !== -1) {
setCurrentTemplateIndex(firstUnsignedIndex); setCurrentTemplateIndex(firstUnsignedIndex);
@ -95,8 +95,10 @@ export default function InscriptionFormShared({
useEffect(() => { useEffect(() => {
// Vérifier si tous les templates ont leur champ "file" différent de null // Vérifier si tous les templates ont leur champ "file" différent de null
const allSigned = schoolFileTemplates.every((template) => template.file !== null); const allSigned = schoolFileTemplates.every(
(template) => template.file !== null
);
// Mettre à jour isPage4Valid en fonction de cette condition // Mettre à jour isPage4Valid en fonction de cette condition
setIsPage4Valid(allSigned); setIsPage4Valid(allSigned);
@ -105,26 +107,34 @@ export default function InscriptionFormShared({
} }
}, [schoolFileTemplates]); }, [schoolFileTemplates]);
useEffect(() => {
// Vérifier si tous les parentFileTemplates ont leur champ "file" différent de null
const allUploaded = parentFileTemplates.every(
(template) => template.file !== null
);
// Mettre à jour isPage5Valid en fonction de cette condition
setIsPage5Valid(allUploaded);
}, [parentFileTemplates]);
const handleTemplateSigned = (index) => { const handleTemplateSigned = (index) => {
const template = schoolFileTemplates[index]; const template = schoolFileTemplates[index];
if (!template) { if (!template) {
logger.error('Template introuvable pour l\'index donné.'); logger.error("Template introuvable pour l'index donné.");
return; return;
} }
downloadTemplate(template.slug) downloadTemplate(template.slug)
.then((data) => fetch(data)) .then((data) => fetch(data))
.then((response) => response.blob()) .then((response) => response.blob())
.then((blob) => { .then((blob) => {
const file = new File( const file = new File([blob], `${template.name}.pdf`, {
[blob], type: blob.type,
`${template.name}.pdf`, });
{ type: blob.type }
);
const updateData = new FormData(); const updateData = new FormData();
updateData.append('file', file); updateData.append('file', file);
return editRegistrationSchoolFileTemplates( return editRegistrationSchoolFileTemplates(
template.id, template.id,
updateData, updateData,
@ -133,7 +143,7 @@ export default function InscriptionFormShared({
}) })
.then((data) => { .then((data) => {
logger.debug('Template mis à jour avec succès :', data); logger.debug('Template mis à jour avec succès :', data);
// Mettre à jour l'état local de schoolFileTemplates // Mettre à jour l'état local de schoolFileTemplates
setSchoolFileTemplates((prevTemplates) => setSchoolFileTemplates((prevTemplates) =>
prevTemplates.map((t, i) => prevTemplates.map((t, i) =>
@ -236,6 +246,15 @@ export default function InscriptionFormShared({
return updatedFiles; return updatedFiles;
}); });
// Mettre à jour parentFileTemplates
setParentFileTemplates((prevTemplates) =>
prevTemplates.map((template) =>
template.id === selectedFile.id
? { ...template, file: response.data.file }
: template
)
);
return response; // Retourner la réponse pour signaler le succès return response; // Retourner la réponse pour signaler le succès
}) })
.catch((error) => { .catch((error) => {
@ -265,6 +284,8 @@ export default function InscriptionFormShared({
.then((response) => { .then((response) => {
logger.debug('Fichier supprimé avec succès dans la base :', response); logger.debug('Fichier supprimé avec succès dans la base :', response);
setIsPage5Valid(false);
// Mettre à jour l'état local pour refléter la suppression // Mettre à jour l'état local pour refléter la suppression
setUploadedFiles((prev) => setUploadedFiles((prev) =>
prev.map((uploadedFile) => prev.map((uploadedFile) =>
@ -273,6 +294,13 @@ export default function InscriptionFormShared({
: uploadedFile : uploadedFile
) )
); );
// Mettre à jour l'état local pour refléter la suppression dans parentFileTemplates
setParentFileTemplates((prevTemplates) =>
prevTemplates.map((template) =>
template.id === templateId ? { ...template, file: null } : template
)
);
return response; return response;
}) })
.catch((error) => { .catch((error) => {
@ -311,10 +339,9 @@ export default function InscriptionFormShared({
const stepTitles = { const stepTitles = {
1: 'Elève', 1: 'Elève',
2: 'Responsables légaux', 2: 'Responsables légaux',
3: "Modalités de paiement", 3: 'Modalités de paiement',
4: "Formulaires à signer", 4: 'Formulaires à signer',
5: "Pièces à fournir", 5: 'Pièces à fournir',
6: "Validation"
}; };
const steps = [ const steps = [
@ -323,7 +350,6 @@ export default function InscriptionFormShared({
'Paiement', 'Paiement',
'Formulaires', 'Formulaires',
'Documents parent', 'Documents parent',
'Validation'
]; ];
const isStepValid = (stepNumber) => { const isStepValid = (stepNumber) => {
@ -334,6 +360,10 @@ export default function InscriptionFormShared({
return isPage2Valid; return isPage2Valid;
case 3: case 3:
return isPage3Valid; return isPage3Valid;
case 4:
return isPage4Valid;
case 5:
return isPage5Valid;
default: default:
return false; return false;
} }
@ -350,7 +380,10 @@ export default function InscriptionFormShared({
setStep={setCurrentPage} setStep={setCurrentPage}
isStepValid={isStepValid} isStepValid={isStepValid}
/> />
<div className="flex-1 overflow-y-auto mt-12 " style={{ maxHeight: 'calc(100vh - 400px)' }}> <div
className="flex-1 overflow-y-auto mt-12 "
style={{ maxHeight: 'calc(100vh - 400px)' }}
>
{/* Page 1 : Informations sur l'élève */} {/* Page 1 : Informations sur l'élève */}
{currentPage === 1 && ( {currentPage === 1 && (
<StudentInfoForm <StudentInfoForm
@ -393,78 +426,83 @@ export default function InscriptionFormShared({
{/* Pages suivantes : Section Fichiers d'inscription */} {/* Pages suivantes : Section Fichiers d'inscription */}
{currentPage === 4 && ( {currentPage === 4 && (
<div className="mt-8 mb-4 w-4/5 mx-auto flex gap-8"> <div className="mt-8 mb-4 w-4/5 mx-auto flex gap-8">
{/* Liste des états de signature */} {/* Liste des états de signature */}
<div className="w-1/4 bg-gray-50 p-4 rounded-lg shadow-sm border border-gray-200"> <div className="w-1/4 bg-gray-50 p-4 rounded-lg shadow-sm border border-gray-200">
<h3 className="text-lg font-semibold text-gray-800 mb-4">Documents</h3> <h3 className="text-lg font-semibold text-gray-800 mb-4">
<ul className="space-y-2"> Documents
{schoolFileTemplates.map((template, index) => ( </h3>
<li <ul className="space-y-2">
key={template.id} {schoolFileTemplates.map((template, index) => (
className={`flex items-center cursor-pointer ${ <li
index === currentTemplateIndex key={template.id}
? 'text-blue-600 font-bold' className={`flex items-center cursor-pointer ${
: template.file !== null index === currentTemplateIndex
? 'text-green-600' ? 'text-blue-600 font-bold'
: 'text-gray-600' : template.file !== null
}`} ? 'text-green-600'
onClick={() => setCurrentTemplateIndex(index)} // Mettre à jour l'index du template actuel : 'text-gray-600'
> }`}
<span className="mr-2"> onClick={() => setCurrentTemplateIndex(index)} // Mettre à jour l'index du template actuel
{template.file !== null ? ( >
<CheckCircle className="w-5 h-5 text-green-600" /> <span className="mr-2">
) : ( {template.file !== null ? (
<Loader2 className="w-5 h-5 text-gray-600" /> <CheckCircle className="w-5 h-5 text-green-600" />
)} ) : (
</span> <Loader2 className="w-5 h-5 text-gray-600" />
{template.name || 'Document sans nom'} )}
</li> </span>
))} {template.name || 'Document sans nom'}
</ul> </li>
))}
</ul>
</div>
{/* Affichage du fichier actuel */}
<div className="w-3/4">
{currentTemplateIndex < schoolFileTemplates.length && (
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
<h3 className="text-lg font-semibold text-gray-800 mb-4">
{schoolFileTemplates[currentTemplateIndex].name ||
'Document sans nom'}
</h3>
<p className="text-sm text-gray-500 mb-4">
{schoolFileTemplates[currentTemplateIndex].description ||
'Aucune description disponible pour ce document.'}
</p>
{schoolFileTemplates[currentTemplateIndex].file === null ? (
<DocusealForm
key={schoolFileTemplates[currentTemplateIndex].slug}
id="docusealForm"
src={`https://docuseal.com/s/${schoolFileTemplates[currentTemplateIndex].slug}`}
withDownloadButton={false}
withTitle={false}
onComplete={() =>
handleTemplateSigned(currentTemplateIndex)
}
/>
) : (
<iframe
src={`${BASE_URL}/${schoolFileTemplates[currentTemplateIndex].file}`}
title="Document Viewer"
className="w-full"
style={{
height: '75vh',
border: 'none',
}}
/>
)}
</div>
)}
{/* Message de fin */}
{currentTemplateIndex >= schoolFileTemplates.length && (
<div className="text-center text-green-600 font-semibold">
Tous les formulaires ont été signés avec succès !
</div>
)}
</div>
</div> </div>
{/* Affichage du fichier actuel */}
<div className="w-3/4">
{currentTemplateIndex < schoolFileTemplates.length && (
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
<h3 className="text-lg font-semibold text-gray-800 mb-4">
{schoolFileTemplates[currentTemplateIndex].name || 'Document sans nom'}
</h3>
<p className="text-sm text-gray-500 mb-4">
{schoolFileTemplates[currentTemplateIndex].description ||
'Aucune description disponible pour ce document.'}
</p>
{schoolFileTemplates[currentTemplateIndex].file === null ? (
<DocusealForm
key={schoolFileTemplates[currentTemplateIndex].slug}
id="docusealForm"
src={`https://docuseal.com/s/${schoolFileTemplates[currentTemplateIndex].slug}`}
withDownloadButton={false}
withTitle={false}
onComplete={() => handleTemplateSigned(currentTemplateIndex)}
/>
) : (
<iframe
src={`${BASE_URL}/${schoolFileTemplates[currentTemplateIndex].file}`}
title="Document Viewer"
className="w-full"
style={{
height: '75vh',
border: 'none',
}}
/>
)}
</div>
)}
{/* Message de fin */}
{currentTemplateIndex >= schoolFileTemplates.length && (
<div className="text-center text-green-600 font-semibold">
Tous les formulaires ont été signés avec succès !
</div>
)}
</div>
</div>
)} )}
{/* Dernière page : Section Fichiers parents */} {/* Dernière page : Section Fichiers parents */}
@ -478,47 +516,57 @@ export default function InscriptionFormShared({
)} )}
</div> </div>
{/* Boutons de contrôle */} {/* Boutons de contrôle */}
<div className="flex justify-center space-x-4 mt-12"> <div className="flex justify-center space-x-4 mt-12">
{currentPage > 1 && ( {currentPage > 1 && (
<Button <Button
text="Précédent" text="Précédent"
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
handlePreviousPage(); handlePreviousPage();
}} }}
primary primary
/> />
)} )}
{currentPage < steps.length && ( {currentPage < steps.length && (
<Button <Button
text="Suivant" text="Suivant"
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
handleNextPage(); handleNextPage();
}} }}
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${ className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
(currentPage === 1 && !isPage1Valid) || (currentPage === 1 && !isPage1Valid) ||
(currentPage === 2 && !isPage2Valid) || (currentPage === 2 && !isPage2Valid) ||
(currentPage === 3 && !isPage3Valid) || (currentPage === 3 && !isPage3Valid) ||
(currentPage === 4 && !isPage4Valid) (currentPage === 4 && !isPage4Valid)
? 'bg-gray-300 text-gray-700 cursor-not-allowed' ? 'bg-gray-300 text-gray-700 cursor-not-allowed'
: 'bg-emerald-500 text-white hover:bg-emerald-600' : 'bg-emerald-500 text-white hover:bg-emerald-600'
}`} }`}
disabled={ disabled={
(currentPage === 1 && !isPage1Valid) || (currentPage === 1 && !isPage1Valid) ||
(currentPage === 2 && !isPage2Valid) || (currentPage === 2 && !isPage2Valid) ||
(currentPage === 3 && !isPage3Valid) || (currentPage === 3 && !isPage3Valid) ||
(currentPage === 4 && !isPage4Valid) (currentPage === 4 && !isPage4Valid)
} }
primary primary
name="Next" name="Next"
/> />
)} )}
{currentPage === steps.length && ( {currentPage === steps.length && (
<Button onClick={handleSubmit} text="Valider" primary /> <Button
)} onClick={handleSubmit}
</div> text="Valider"
primary
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
currentPage === 5 && !isPage5Valid
? 'bg-gray-300 text-gray-700 cursor-not-allowed'
: 'bg-emerald-500 text-white hover:bg-emerald-600'
}`}
disabled={currentPage === 5 && !isPage5Valid}
/>
)}
</div>
</div> </div>
); );
} }

View File

@ -7,12 +7,13 @@ export default function PaymentMethodSelector({
registrationPaymentModes, registrationPaymentModes,
tuitionPaymentModes, tuitionPaymentModes,
errors, errors,
setIsPageValid setIsPageValid,
}) { }) {
useEffect(() => { useEffect(() => {
const isValid = !Object.keys(formData).some((field) => getLocalError(field) !== ''); const isValid = !Object.keys(formData).some(
console.log(isValid) (field) => getLocalError(field) !== ''
);
console.log(isValid);
setIsPageValid(isValid); setIsPageValid(isValid);
}, [formData, setIsPageValid]); }, [formData, setIsPageValid]);
@ -30,8 +31,12 @@ export default function PaymentMethodSelector({
const getLocalError = (field) => { const getLocalError = (field) => {
if ( if (
// Student Form // Student Form
( field === 'registration_payment' && (!formData.registration_payment || String(formData.registration_payment).trim() === '') ) || (field === 'registration_payment' &&
( field === 'tuition_payment' && (!formData.tuition_payment || String(formData.tuition_payment).trim() === '') ) (!formData.registration_payment ||
String(formData.registration_payment).trim() === '')) ||
(field === 'tuition_payment' &&
(!formData.tuition_payment ||
String(formData.tuition_payment).trim() === ''))
) { ) {
return 'Champs requis'; return 'Champs requis';
} }
@ -47,13 +52,14 @@ export default function PaymentMethodSelector({
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200"> <div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
{/* Titre */} {/* Titre */}
<h2 className="text-2xl font-semibold mb-6 text-gray-800 border-b pb-2"> <h2 className="text-2xl font-semibold mb-6 text-gray-800 border-b pb-2">
Frais d'inscription Frais d'inscription
</h2> </h2>
{/* Section d'information */} {/* Section d'information */}
<div className="mb-6 bg-gray-50 p-4 rounded-lg border border-gray-100"> <div className="mb-6 bg-gray-50 p-4 rounded-lg border border-gray-100">
<p className="text-gray-700 text-sm mb-2"> <p className="text-gray-700 text-sm mb-2">
<strong className="text-gray-900">Montant :</strong> {formData.totalRegistrationFees} <strong className="text-gray-900">Montant :</strong>{' '}
{formData.totalRegistrationFees}
</p> </p>
</div> </div>
@ -62,7 +68,7 @@ export default function PaymentMethodSelector({
label="Mode de Paiement" label="Mode de Paiement"
placeHolder="Sélectionner un mode de paiement" placeHolder="Sélectionner un mode de paiement"
selected={formData.registration_payment} selected={formData.registration_payment}
callback={(e) => onChange("registration_payment", e.target.value)} callback={(e) => onChange('registration_payment', e.target.value)}
choices={registrationPaymentModes.map((mode) => ({ choices={registrationPaymentModes.map((mode) => ({
value: mode.mode, value: mode.mode,
label: label:
@ -70,20 +76,24 @@ export default function PaymentMethodSelector({
?.name || 'Mode inconnu', ?.name || 'Mode inconnu',
}))} }))}
required required
errorMsg={getError("registration_payment") || getLocalError("registration_payment")} errorMsg={
getError('registration_payment') ||
getLocalError('registration_payment')
}
/> />
</div> </div>
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200 mt-12"> <div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200 mt-12">
{/* Titre */} {/* Titre */}
<h2 className="text-2xl font-semibold mb-6 text-gray-800 border-b pb-2"> <h2 className="text-2xl font-semibold mb-6 text-gray-800 border-b pb-2">
Frais de scolarité Frais de scolarité
</h2> </h2>
{/* Section d'information */} {/* Section d'information */}
<div className="mb-6 bg-gray-50 p-4 rounded-lg border border-gray-100"> <div className="mb-6 bg-gray-50 p-4 rounded-lg border border-gray-100">
<p className="text-gray-700 text-sm mb-2"> <p className="text-gray-700 text-sm mb-2">
<strong className="text-gray-900">Montant :</strong> {formData.totalTuitionFees} <strong className="text-gray-900">Montant :</strong>{' '}
{formData.totalTuitionFees}
</p> </p>
</div> </div>
@ -92,7 +102,7 @@ export default function PaymentMethodSelector({
label="Mode de Paiement" label="Mode de Paiement"
placeHolder="Sélectionner un mode de paiement" placeHolder="Sélectionner un mode de paiement"
selected={formData.tuition_payment} selected={formData.tuition_payment}
callback={(e) => onChange("tuition_payment", e.target.value)} callback={(e) => onChange('tuition_payment', e.target.value)}
choices={tuitionPaymentModes.map((mode) => ({ choices={tuitionPaymentModes.map((mode) => ({
value: mode.mode, value: mode.mode,
label: label:
@ -100,7 +110,9 @@ export default function PaymentMethodSelector({
?.name || 'Mode inconnu', ?.name || 'Mode inconnu',
}))} }))}
required required
errorMsg={getError("tuition_payment") || getLocalError("tuition_payment")} errorMsg={
getError('tuition_payment') || getLocalError('tuition_payment')
}
/> />
</div> </div>
</> </>

View File

@ -9,14 +9,18 @@ export default function ResponsableInputFields({
guardians, guardians,
setGuardians, setGuardians,
errors, errors,
setIsPageValid setIsPageValid,
}) { }) {
const t = useTranslations('ResponsableInputFields'); const t = useTranslations('ResponsableInputFields');
useEffect(() => { useEffect(() => {
const isValid = guardians.length > 0 && guardians.every((guardian, index) => { const isValid =
return !Object.keys(guardian).some((field) => getLocalError(index, field) !== ''); guardians.length > 0 &&
}); guardians.every((guardian, index) => {
return !Object.keys(guardian).some(
(field) => getLocalError(index, field) !== ''
);
});
setIsPageValid(isValid); setIsPageValid(isValid);
}, [guardians, setIsPageValid]); }, [guardians, setIsPageValid]);
@ -28,18 +32,29 @@ export default function ResponsableInputFields({
const getLocalError = (index, field) => { const getLocalError = (index, field) => {
if ( if (
// Student Form // Student Form
( field === 'last_name' && (!guardians[index].last_name || guardians[index].last_name.trim() === '') ) || (field === 'last_name' &&
( field === 'first_name' && (!guardians[index].first_name || guardians[index].first_name.trim() === '') ) || (!guardians[index].last_name ||
( field === 'email' && (!guardians[index].associated_profile_email || guardians[index].associated_profile_email.trim() === '') ) || guardians[index].last_name.trim() === '')) ||
( field === 'birth_date' && (!guardians[index].birth_date || guardians[index].birth_date.trim() === '') ) || (field === 'first_name' &&
( field === 'profession' && (!guardians[index].profession || guardians[index].profession.trim() === '') ) || (!guardians[index].first_name ||
( field === 'address' && (!guardians[index].address || guardians[index].address.trim() === '') ) guardians[index].first_name.trim() === '')) ||
(field === 'email' &&
(!guardians[index].associated_profile_email ||
guardians[index].associated_profile_email.trim() === '')) ||
(field === 'birth_date' &&
(!guardians[index].birth_date ||
guardians[index].birth_date.trim() === '')) ||
(field === 'profession' &&
(!guardians[index].profession ||
guardians[index].profession.trim() === '')) ||
(field === 'address' &&
(!guardians[index].address || guardians[index].address.trim() === ''))
) { ) {
return 'Champs requis'; return 'Champs requis';
} }
return ''; return '';
}; };
const onGuardiansChange = (id, field, value) => { const onGuardiansChange = (id, field, value) => {
const updatedGuardians = guardians.map((guardian) => const updatedGuardians = guardians.map((guardian) =>
guardian.id === id ? { ...guardian, [field]: value } : guardian guardian.id === id ? { ...guardian, [field]: value } : guardian
@ -50,7 +65,7 @@ export default function ResponsableInputFields({
const addGuardian = () => { const addGuardian = () => {
setGuardians([...guardians, { id: Date.now(), name: '', email: '' }]); setGuardians([...guardians, { id: Date.now(), name: '', email: '' }]);
}; };
const deleteGuardian = (index) => { const deleteGuardian = (index) => {
const updatedGuardians = guardians.filter((_, i) => i !== index); const updatedGuardians = guardians.filter((_, i) => i !== index);
setGuardians(updatedGuardians); setGuardians(updatedGuardians);
@ -88,7 +103,10 @@ export default function ResponsableInputFields({
onChange={(event) => { onChange={(event) => {
onGuardiansChange(item.id, 'last_name', event.target.value); onGuardiansChange(item.id, 'last_name', event.target.value);
}} }}
errorMsg={getError(index, 'last_name') || getLocalError(index, 'last_name')} errorMsg={
getError(index, 'last_name') ||
getLocalError(index, 'last_name')
}
required required
/> />
<InputText <InputText
@ -99,7 +117,10 @@ export default function ResponsableInputFields({
onChange={(event) => { onChange={(event) => {
onGuardiansChange(item.id, 'first_name', event.target.value); onGuardiansChange(item.id, 'first_name', event.target.value);
}} }}
errorMsg={getError(index, 'first_name') || getLocalError(index, 'first_name')} errorMsg={
getError(index, 'first_name') ||
getLocalError(index, 'first_name')
}
required required
/> />
</div> </div>
@ -118,11 +139,13 @@ export default function ResponsableInputFields({
); );
}} }}
required required
errorMsg={getError(index, 'email') || getLocalError(index, 'email')} errorMsg={
getError(index, 'email') || getLocalError(index, 'email')
}
/> />
<InputPhone <InputPhone
name="telephoneResponsable" name="telephoneResponsable"
label='phone' label="phone"
value={item.phone} value={item.phone}
onChange={(event) => { onChange={(event) => {
onGuardiansChange(item.id, 'phone', event); onGuardiansChange(item.id, 'phone', event);
@ -142,7 +165,10 @@ export default function ResponsableInputFields({
onGuardiansChange(item.id, 'birth_date', event.target.value); onGuardiansChange(item.id, 'birth_date', event.target.value);
}} }}
required required
errorMsg={getError(index, 'birth_date') || getLocalError(index, 'birth_date')} errorMsg={
getError(index, 'birth_date') ||
getLocalError(index, 'birth_date')
}
/> />
<InputText <InputText
name="professionResponsable" name="professionResponsable"
@ -153,7 +179,10 @@ export default function ResponsableInputFields({
onGuardiansChange(item.id, 'profession', event.target.value); onGuardiansChange(item.id, 'profession', event.target.value);
}} }}
required required
errorMsg={getError(index, 'profession') || getLocalError(index, 'profession')} errorMsg={
getError(index, 'profession') ||
getLocalError(index, 'profession')
}
/> />
</div> </div>
@ -167,7 +196,9 @@ export default function ResponsableInputFields({
onGuardiansChange(item.id, 'address', event.target.value); onGuardiansChange(item.id, 'address', event.target.value);
}} }}
required required
errorMsg={getError(index, 'address') || getLocalError(index, 'address')} errorMsg={
getError(index, 'address') || getLocalError(index, 'address')
}
/> />
</div> </div>
</div> </div>

View File

@ -2,9 +2,7 @@ import React, { useState, useEffect } from 'react';
import InputText from '@/components/InputText'; import InputText from '@/components/InputText';
import SelectChoice from '@/components/SelectChoice'; import SelectChoice from '@/components/SelectChoice';
import Loader from '@/components/Loader'; import Loader from '@/components/Loader';
import { import { fetchRegisterForm } from '@/app/actions/subscriptionAction';
fetchRegisterForm
} from '@/app/actions/subscriptionAction';
import logger from '@/utils/logger'; import logger from '@/utils/logger';
import SectionHeader from '@/components/SectionHeader'; import SectionHeader from '@/components/SectionHeader';
import { User } from 'lucide-react'; import { User } from 'lucide-react';
@ -29,9 +27,8 @@ export default function StudentInfoForm({
errors, errors,
setIsPageValid, setIsPageValid,
hasInteracted, hasInteracted,
setHasInteracted setHasInteracted,
}) { }) {
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
useEffect(() => { useEffect(() => {
@ -59,14 +56,15 @@ export default function StudentInfoForm({
}); });
setIsLoading(false); setIsLoading(false);
} } else {
else {
setIsLoading(false); setIsLoading(false);
} }
}, [studentId, hasInteracted]); }, [studentId, hasInteracted]);
useEffect(() => { useEffect(() => {
const isValid = !Object.keys(formData).some((field) => getLocalError(field) !== ''); const isValid = !Object.keys(formData).some(
(field) => getLocalError(field) !== ''
);
setIsPageValid(isValid); setIsPageValid(isValid);
}, [formData, hasInteracted, setIsPageValid]); }, [formData, hasInteracted, setIsPageValid]);
@ -77,15 +75,26 @@ export default function StudentInfoForm({
const getLocalError = (field) => { const getLocalError = (field) => {
if ( if (
// Student Form // Student Form
( field === 'last_name' && (!formData.last_name || formData.last_name.trim() === '') ) || (field === 'last_name' &&
( field === 'first_name' && (!formData.first_name || formData.first_name.trim() === '') ) || (!formData.last_name || formData.last_name.trim() === '')) ||
( field === 'nationality' && (!formData.nationality || formData.nationality.trim() === '') ) || (field === 'first_name' &&
( field === 'birth_date' && (!formData.birth_date || formData.birth_date.trim() === '') ) || (!formData.first_name || formData.first_name.trim() === '')) ||
( field === 'birth_place' && (!formData.birth_place || formData.birth_place.trim() === '') ) || (field === 'nationality' &&
( field === 'birth_postal_code' && (!formData.birth_postal_code || String(formData.birth_postal_code).trim() === '') ) || (!formData.nationality || formData.nationality.trim() === '')) ||
( field === 'address' && (!formData.address || formData.address.trim() === '') ) || (field === 'birth_date' &&
( field === 'attending_physician' && (!formData.attending_physician || formData.attending_physician.trim() === '') ) || (!formData.birth_date || formData.birth_date.trim() === '')) ||
( field === 'level' && (!formData.level || String(formData.level).trim() === '') ) (field === 'birth_place' &&
(!formData.birth_place || formData.birth_place.trim() === '')) ||
(field === 'birth_postal_code' &&
(!formData.birth_postal_code ||
String(formData.birth_postal_code).trim() === '')) ||
(field === 'address' &&
(!formData.address || formData.address.trim() === '')) ||
(field === 'attending_physician' &&
(!formData.attending_physician ||
formData.attending_physician.trim() === '')) ||
(field === 'level' &&
(!formData.level || String(formData.level).trim() === ''))
) { ) {
return 'Champs requis'; return 'Champs requis';
} }
@ -158,11 +167,12 @@ export default function StudentInfoForm({
name="birth_postal_code" name="birth_postal_code"
label="Code Postal de Naissance" label="Code Postal de Naissance"
value={formData.birth_postal_code} value={formData.birth_postal_code}
onChange={(e) => onChange={(e) => onChange('birth_postal_code', e.target.value)}
onChange('birth_postal_code', e.target.value)
}
required required
errorMsg={getError('birth_postal_code') || getLocalError('birth_postal_code')} errorMsg={
getError('birth_postal_code') ||
getLocalError('birth_postal_code')
}
/> />
<div className="md:col-span-2"> <div className="md:col-span-2">
<InputText <InputText
@ -178,11 +188,12 @@ export default function StudentInfoForm({
name="attending_physician" name="attending_physician"
label="Médecin Traitant" label="Médecin Traitant"
value={formData.attending_physician} value={formData.attending_physician}
onChange={(e) => onChange={(e) => onChange('attending_physician', e.target.value)}
onChange('attending_physician', e.target.value)
}
required required
errorMsg={getError('attending_physician') || getLocalError('attending_physician')} errorMsg={
getError('attending_physician') ||
getLocalError('attending_physician')
}
/> />
<SelectChoice <SelectChoice
name="level" name="level"

View File

@ -4,7 +4,10 @@ import Button from '@/components/Button';
import ToggleSwitch from '@/components/ToggleSwitch'; // Import du composant ToggleSwitch import ToggleSwitch from '@/components/ToggleSwitch'; // Import du composant ToggleSwitch
import { BASE_URL } from '@/utils/Url'; import { BASE_URL } from '@/utils/Url';
import { generateToken } from '@/app/actions/registerFileGroupAction'; import { generateToken } from '@/app/actions/registerFileGroupAction';
import { fetchSchoolFileTemplatesFromRegistrationFiles, fetchParentFileTemplatesFromRegistrationFiles } from '@/app/actions/subscriptionAction'; import {
fetchSchoolFileTemplatesFromRegistrationFiles,
fetchParentFileTemplatesFromRegistrationFiles,
} from '@/app/actions/subscriptionAction';
import logger from '@/utils/logger'; import logger from '@/utils/logger';
import { GraduationCap } from 'lucide-react'; import { GraduationCap } from 'lucide-react';
import FileUpload from '@/components/FileUpload'; import FileUpload from '@/components/FileUpload';
@ -47,7 +50,12 @@ export default function ValidateSubscription({
setSchoolFileTemplates(data); setSchoolFileTemplates(data);
logger.debug('Fichiers schoolFileTemplates récupérés:', data); logger.debug('Fichiers schoolFileTemplates récupérés:', data);
}) })
.catch((error) => logger.error('Erreur lors de la récupération des schoolFileTemplates:', error)); .catch((error) =>
logger.error(
'Erreur lors de la récupération des schoolFileTemplates:',
error
)
);
// Récupérer les fichiers parentFileTemplates pour l'étudiant // Récupérer les fichiers parentFileTemplates pour l'étudiant
fetchParentFileTemplatesFromRegistrationFiles(studentId) fetchParentFileTemplatesFromRegistrationFiles(studentId)
@ -55,7 +63,12 @@ export default function ValidateSubscription({
setParentFileTemplates(data); setParentFileTemplates(data);
logger.debug('Fichiers parentFileTemplates récupérés:', data); logger.debug('Fichiers parentFileTemplates récupérés:', data);
}) })
.catch((error) => logger.error('Erreur lors de la récupération des parentFileTemplates:', error)); .catch((error) =>
logger.error(
'Erreur lors de la récupération des parentFileTemplates:',
error
)
);
}, [studentId]); }, [studentId]);
const handleAccept = () => { const handleAccept = () => {
@ -63,16 +76,16 @@ export default function ValidateSubscription({
logger.error('Aucun fichier sélectionné pour le champ SEPA.'); logger.error('Aucun fichier sélectionné pour le champ SEPA.');
return; return;
} }
// Ajouter le paramètre fusion dans l'URL // Ajouter le paramètre fusion dans l'URL
const fusionParam = mergeDocuments ? 'true' : 'false'; const fusionParam = mergeDocuments ? 'true' : 'false';
const data = { const data = {
status: 7, status: 7,
sepa_file: selectedFile, // Utilise le fichier sélectionné depuis l'état sepa_file: selectedFile, // Utilise le fichier sélectionné depuis l'état
fusionParam: fusionParam fusionParam: fusionParam,
}; };
// Appeler la fonction passée par le parent pour mettre à jour le RF // Appeler la fonction passée par le parent pour mettre à jour le RF
onAccept(data); onAccept(data);
}; };
@ -85,7 +98,11 @@ export default function ValidateSubscription({
const isValidateButtonDisabled = isSepa && !uploadedFileName; const isValidateButtonDisabled = isSepa && !uploadedFileName;
const goToNextPage = () => { const goToNextPage = () => {
const totalPages = 1 + schoolFileTemplates.length + parentFileTemplates.length + (isSepa ? 1 : 0); const totalPages =
1 +
schoolFileTemplates.length +
parentFileTemplates.length +
(isSepa ? 1 : 0);
if (currentPage < totalPages) { if (currentPage < totalPages) {
setCurrentPage(currentPage + 1); setCurrentPage(currentPage + 1);
} }
@ -97,7 +114,11 @@ export default function ValidateSubscription({
} }
}; };
const totalPages = 1 + schoolFileTemplates.length + parentFileTemplates.length + (isSepa ? 1 : 0); const totalPages =
1 +
schoolFileTemplates.length +
parentFileTemplates.length +
(isSepa ? 1 : 0);
const renderContent = () => { const renderContent = () => {
if (currentPage === 1) { if (currentPage === 1) {
@ -114,7 +135,10 @@ export default function ValidateSubscription({
}} }}
/> />
); );
} else if (currentPage > 1 && currentPage <= 1 + schoolFileTemplates.length) { } else if (
currentPage > 1 &&
currentPage <= 1 + schoolFileTemplates.length
) {
// Pages des schoolFileTemplates // Pages des schoolFileTemplates
const index = currentPage - 2; // Décalage pour correspondre à l'index du tableau const index = currentPage - 2; // Décalage pour correspondre à l'index du tableau
return ( return (
@ -129,7 +153,10 @@ export default function ValidateSubscription({
}} }}
/> />
); );
} else if (currentPage > 1 + schoolFileTemplates.length && currentPage <= 1 + schoolFileTemplates.length + parentFileTemplates.length) { } else if (
currentPage > 1 + schoolFileTemplates.length &&
currentPage <= 1 + schoolFileTemplates.length + parentFileTemplates.length
) {
// Pages des parentFileTemplates // Pages des parentFileTemplates
const index = currentPage - 2 - schoolFileTemplates.length; // Décalage pour correspondre à l'index du tableau const index = currentPage - 2 - schoolFileTemplates.length; // Décalage pour correspondre à l'index du tableau
return ( return (
@ -175,7 +202,9 @@ export default function ValidateSubscription({
{/* Option de fusion des documents (affichée uniquement sur la dernière page) */} {/* Option de fusion des documents (affichée uniquement sur la dernière page) */}
{currentPage === totalPages && ( {currentPage === totalPages && (
<div className="flex items-center justify-between mt-6"> <div className="flex items-center justify-between mt-6">
<span className="text-gray-700">Fusionner les documents en un seul fichier PDF</span> <span className="text-gray-700">
Fusionner les documents en un seul fichier PDF
</span>
<ToggleSwitch <ToggleSwitch
label="Fusionner" label="Fusionner"
checked={mergeDocuments} checked={mergeDocuments}

View File

@ -1,24 +1,27 @@
import React from 'react'; import React from 'react';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
const SectionHeader = ({ const SectionHeader = ({
icon: Icon, icon: Icon,
discountStyle = false, discountStyle = false,
title, title,
description, description,
button = false, button = false,
buttonOpeningModal = false, buttonOpeningModal = false,
onClick = null onClick = null,
}) => { }) => {
return ( return (
<div className="flex items-center justify-between mb-6"> <div className="flex items-center justify-between mb-6">
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<div className={`${discountStyle ? "bg-yellow-100" : "bg-emerald-100"} p-3 rounded-full shadow-md`}> <div
<Icon className={`${discountStyle ? 'bg-yellow-100' : 'bg-emerald-100'} p-3 rounded-full shadow-md`}
className={discountStyle ? >
"w-8 h-8 text-yellow-600" : <Icon
"w-8 h-8 text-emerald-600" className={
} discountStyle
? 'w-8 h-8 text-yellow-600'
: 'w-8 h-8 text-emerald-600'
}
/> />
</div> </div>
<div> <div>
@ -29,9 +32,10 @@ const SectionHeader = ({
{button && onClick && ( {button && onClick && (
<button <button
onClick={onClick} onClick={onClick}
className={buttonOpeningModal ? className={
"flex items-center bg-emerald-200 text-emerald-700 p-2 rounded-full shadow-sm hover:bg-emerald-300" : buttonOpeningModal
"text-emerald-500 hover:bg-emerald-200 rounded-full p-2" ? 'flex items-center bg-emerald-200 text-emerald-700 p-2 rounded-full shadow-sm hover:bg-emerald-300'
: 'text-emerald-500 hover:bg-emerald-200 rounded-full p-2'
} }
> >
<Plus className="w-6 h-6" /> <Plus className="w-6 h-6" />
@ -41,4 +45,4 @@ const SectionHeader = ({
); );
}; };
export default SectionHeader; export default SectionHeader;

View File

@ -9,7 +9,13 @@ import { createRegistrationParentFileTemplate } from '@/app/actions/registerFile
import { useCsrfToken } from '@/context/CsrfContext'; import { useCsrfToken } from '@/context/CsrfContext';
import SectionHeader from '@/components/SectionHeader'; import SectionHeader from '@/components/SectionHeader';
export default function ParentFilesSection({ parentFiles, groups, handleCreate, handleEdit, handleDelete }) { export default function ParentFilesSection({
parentFiles,
groups,
handleCreate,
handleEdit,
handleDelete,
}) {
const [editingDocumentId, setEditingDocumentId] = useState(null); const [editingDocumentId, setEditingDocumentId] = useState(null);
const [formData, setFormData] = useState(null); const [formData, setFormData] = useState(null);
const [selectedGroups, setSelectedGroups] = useState([]); // Gestion des groupes sélectionnés const [selectedGroups, setSelectedGroups] = useState([]); // Gestion des groupes sélectionnés
@ -17,9 +23,9 @@ export default function ParentFilesSection({ parentFiles, groups, handleCreate,
const [guardianDetails, setGuardianDetails] = useState([]); const [guardianDetails, setGuardianDetails] = useState([]);
const [popupVisible, setPopupVisible] = useState(false); const [popupVisible, setPopupVisible] = useState(false);
const [popupMessage, setPopupMessage] = useState(""); const [popupMessage, setPopupMessage] = useState('');
const [removePopupVisible, setRemovePopupVisible] = useState(false); const [removePopupVisible, setRemovePopupVisible] = useState(false);
const [removePopupMessage, setRemovePopupMessage] = useState(""); const [removePopupMessage, setRemovePopupMessage] = useState('');
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {}); const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
const csrfToken = useCsrfToken(); const csrfToken = useCsrfToken();
@ -60,15 +66,18 @@ export default function ParentFilesSection({ parentFiles, groups, handleCreate,
// Création des templates // Création des templates
const data = { const data = {
master: createdDocument?.id, master: createdDocument?.id,
registration_form: guardian.registration_form registration_form: guardian.registration_form,
}; };
console.log(guardian) console.log(guardian);
createRegistrationParentFileTemplate(data, csrfToken) createRegistrationParentFileTemplate(data, csrfToken)
.then(response => { .then((response) => {
logger.debug('Template enregistré avec succès:', response); logger.debug('Template enregistré avec succès:', response);
}) })
.catch(error => { .catch((error) => {
logger.error('Erreur lors de l\'enregistrement du template:', error); logger.error(
"Erreur lors de l'enregistrement du template:",
error
);
}); });
}); });
}); });
@ -101,26 +110,28 @@ export default function ParentFilesSection({ parentFiles, groups, handleCreate,
const handleGroupChange = (selected) => { const handleGroupChange = (selected) => {
setSelectedGroups(selected); setSelectedGroups(selected);
console.log('selected : ', selected) console.log('selected : ', selected);
// Extraire les guardians associés aux register_forms des groupes sélectionnés // Extraire les guardians associés aux register_forms des groupes sélectionnés
const details = selected.flatMap(group => const details = selected.flatMap((group) =>
group.registration_forms.flatMap(form => group.registration_forms.flatMap((form) =>
form.guardians.map(guardian => ({ form.guardians.map((guardian) => ({
email: guardian.associated_profile_email, email: guardian.associated_profile_email,
last_name: form.last_name, // Extraire depuis form last_name: form.last_name, // Extraire depuis form
first_name: form.first_name, // Extraire depuis form first_name: form.first_name, // Extraire depuis form
registration_form: form.student_id // Utiliser student_id comme ID du register_form registration_form: form.student_id, // Utiliser student_id comme ID du register_form
})) }))
) )
); );
console.log("Guardians associés : ", details); console.log('Guardians associés : ', details);
setGuardianDetails(details); // Mettre à jour la variable d'état avec les détails des guardians setGuardianDetails(details); // Mettre à jour la variable d'état avec les détails des guardians
}; };
const renderRequiredDocumentCell = (document, column) => { const renderRequiredDocumentCell = (document, column) => {
const isEditing = editingDocumentId === document.id || (editingDocumentId === 'new' && !document.id); const isEditing =
editingDocumentId === document.id ||
(editingDocumentId === 'new' && !document.id);
if (isEditing) { if (isEditing) {
switch (column) { switch (column) {
@ -129,7 +140,9 @@ export default function ParentFilesSection({ parentFiles, groups, handleCreate,
<InputText <InputText
name="name" name="name"
value={formData.name} value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })} onChange={(e) =>
setFormData({ ...formData, name: e.target.value })
}
placeholder="Nom de la pièce" placeholder="Nom de la pièce"
className="w-full" className="w-full"
/> />
@ -139,12 +152,14 @@ export default function ParentFilesSection({ parentFiles, groups, handleCreate,
<InputText <InputText
name="description" name="description"
value={formData.description} value={formData.description}
onChange={(e) => setFormData({ ...formData, description: e.target.value })} onChange={(e) =>
setFormData({ ...formData, description: e.target.value })
}
placeholder="Description" placeholder="Description"
className="w-full" className="w-full"
/> />
); );
case 'Dossiers d\'inscription': case "Dossiers d'inscription":
return ( return (
<MultiSelect <MultiSelect
name="groups" name="groups"
@ -183,11 +198,15 @@ export default function ParentFilesSection({ parentFiles, groups, handleCreate,
return <span>{document.name}</span>; return <span>{document.name}</span>;
case 'Description': case 'Description':
return <span>{document.description}</span>; return <span>{document.description}</span>;
case 'Dossiers d\'inscription': case "Dossiers d'inscription":
return ( return (
<span> <span>
{document.groups {document.groups
.map((groupId) => groups.find((group) => group.id === groupId)?.name || 'Dossiers d\'inscription inconnu') .map(
(groupId) =>
groups.find((group) => group.id === groupId)?.name ||
"Dossiers d'inscription inconnu"
)
.join(', ')} .join(', ')}
</span> </span>
); );
@ -211,13 +230,20 @@ export default function ParentFilesSection({ parentFiles, groups, handleCreate,
setRemovePopupOnConfirm(() => () => { setRemovePopupOnConfirm(() => () => {
handleRemoveDocument(document.id) handleRemoveDocument(document.id)
.then(() => { .then(() => {
setPopupMessage(`Le document "${document.name}" a été correctement supprimé.`); setPopupMessage(
`Le document "${document.name}" a été correctement supprimé.`
);
setPopupVisible(true); setPopupVisible(true);
setRemovePopupVisible(false); setRemovePopupVisible(false);
}) })
.catch((error) => { .catch((error) => {
logger.error('Erreur lors de la suppression du document:', error); logger.error(
setPopupMessage(`Erreur lors de la suppression du document "${document.name}".`); 'Erreur lors de la suppression du document:',
error
);
setPopupMessage(
`Erreur lors de la suppression du document "${document.name}".`
);
setPopupVisible(true); setPopupVisible(true);
setRemovePopupVisible(false); setRemovePopupVisible(false);
}); });
@ -236,10 +262,23 @@ export default function ParentFilesSection({ parentFiles, groups, handleCreate,
}; };
const columnsRequiredDocuments = [ const columnsRequiredDocuments = [
{ name: 'Nom de la pièce', transform: (row) => renderRequiredDocumentCell(row, 'Nom de la pièce') }, {
{ name: 'Description', transform: (row) => renderRequiredDocumentCell(row, 'Description') }, name: 'Nom de la pièce',
{ name: 'Dossiers d\'inscription', transform: (row) => renderRequiredDocumentCell(row, 'Dossiers d\'inscription') }, transform: (row) => renderRequiredDocumentCell(row, 'Nom de la pièce'),
{ name: 'Actions', transform: (row) => renderRequiredDocumentCell(row, 'Actions') }, },
{
name: 'Description',
transform: (row) => renderRequiredDocumentCell(row, 'Description'),
},
{
name: "Dossiers d'inscription",
transform: (row) =>
renderRequiredDocumentCell(row, "Dossiers d'inscription"),
},
{
name: 'Actions',
transform: (row) => renderRequiredDocumentCell(row, 'Actions'),
},
]; ];
return ( return (
@ -252,7 +291,9 @@ export default function ParentFilesSection({ parentFiles, groups, handleCreate,
onClick={handleAddEmptyRequiredDocument} onClick={handleAddEmptyRequiredDocument}
/> />
<Table <Table
data={editingDocumentId === 'new' ? [formData, ...parentFiles] : parentFiles} data={
editingDocumentId === 'new' ? [formData, ...parentFiles] : parentFiles
}
columns={columnsRequiredDocuments} columns={columnsRequiredDocuments}
/> />
<Popup <Popup
@ -270,4 +311,4 @@ export default function ParentFilesSection({ parentFiles, groups, handleCreate,
/> />
</div> </div>
); );
} }