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,
} from '@/app/actions/schoolAction';
import {
fetchProfiles,
} from '@/app/actions/authAction';
import { fetchProfiles } from '@/app/actions/authAction';
import {
BASE_URL,
@ -145,7 +143,7 @@ export default function Page({ params: { locale } }) {
const files = [];
if (row.registration_file) {
files.push({
name: 'Fichier d\'inscription',
name: "Fichier d'inscription",
url: `${BASE_URL}${row.registration_file}`,
});
}
@ -585,7 +583,7 @@ export default function Page({ params: { locale } }) {
})
.catch((error) => {
logger.error(
'Erreur lors de l\'enregistrement du template:',
"Erreur lors de l'enregistrement du template:",
error
);
});
@ -607,14 +605,11 @@ export default function Page({ params: { locale } }) {
csrfToken
)
.then((response) => {
logger.debug(
'Parent template enregistré avec succès:',
response
);
logger.debug('Parent template enregistré avec succès:', response);
})
.catch((error) => {
logger.error(
'Erreur lors de l\'enregistrement du parent template:',
"Erreur lors de l'enregistrement du parent template:",
error
);
});

View File

@ -23,7 +23,7 @@ export default function Page() {
const handleAcceptRF = (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();
formData.append('status', status); // Ajoute le statut
formData.append('sepa_file', sepa_file); // Ajoute le fichier SEPA

View File

@ -2,7 +2,11 @@ import React, { useState, useRef } from 'react';
import { CloudUpload } from 'lucide-react';
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 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()}
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
type="file"
accept=".pdf"
@ -43,8 +48,12 @@ export default function FileUpload({ selectionMessage, onFileSelect, uploadedFil
ref={fileInputRef} // Attachement de la référence
/>
<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-sm text-gray-500 mt-2">ou cliquez pour sélectionner un fichier PDF</p>
<p className="text-lg font-semibold text-gray-800">
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>
</div>
{localFileName && (

View File

@ -65,13 +65,13 @@ export default function InscriptionFormShared({
const [uploadedFiles, setUploadedFiles] = useState([]);
const [schoolFileTemplates, setSchoolFileTemplates] = useState([]);
const [parentFileTemplates, setParentFileTemplates] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [isSignatureComplete, setIsSignatureComplete] = useState(false);
const [currentPage, setCurrentPage] = useState(5);
const [isPage1Valid, setIsPage1Valid] = useState(false);
const [isPage2Valid, setIsPage2Valid] = useState(false);
const [isPage3Valid, setIsPage3Valid] = useState(false);
const [isPage4Valid, setIsPage4Valid] = useState(false);
const [isPage5Valid, setIsPage5Valid] = useState(false);
const [hasInteracted, setHasInteracted] = useState(false);
@ -95,7 +95,9 @@ export default function InscriptionFormShared({
useEffect(() => {
// 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
setIsPage4Valid(allSigned);
@ -105,11 +107,21 @@ export default function InscriptionFormShared({
}
}, [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 template = schoolFileTemplates[index];
if (!template) {
logger.error('Template introuvable pour l\'index donné.');
logger.error("Template introuvable pour l'index donné.");
return;
}
@ -117,11 +129,9 @@ export default function InscriptionFormShared({
.then((data) => fetch(data))
.then((response) => response.blob())
.then((blob) => {
const file = new File(
[blob],
`${template.name}.pdf`,
{ type: blob.type }
);
const file = new File([blob], `${template.name}.pdf`, {
type: blob.type,
});
const updateData = new FormData();
updateData.append('file', file);
@ -236,6 +246,15 @@ export default function InscriptionFormShared({
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
})
.catch((error) => {
@ -265,6 +284,8 @@ export default function InscriptionFormShared({
.then((response) => {
logger.debug('Fichier supprimé avec succès dans la base :', response);
setIsPage5Valid(false);
// Mettre à jour l'état local pour refléter la suppression
setUploadedFiles((prev) =>
prev.map((uploadedFile) =>
@ -273,6 +294,13 @@ export default function InscriptionFormShared({
: 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;
})
.catch((error) => {
@ -311,10 +339,9 @@ export default function InscriptionFormShared({
const stepTitles = {
1: 'Elève',
2: 'Responsables légaux',
3: "Modalités de paiement",
4: "Formulaires à signer",
5: "Pièces à fournir",
6: "Validation"
3: 'Modalités de paiement',
4: 'Formulaires à signer',
5: 'Pièces à fournir',
};
const steps = [
@ -323,7 +350,6 @@ export default function InscriptionFormShared({
'Paiement',
'Formulaires',
'Documents parent',
'Validation'
];
const isStepValid = (stepNumber) => {
@ -334,6 +360,10 @@ export default function InscriptionFormShared({
return isPage2Valid;
case 3:
return isPage3Valid;
case 4:
return isPage4Valid;
case 5:
return isPage5Valid;
default:
return false;
}
@ -350,7 +380,10 @@ export default function InscriptionFormShared({
setStep={setCurrentPage}
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 */}
{currentPage === 1 && (
<StudentInfoForm
@ -395,7 +428,9 @@ export default function InscriptionFormShared({
<div className="mt-8 mb-4 w-4/5 mx-auto flex gap-8">
{/* Liste des états de signature */}
<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">
Documents
</h3>
<ul className="space-y-2">
{schoolFileTemplates.map((template, index) => (
<li
@ -427,7 +462,8 @@ export default function InscriptionFormShared({
{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'}
{schoolFileTemplates[currentTemplateIndex].name ||
'Document sans nom'}
</h3>
<p className="text-sm text-gray-500 mb-4">
{schoolFileTemplates[currentTemplateIndex].description ||
@ -441,7 +477,9 @@ export default function InscriptionFormShared({
src={`https://docuseal.com/s/${schoolFileTemplates[currentTemplateIndex].slug}`}
withDownloadButton={false}
withTitle={false}
onComplete={() => handleTemplateSigned(currentTemplateIndex)}
onComplete={() =>
handleTemplateSigned(currentTemplateIndex)
}
/>
) : (
<iframe
@ -516,7 +554,17 @@ export default function InscriptionFormShared({
/>
)}
{currentPage === steps.length && (
<Button onClick={handleSubmit} text="Valider" primary />
<Button
onClick={handleSubmit}
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>

View File

@ -7,12 +7,13 @@ export default function PaymentMethodSelector({
registrationPaymentModes,
tuitionPaymentModes,
errors,
setIsPageValid
setIsPageValid,
}) {
useEffect(() => {
const isValid = !Object.keys(formData).some((field) => getLocalError(field) !== '');
console.log(isValid)
const isValid = !Object.keys(formData).some(
(field) => getLocalError(field) !== ''
);
console.log(isValid);
setIsPageValid(isValid);
}, [formData, setIsPageValid]);
@ -30,8 +31,12 @@ export default function PaymentMethodSelector({
const getLocalError = (field) => {
if (
// Student Form
( field === 'registration_payment' && (!formData.registration_payment || String(formData.registration_payment).trim() === '') ) ||
( field === 'tuition_payment' && (!formData.tuition_payment || String(formData.tuition_payment).trim() === '') )
(field === 'registration_payment' &&
(!formData.registration_payment ||
String(formData.registration_payment).trim() === '')) ||
(field === 'tuition_payment' &&
(!formData.tuition_payment ||
String(formData.tuition_payment).trim() === ''))
) {
return 'Champs requis';
}
@ -53,7 +58,8 @@ export default function PaymentMethodSelector({
{/* Section d'information */}
<div className="mb-6 bg-gray-50 p-4 rounded-lg border border-gray-100">
<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>
</div>
@ -62,7 +68,7 @@ export default function PaymentMethodSelector({
label="Mode de Paiement"
placeHolder="Sélectionner un mode de paiement"
selected={formData.registration_payment}
callback={(e) => onChange("registration_payment", e.target.value)}
callback={(e) => onChange('registration_payment', e.target.value)}
choices={registrationPaymentModes.map((mode) => ({
value: mode.mode,
label:
@ -70,7 +76,10 @@ export default function PaymentMethodSelector({
?.name || 'Mode inconnu',
}))}
required
errorMsg={getError("registration_payment") || getLocalError("registration_payment")}
errorMsg={
getError('registration_payment') ||
getLocalError('registration_payment')
}
/>
</div>
@ -83,7 +92,8 @@ export default function PaymentMethodSelector({
{/* Section d'information */}
<div className="mb-6 bg-gray-50 p-4 rounded-lg border border-gray-100">
<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>
</div>
@ -92,7 +102,7 @@ export default function PaymentMethodSelector({
label="Mode de Paiement"
placeHolder="Sélectionner un mode de paiement"
selected={formData.tuition_payment}
callback={(e) => onChange("tuition_payment", e.target.value)}
callback={(e) => onChange('tuition_payment', e.target.value)}
choices={tuitionPaymentModes.map((mode) => ({
value: mode.mode,
label:
@ -100,7 +110,9 @@ export default function PaymentMethodSelector({
?.name || 'Mode inconnu',
}))}
required
errorMsg={getError("tuition_payment") || getLocalError("tuition_payment")}
errorMsg={
getError('tuition_payment') || getLocalError('tuition_payment')
}
/>
</div>
</>

View File

@ -9,13 +9,17 @@ export default function ResponsableInputFields({
guardians,
setGuardians,
errors,
setIsPageValid
setIsPageValid,
}) {
const t = useTranslations('ResponsableInputFields');
useEffect(() => {
const isValid = guardians.length > 0 && guardians.every((guardian, index) => {
return !Object.keys(guardian).some((field) => getLocalError(index, field) !== '');
const isValid =
guardians.length > 0 &&
guardians.every((guardian, index) => {
return !Object.keys(guardian).some(
(field) => getLocalError(index, field) !== ''
);
});
setIsPageValid(isValid);
@ -28,12 +32,23 @@ export default function ResponsableInputFields({
const getLocalError = (index, field) => {
if (
// Student Form
( field === 'last_name' && (!guardians[index].last_name || guardians[index].last_name.trim() === '') ) ||
( field === 'first_name' && (!guardians[index].first_name || 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() === '') )
(field === 'last_name' &&
(!guardians[index].last_name ||
guardians[index].last_name.trim() === '')) ||
(field === 'first_name' &&
(!guardians[index].first_name ||
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';
}
@ -88,7 +103,10 @@ export default function ResponsableInputFields({
onChange={(event) => {
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
/>
<InputText
@ -99,7 +117,10 @@ export default function ResponsableInputFields({
onChange={(event) => {
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
/>
</div>
@ -118,11 +139,13 @@ export default function ResponsableInputFields({
);
}}
required
errorMsg={getError(index, 'email') || getLocalError(index, 'email')}
errorMsg={
getError(index, 'email') || getLocalError(index, 'email')
}
/>
<InputPhone
name="telephoneResponsable"
label='phone'
label="phone"
value={item.phone}
onChange={(event) => {
onGuardiansChange(item.id, 'phone', event);
@ -142,7 +165,10 @@ export default function ResponsableInputFields({
onGuardiansChange(item.id, 'birth_date', event.target.value);
}}
required
errorMsg={getError(index, 'birth_date') || getLocalError(index, 'birth_date')}
errorMsg={
getError(index, 'birth_date') ||
getLocalError(index, 'birth_date')
}
/>
<InputText
name="professionResponsable"
@ -153,7 +179,10 @@ export default function ResponsableInputFields({
onGuardiansChange(item.id, 'profession', event.target.value);
}}
required
errorMsg={getError(index, 'profession') || getLocalError(index, 'profession')}
errorMsg={
getError(index, 'profession') ||
getLocalError(index, 'profession')
}
/>
</div>
@ -167,7 +196,9 @@ export default function ResponsableInputFields({
onGuardiansChange(item.id, 'address', event.target.value);
}}
required
errorMsg={getError(index, 'address') || getLocalError(index, 'address')}
errorMsg={
getError(index, 'address') || getLocalError(index, 'address')
}
/>
</div>
</div>

View File

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

View File

@ -4,7 +4,10 @@ import Button from '@/components/Button';
import ToggleSwitch from '@/components/ToggleSwitch'; // Import du composant ToggleSwitch
import { BASE_URL } from '@/utils/Url';
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 { GraduationCap } from 'lucide-react';
import FileUpload from '@/components/FileUpload';
@ -47,7 +50,12 @@ export default function ValidateSubscription({
setSchoolFileTemplates(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
fetchParentFileTemplatesFromRegistrationFiles(studentId)
@ -55,7 +63,12 @@ export default function ValidateSubscription({
setParentFileTemplates(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]);
const handleAccept = () => {
@ -70,7 +83,7 @@ export default function ValidateSubscription({
const data = {
status: 7,
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
@ -85,7 +98,11 @@ export default function ValidateSubscription({
const isValidateButtonDisabled = isSepa && !uploadedFileName;
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) {
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 = () => {
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
const index = currentPage - 2; // Décalage pour correspondre à l'index du tableau
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
const index = currentPage - 2 - schoolFileTemplates.length; // Décalage pour correspondre à l'index du tableau
return (
@ -175,7 +202,9 @@ export default function ValidateSubscription({
{/* Option de fusion des documents (affichée uniquement sur la dernière page) */}
{currentPage === totalPages && (
<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
label="Fusionner"
checked={mergeDocuments}

View File

@ -8,16 +8,19 @@ const SectionHeader = ({
description,
button = false,
buttonOpeningModal = false,
onClick = null
onClick = null,
}) => {
return (
<div className="flex items-center justify-between mb-6">
<div className="flex items-center space-x-4">
<div className={`${discountStyle ? "bg-yellow-100" : "bg-emerald-100"} p-3 rounded-full shadow-md`}>
<div
className={`${discountStyle ? 'bg-yellow-100' : 'bg-emerald-100'} p-3 rounded-full shadow-md`}
>
<Icon
className={discountStyle ?
"w-8 h-8 text-yellow-600" :
"w-8 h-8 text-emerald-600"
className={
discountStyle
? 'w-8 h-8 text-yellow-600'
: 'w-8 h-8 text-emerald-600'
}
/>
</div>
@ -29,9 +32,10 @@ const SectionHeader = ({
{button && onClick && (
<button
onClick={onClick}
className={buttonOpeningModal ?
"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"
className={
buttonOpeningModal
? '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" />

View File

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