mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 07:53:23 +00:00
feat: Ordonnancement de l'inscription sur plusieurs pages + contrôle des
champs remplis dans le formulaire
This commit is contained in:
@ -2,7 +2,7 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import DjangoCSRFToken from '@/components/DjangoCSRFToken';
|
import DjangoCSRFToken from '@/components/DjangoCSRFToken';
|
||||||
import Logo from '@/components/Logo';
|
import Logo from '@/components/Logo';
|
||||||
import { useSearchParams, useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import InputTextIcon from '@/components/InputTextIcon';
|
import InputTextIcon from '@/components/InputTextIcon';
|
||||||
import Loader from '@/components/Loader'; // Importez le composant Loader
|
import Loader from '@/components/Loader'; // Importez le composant Loader
|
||||||
import Button from '@/components/Button'; // Importez le composant Button
|
import Button from '@/components/Button'; // Importez le composant Button
|
||||||
@ -16,7 +16,6 @@ import logger from '@/utils/logger';
|
|||||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const searchParams = useSearchParams();
|
|
||||||
const [errorMessage, setErrorMessage] = useState('');
|
const [errorMessage, setErrorMessage] = useState('');
|
||||||
const [userFieldError, setUserFieldError] = useState('');
|
const [userFieldError, setUserFieldError] = useState('');
|
||||||
const [passwordFieldError, setPasswordFieldError] = useState('');
|
const [passwordFieldError, setPasswordFieldError] = useState('');
|
||||||
@ -26,10 +25,6 @@ export default function Page() {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const csrfToken = useCsrfToken(); // Utilisez le hook useCsrfToken
|
const csrfToken = useCsrfToken(); // Utilisez le hook useCsrfToken
|
||||||
|
|
||||||
function isOK(data) {
|
|
||||||
return data.errorMessage === '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleFormLogin(formData) {
|
function handleFormLogin(formData) {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setErrorMessage('');
|
setErrorMessage('');
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
// Import des dépendances nécessaires
|
// Import des dépendances nécessaires
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import Loader from '@/components/Loader';
|
|
||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
import DjangoCSRFToken from '@/components/DjangoCSRFToken';
|
import DjangoCSRFToken from '@/components/DjangoCSRFToken';
|
||||||
import {
|
import {
|
||||||
fetchRegisterForm,
|
|
||||||
fetchSchoolFileTemplatesFromRegistrationFiles,
|
fetchSchoolFileTemplatesFromRegistrationFiles,
|
||||||
fetchParentFileTemplatesFromRegistrationFiles,
|
fetchParentFileTemplatesFromRegistrationFiles,
|
||||||
} from '@/app/actions/subscriptionAction';
|
} from '@/app/actions/subscriptionAction';
|
||||||
@ -19,11 +17,12 @@ import {
|
|||||||
} from '@/app/actions/schoolAction';
|
} from '@/app/actions/schoolAction';
|
||||||
import { BASE_URL } from '@/utils/Url';
|
import { BASE_URL } from '@/utils/Url';
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
import StudentInfoForm, {
|
|
||||||
validateStudentInfo,
|
|
||||||
} from '@/components/Inscription/StudentInfoForm';
|
|
||||||
import FilesToUpload from '@/components/Inscription/FilesToUpload';
|
import FilesToUpload from '@/components/Inscription/FilesToUpload';
|
||||||
import { DocusealForm } from '@docuseal/react';
|
import { DocusealForm } from '@docuseal/react';
|
||||||
|
import StudentInfoForm from '@/components/Inscription/StudentInfoForm';
|
||||||
|
import ResponsableInputFields from '@/components/Inscription/ResponsableInputFields';
|
||||||
|
import PaymentMethodSelector from '@/components/Inscription/PaymentMethodSelector';
|
||||||
|
import ProgressStep from '@/components/ProgressStep';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Composant de formulaire d'inscription partagé
|
* Composant de formulaire d'inscription partagé
|
||||||
@ -41,7 +40,6 @@ export default function InscriptionFormShared({
|
|||||||
errors = {}, // Nouvelle prop pour les erreurs
|
errors = {}, // Nouvelle prop pour les erreurs
|
||||||
}) {
|
}) {
|
||||||
// États pour gérer les données du formulaire
|
// États pour gérer les données du formulaire
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
id: '',
|
id: '',
|
||||||
last_name: '',
|
last_name: '',
|
||||||
@ -67,44 +65,13 @@ export default function InscriptionFormShared({
|
|||||||
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(1);
|
||||||
|
const [isSignatureComplete, setIsSignatureComplete] = useState(false);
|
||||||
|
|
||||||
const isCurrentPageValid = () => {
|
const [isPage1Valid, setIsPage1Valid] = useState(false);
|
||||||
if (currentPage === 1) {
|
const [isPage2Valid, setIsPage2Valid] = useState(false);
|
||||||
const isValid = validateStudentInfo(formData);
|
const [isPage3Valid, setIsPage3Valid] = useState(false);
|
||||||
return isValid;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Chargement initial des données
|
const [hasInteracted, setHasInteracted] = useState(false);
|
||||||
// Mettre à jour les données quand initialData change
|
|
||||||
useEffect(() => {
|
|
||||||
if (studentId) {
|
|
||||||
fetchRegisterForm(studentId).then((data) => {
|
|
||||||
logger.debug(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 || '',
|
|
||||||
registration_payment: data?.registration_payment || '',
|
|
||||||
tuition_payment: data?.tuition_payment || '',
|
|
||||||
totalRegistrationFees: data?.totalRegistrationFees,
|
|
||||||
totalTuitionFees: data?.totalTuitionFees,
|
|
||||||
});
|
|
||||||
setGuardians(data?.student?.guardians || []);
|
|
||||||
});
|
|
||||||
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
}, [studentId]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchSchoolFileTemplatesFromRegistrationFiles(studentId).then((data) => {
|
fetchSchoolFileTemplatesFromRegistrationFiles(studentId).then((data) => {
|
||||||
@ -159,11 +126,6 @@ export default function InscriptionFormShared({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fonctions de gestion du formulaire et des fichiers
|
|
||||||
const updateFormField = (field, value) => {
|
|
||||||
setFormData((prev) => ({ ...prev, [field]: value }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFileUpload = (file, selectedFile) => {
|
const handleFileUpload = (file, selectedFile) => {
|
||||||
if (!file || !selectedFile) {
|
if (!file || !selectedFile) {
|
||||||
logger.error('Données manquantes pour le téléversement.');
|
logger.error('Données manquantes pour le téléversement.');
|
||||||
@ -265,19 +227,6 @@ export default function InscriptionFormShared({
|
|||||||
onSubmit(data);
|
onSubmit(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Soumission du formulaire
|
|
||||||
const handleSave = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const data = {
|
|
||||||
student: {
|
|
||||||
...formData,
|
|
||||||
guardians,
|
|
||||||
},
|
|
||||||
establishment: selectedEstablishmentId,
|
|
||||||
};
|
|
||||||
onSubmit(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNextPage = () => {
|
const handleNextPage = () => {
|
||||||
setCurrentPage(currentPage + 1);
|
setCurrentPage(currentPage + 1);
|
||||||
};
|
};
|
||||||
@ -286,31 +235,93 @@ export default function InscriptionFormShared({
|
|||||||
setCurrentPage(currentPage - 1);
|
setCurrentPage(currentPage - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Affichage du loader pendant le chargement
|
const stepTitles = {
|
||||||
if (isLoading) return <Loader />;
|
1: 'Elève',
|
||||||
|
2: 'Responsables légaux',
|
||||||
|
3: "Modalités de paiement",
|
||||||
|
4: "Formulaires à signer",
|
||||||
|
5: "Pièces à fournir",
|
||||||
|
6: "Validation"
|
||||||
|
};
|
||||||
|
|
||||||
|
const steps = [
|
||||||
|
'Élève',
|
||||||
|
'Responsable',
|
||||||
|
'Paiement',
|
||||||
|
'Formulaires',
|
||||||
|
'Documents parent',
|
||||||
|
'Validation'
|
||||||
|
];
|
||||||
|
|
||||||
|
const isStepValid = (stepNumber) => {
|
||||||
|
switch (stepNumber) {
|
||||||
|
case 1:
|
||||||
|
return isPage1Valid;
|
||||||
|
case 2:
|
||||||
|
return isPage2Valid;
|
||||||
|
case 3:
|
||||||
|
return isPage3Valid;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Rendu du composant
|
// Rendu du composant
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto p-6">
|
<div className="mx-auto p-6">
|
||||||
<form onSubmit={handleSubmit} className="space-y-8">
|
|
||||||
<DjangoCSRFToken csrfToken={csrfToken} />
|
<DjangoCSRFToken csrfToken={csrfToken} />
|
||||||
{/* Page 1 : Informations de l'élève et Responsables */}
|
<ProgressStep
|
||||||
|
steps={steps}
|
||||||
|
stepTitles={stepTitles}
|
||||||
|
currentStep={currentPage}
|
||||||
|
setStep={setCurrentPage}
|
||||||
|
isStepValid={isStepValid}
|
||||||
|
/>
|
||||||
|
<div className="flex-1 overflow-y-auto mt-12 " style={{ maxHeight: 'calc(100vh - 300px)' }}>
|
||||||
|
{/* Page 1 : Informations sur l'élève */}
|
||||||
{currentPage === 1 && (
|
{currentPage === 1 && (
|
||||||
<StudentInfoForm
|
<StudentInfoForm
|
||||||
|
studentId={studentId}
|
||||||
formData={formData}
|
formData={formData}
|
||||||
updateFormField={updateFormField}
|
setFormData={setFormData}
|
||||||
guardians={guardians}
|
guardians={guardians}
|
||||||
setGuardians={setGuardians}
|
setGuardians={setGuardians}
|
||||||
registrationPaymentModes={registrationPaymentModes}
|
|
||||||
tuitionPaymentModes={tuitionPaymentModes}
|
|
||||||
errors={errors}
|
errors={errors}
|
||||||
|
setIsPageValid={setIsPage1Valid}
|
||||||
|
hasInteracted={hasInteracted}
|
||||||
|
setHasInteracted={setHasInteracted}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Page 2 : Informations sur les responsables légaux */}
|
||||||
|
{currentPage === 2 && (
|
||||||
|
<ResponsableInputFields
|
||||||
|
guardians={guardians}
|
||||||
|
setGuardians={setGuardians}
|
||||||
|
errors={errors}
|
||||||
|
setIsPageValid={setIsPage2Valid}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Page 3 : Informations sur les modalités de paiement */}
|
||||||
|
{currentPage === 3 && (
|
||||||
|
<>
|
||||||
|
<PaymentMethodSelector
|
||||||
|
formData={formData}
|
||||||
|
setFormData={setFormData}
|
||||||
|
registrationPaymentModes={registrationPaymentModes}
|
||||||
|
tuitionPaymentModes={tuitionPaymentModes}
|
||||||
|
errors={errors}
|
||||||
|
setIsPageValid={setIsPage3Valid}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Pages suivantes : Section Fichiers d'inscription */}
|
{/* Pages suivantes : Section Fichiers d'inscription */}
|
||||||
{currentPage > 1 && currentPage <= schoolFileTemplates.length + 1 && (
|
{currentPage === 4 && (
|
||||||
<div className="mt-8 mb-4 w-3/5">
|
<div className="mt-8 mb-4 w-3/5 mx-auto">
|
||||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
{schoolFileTemplates.length > 0 && (
|
||||||
|
<div className="mt-8 mb-4 w-3/5 mx-auto">
|
||||||
{/* Titre du document */}
|
{/* Titre du document */}
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<h2 className="text-lg font-semibold text-gray-800">
|
<h2 className="text-lg font-semibold text-gray-800">
|
||||||
@ -326,12 +337,14 @@ export default function InscriptionFormShared({
|
|||||||
{/* Affichage du formulaire ou du document */}
|
{/* Affichage du formulaire ou du document */}
|
||||||
{schoolFileTemplates[currentPage - 2].file === null ? (
|
{schoolFileTemplates[currentPage - 2].file === null ? (
|
||||||
<DocusealForm
|
<DocusealForm
|
||||||
|
key={schoolFileTemplates[currentPage - 2].slug} // Clé unique basée sur le slug du document
|
||||||
id="docusealForm"
|
id="docusealForm"
|
||||||
src={
|
src={
|
||||||
'https://docuseal.com/s/' +
|
'https://docuseal.com/s/' +
|
||||||
schoolFileTemplates[currentPage - 2].slug
|
schoolFileTemplates[currentPage - 2].slug
|
||||||
}
|
}
|
||||||
withDownloadButton={false}
|
withDownloadButton={false}
|
||||||
|
withTitle={false}
|
||||||
onComplete={() => {
|
onComplete={() => {
|
||||||
downloadTemplate(schoolFileTemplates[currentPage - 2].slug)
|
downloadTemplate(schoolFileTemplates[currentPage - 2].slug)
|
||||||
.then((data) => fetch(data))
|
.then((data) => fetch(data))
|
||||||
@ -353,9 +366,11 @@ export default function InscriptionFormShared({
|
|||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
logger.debug('EDIT TEMPLATE : ', data);
|
logger.debug('EDIT TEMPLATE : ', data);
|
||||||
|
setIsSignatureComplete(true);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
logger.error('error editing template : ', error);
|
logger.error('error editing template : ', error);
|
||||||
|
setIsSignatureComplete(false);
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -371,11 +386,12 @@ export default function InscriptionFormShared({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Dernière page : Section Fichiers parents */}
|
{/* Dernière page : Section Fichiers parents */}
|
||||||
{currentPage === schoolFileTemplates.length + 2 && (
|
{currentPage === 5 && (
|
||||||
<FilesToUpload
|
<FilesToUpload
|
||||||
parentFileTemplates={parentFileTemplates}
|
parentFileTemplates={parentFileTemplates}
|
||||||
uploadedFiles={uploadedFiles}
|
uploadedFiles={uploadedFiles}
|
||||||
@ -383,16 +399,10 @@ export default function InscriptionFormShared({
|
|||||||
onFileDelete={handleDeleteFile}
|
onFileDelete={handleDeleteFile}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Boutons de contrôle */}
|
{/* Boutons de contrôle */}
|
||||||
<div className="flex justify-center space-x-4">
|
<div className="flex justify-center space-x-4 mt-12">
|
||||||
<Button
|
|
||||||
text="Sauvegarder"
|
|
||||||
onClick={handleSave}
|
|
||||||
className="px-4 py-2 rounded-md shadow-sm focus:outline-none bg-orange-500 text-white hover:bg-orange-600"
|
|
||||||
primary
|
|
||||||
name="Save"
|
|
||||||
/>
|
|
||||||
{currentPage > 1 && (
|
{currentPage > 1 && (
|
||||||
<Button
|
<Button
|
||||||
text="Précédent"
|
text="Précédent"
|
||||||
@ -400,9 +410,10 @@ export default function InscriptionFormShared({
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handlePreviousPage();
|
handlePreviousPage();
|
||||||
}}
|
}}
|
||||||
|
primary
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{currentPage < schoolFileTemplates.length + 2 && (
|
{currentPage < steps.length && (
|
||||||
<Button
|
<Button
|
||||||
text="Suivant"
|
text="Suivant"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
@ -410,20 +421,25 @@ export default function InscriptionFormShared({
|
|||||||
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 ${
|
||||||
!isCurrentPageValid()
|
(currentPage === 1 && !isPage1Valid) ||
|
||||||
|
(currentPage === 2 && !isPage2Valid) ||
|
||||||
|
(currentPage === 3 && !isPage3Valid)
|
||||||
? '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={!isCurrentPageValid()}
|
disabled={
|
||||||
|
(currentPage === 1 && !isPage1Valid) ||
|
||||||
|
(currentPage === 2 && !isPage2Valid) ||
|
||||||
|
(currentPage === 3 && !isPage3Valid)
|
||||||
|
}
|
||||||
primary
|
primary
|
||||||
name="Next"
|
name="Next"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{currentPage === schoolFileTemplates.length + 2 && (
|
{currentPage === steps.length && (
|
||||||
<Button type="submit" text="Valider" primary />
|
<Button onClick={handleSubmit} text="Valider" primary />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,48 +1,108 @@
|
|||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import SelectChoice from '@/components/SelectChoice';
|
import SelectChoice from '@/components/SelectChoice';
|
||||||
|
|
||||||
export default function PaymentMethodSelector({
|
export default function PaymentMethodSelector({
|
||||||
formData,
|
formData,
|
||||||
title,
|
setFormData,
|
||||||
name,
|
registrationPaymentModes,
|
||||||
updateFormField,
|
tuitionPaymentModes,
|
||||||
selected,
|
errors,
|
||||||
paymentModes,
|
setIsPageValid
|
||||||
paymentModesOptions,
|
|
||||||
amount,
|
|
||||||
getError,
|
|
||||||
}) {
|
}) {
|
||||||
//console.log(paymentModes)
|
|
||||||
//console.log(selected)
|
useEffect(() => {
|
||||||
|
const isValid = !Object.keys(formData).some((field) => getLocalError(field) !== '');
|
||||||
|
console.log(isValid)
|
||||||
|
setIsPageValid(isValid);
|
||||||
|
}, [formData, setIsPageValid]);
|
||||||
|
|
||||||
|
const paymentModesOptions = [
|
||||||
|
{ id: 1, name: 'Prélèvement SEPA' },
|
||||||
|
{ id: 2, name: 'Virement' },
|
||||||
|
{ id: 3, name: 'Chèque' },
|
||||||
|
{ id: 4, name: 'Espèce' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const getError = (field) => {
|
||||||
|
return errors?.student?.[field]?.[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
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() === '') )
|
||||||
|
) {
|
||||||
|
return 'Champs requis';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChange = (field, value) => {
|
||||||
|
setFormData((prev) => ({ ...prev, [field]: value }));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<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">
|
||||||
{title}
|
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> {amount} €
|
<strong className="text-gray-900">Montant :</strong> {formData.totalRegistrationFees} €
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SelectChoice
|
<SelectChoice
|
||||||
name={name}
|
name="registration_payment"
|
||||||
label="Mode de Paiement"
|
label="Mode de Paiement"
|
||||||
placeHolder="Sélectionner un mode de paiement"
|
placeHolder="Sélectionner un mode de paiement"
|
||||||
selected={selected || ''}
|
selected={formData.registration_payment}
|
||||||
callback={(e) => updateFormField(name, e.target.value)}
|
callback={(e) => onChange("registration_payment", e.target.value)}
|
||||||
choices={paymentModes.map((mode) => ({
|
choices={registrationPaymentModes.map((mode) => ({
|
||||||
value: mode.mode,
|
value: mode.mode,
|
||||||
label:
|
label:
|
||||||
paymentModesOptions.find((option) => option.id === mode.mode)
|
paymentModesOptions.find((option) => option.id === mode.mode)
|
||||||
?.name || 'Mode inconnu',
|
?.name || 'Mode inconnu',
|
||||||
}))}
|
}))}
|
||||||
required
|
required
|
||||||
errorMsg={getError('payment_method')}
|
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">
|
||||||
|
{/* Titre */}
|
||||||
|
<h2 className="text-2xl font-semibold mb-6 text-gray-800 border-b pb-2">
|
||||||
|
Frais de scolarité
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{/* 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} €
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SelectChoice
|
||||||
|
name="tuition_payment"
|
||||||
|
label="Mode de Paiement"
|
||||||
|
placeHolder="Sélectionner un mode de paiement"
|
||||||
|
selected={formData.tuition_payment}
|
||||||
|
callback={(e) => onChange("tuition_payment", e.target.value)}
|
||||||
|
choices={tuitionPaymentModes.map((mode) => ({
|
||||||
|
value: mode.mode,
|
||||||
|
label:
|
||||||
|
paymentModesOptions.find((option) => option.id === mode.mode)
|
||||||
|
?.name || 'Mode inconnu',
|
||||||
|
}))}
|
||||||
|
required
|
||||||
|
errorMsg={getError("tuition_payment") || getLocalError("tuition_payment")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,27 +1,70 @@
|
|||||||
import InputText from '@/components/InputText';
|
import InputText from '@/components/InputText';
|
||||||
import InputPhone from '@/components/InputPhone';
|
import InputPhone from '@/components/InputPhone';
|
||||||
import Button from '@/components/Button';
|
import React, { useEffect } from 'react';
|
||||||
import React from 'react';
|
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { Trash2, Plus } from 'lucide-react';
|
import { Trash2, Plus, Users } from 'lucide-react';
|
||||||
|
import SectionHeader from '@/components/SectionHeader';
|
||||||
|
|
||||||
export default function ResponsableInputFields({
|
export default function ResponsableInputFields({
|
||||||
guardians,
|
guardians,
|
||||||
onGuardiansChange,
|
setGuardians,
|
||||||
addGuardian,
|
errors,
|
||||||
deleteGuardian,
|
setIsPageValid
|
||||||
errors = [],
|
|
||||||
}) {
|
}) {
|
||||||
const t = useTranslations('ResponsableInputFields');
|
const t = useTranslations('ResponsableInputFields');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const isValid = guardians.length > 0 && guardians.every((guardian, index) => {
|
||||||
|
return !Object.keys(guardian).some((field) => getLocalError(index, field) !== '');
|
||||||
|
});
|
||||||
|
|
||||||
|
setIsPageValid(isValid);
|
||||||
|
}, [guardians, setIsPageValid]);
|
||||||
|
|
||||||
const getError = (index, field) => {
|
const getError = (index, field) => {
|
||||||
return errors[index]?.[field]?.[0];
|
return errors[index]?.[field]?.[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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() === '') )
|
||||||
|
) {
|
||||||
|
return 'Champs requis';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const onGuardiansChange = (id, field, value) => {
|
||||||
|
const updatedGuardians = guardians.map((guardian) =>
|
||||||
|
guardian.id === id ? { ...guardian, [field]: value } : guardian
|
||||||
|
);
|
||||||
|
setGuardians(updatedGuardians);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addGuardian = () => {
|
||||||
|
setGuardians([...guardians, { id: Date.now(), name: '', email: '' }]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteGuardian = (index) => {
|
||||||
|
const updatedGuardians = guardians.filter((_, i) => i !== index);
|
||||||
|
setGuardians(updatedGuardians);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||||
|
<SectionHeader
|
||||||
|
icon={Users}
|
||||||
|
title={`Responsables légaux`}
|
||||||
|
description={`Remplissez les champs requis`}
|
||||||
|
/>
|
||||||
{guardians.map((item, index) => (
|
{guardians.map((item, index) => (
|
||||||
<div className="p-6 bg-gray-50 rounded-lg shadow-sm" key={index}>
|
<div className="p-6 " key={index}>
|
||||||
<div className="flex justify-between items-center mb-4">
|
<div className="flex justify-between items-center mb-4">
|
||||||
<h3 className="text-xl font-bold">
|
<h3 className="text-xl font-bold">
|
||||||
{t('responsable')} {index + 1}
|
{t('responsable')} {index + 1}
|
||||||
@ -45,7 +88,7 @@ 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')}
|
errorMsg={getError(index, 'last_name') || getLocalError(index, 'last_name')}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
@ -56,7 +99,7 @@ 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')}
|
errorMsg={getError(index, 'first_name') || getLocalError(index, 'first_name')}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -75,11 +118,11 @@ export default function ResponsableInputFields({
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
required
|
required
|
||||||
errorMsg={getError(index, 'email')}
|
errorMsg={getError(index, 'email') || getLocalError(index, 'email')}
|
||||||
/>
|
/>
|
||||||
<InputPhone
|
<InputPhone
|
||||||
name="telephoneResponsable"
|
name="telephoneResponsable"
|
||||||
label={t('phone')}
|
label='phone'
|
||||||
value={item.phone}
|
value={item.phone}
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
onGuardiansChange(item.id, 'phone', event);
|
onGuardiansChange(item.id, 'phone', event);
|
||||||
@ -99,7 +142,7 @@ 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')}
|
errorMsg={getError(index, 'birth_date') || getLocalError(index, 'birth_date')}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
name="professionResponsable"
|
name="professionResponsable"
|
||||||
@ -110,7 +153,7 @@ export default function ResponsableInputFields({
|
|||||||
onGuardiansChange(item.id, 'profession', event.target.value);
|
onGuardiansChange(item.id, 'profession', event.target.value);
|
||||||
}}
|
}}
|
||||||
required
|
required
|
||||||
errorMsg={getError(index, 'profession')}
|
errorMsg={getError(index, 'profession') || getLocalError(index, 'profession')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -124,7 +167,7 @@ export default function ResponsableInputFields({
|
|||||||
onGuardiansChange(item.id, 'address', event.target.value);
|
onGuardiansChange(item.id, 'address', event.target.value);
|
||||||
}}
|
}}
|
||||||
required
|
required
|
||||||
errorMsg={getError(index, 'address')}
|
errorMsg={getError(index, 'address') || getLocalError(index, 'address')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,79 +1,135 @@
|
|||||||
import React from 'react';
|
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 ResponsableInputFields from '@/components/Inscription/ResponsableInputFields';
|
import Loader from '@/components/Loader';
|
||||||
import PaymentMethodSelector from '@/components/Inscription/PaymentMethodSelector';
|
import {
|
||||||
|
fetchRegisterForm
|
||||||
|
} from '@/app/actions/subscriptionAction';
|
||||||
|
import logger from '@/utils/logger';
|
||||||
|
import SectionHeader from '@/components/SectionHeader';
|
||||||
|
import { User } from 'lucide-react';
|
||||||
|
|
||||||
const levels = [
|
const levels = [
|
||||||
{ value: '1', label: 'TPS - Très Petite Section' },
|
{ value: '1', label: 'TPS - Très Petite Section' },
|
||||||
{ value: '2', label: 'PS - Petite Section' },
|
{ value: '2', label: 'PS - Petite Section' },
|
||||||
{ value: '3', label: 'MS - Moyenne Section' },
|
{ value: '3', label: 'MS - Moyenne Section' },
|
||||||
{ value: '4', label: 'GS - Grande Section' },
|
{ value: '4', label: 'GS - Grande Section' },
|
||||||
|
{ value: '5', label: 'CP' },
|
||||||
|
{ value: '6', label: 'CE1' },
|
||||||
|
{ value: '7', label: 'CE2' },
|
||||||
|
{ value: '8', label: 'CM1' },
|
||||||
|
{ value: '9', label: 'CM2' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const paymentModesOptions = [
|
|
||||||
{ id: 1, name: 'Prélèvement SEPA' },
|
|
||||||
{ id: 2, name: 'Virement' },
|
|
||||||
{ id: 3, name: 'Chèque' },
|
|
||||||
{ id: 4, name: 'Espèce' },
|
|
||||||
];
|
|
||||||
|
|
||||||
// Fonction de validation pour vérifier les champs requis
|
|
||||||
export function validateStudentInfo(formData) {
|
|
||||||
const requiredFields = [
|
|
||||||
'last_name',
|
|
||||||
'first_name',
|
|
||||||
'nationality',
|
|
||||||
'birth_date',
|
|
||||||
'birth_place',
|
|
||||||
'birth_postal_code',
|
|
||||||
'address',
|
|
||||||
'attending_physician',
|
|
||||||
'level',
|
|
||||||
];
|
|
||||||
|
|
||||||
const isValid = requiredFields.every((field) => {
|
|
||||||
const value = formData[field];
|
|
||||||
return typeof value === 'string' ? value.trim() !== '' : Boolean(value);
|
|
||||||
});
|
|
||||||
|
|
||||||
return isValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function StudentInfoForm({
|
export default function StudentInfoForm({
|
||||||
|
studentId,
|
||||||
formData,
|
formData,
|
||||||
updateFormField,
|
setFormData,
|
||||||
guardians,
|
|
||||||
setGuardians,
|
setGuardians,
|
||||||
registrationPaymentModes,
|
|
||||||
tuitionPaymentModes,
|
|
||||||
errors,
|
errors,
|
||||||
|
setIsPageValid,
|
||||||
|
hasInteracted,
|
||||||
|
setHasInteracted
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (studentId && !hasInteracted) {
|
||||||
|
fetchRegisterForm(studentId).then((data) => {
|
||||||
|
logger.debug(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 || '',
|
||||||
|
registration_payment: data?.registration_payment || '',
|
||||||
|
tuition_payment: data?.tuition_payment || '',
|
||||||
|
totalRegistrationFees: data?.totalRegistrationFees,
|
||||||
|
totalTuitionFees: data?.totalTuitionFees,
|
||||||
|
});
|
||||||
|
setGuardians(data?.student?.guardians || []);
|
||||||
|
});
|
||||||
|
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}, [studentId, hasInteracted]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const isValid = !Object.keys(formData).some((field) => getLocalError(field) !== '');
|
||||||
|
setIsPageValid(isValid);
|
||||||
|
}, [formData, hasInteracted, setIsPageValid]);
|
||||||
|
|
||||||
const getError = (field) => {
|
const getError = (field) => {
|
||||||
return errors?.student?.[field]?.[0];
|
return errors?.student?.[field]?.[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getLocalError = (field) => {
|
||||||
|
if (!hasInteracted) {
|
||||||
|
return ''; // Ne pas afficher les erreurs locales au premier chargement
|
||||||
|
}
|
||||||
|
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() === '') )
|
||||||
|
) {
|
||||||
|
return 'Champs requis';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChange = (field, value) => {
|
||||||
|
setFormData((prev) => ({ ...prev, [field]: value }));
|
||||||
|
|
||||||
|
// Marquer que l'utilisateur a interagi avec le formulaire
|
||||||
|
if (!hasInteracted) {
|
||||||
|
setHasInteracted(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Affichage du loader pendant le chargement
|
||||||
|
if (isLoading) return <Loader />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<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">
|
||||||
<h2 className="text-xl font-bold mb-4 text-gray-800">
|
<SectionHeader
|
||||||
Informations de l'élève
|
icon={User}
|
||||||
</h2>
|
title={`Informations de l'élève`}
|
||||||
|
description={`Remplissez les champs requis`}
|
||||||
|
/>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<InputText
|
<InputText
|
||||||
name="last_name"
|
name="last_name"
|
||||||
label="Nom"
|
label="Nom"
|
||||||
value={formData.last_name}
|
value={formData.last_name}
|
||||||
onChange={(e) => updateFormField('last_name', e.target.value)}
|
onChange={(e) => onChange('last_name', e.target.value)}
|
||||||
required
|
required
|
||||||
errorMsg={getError('last_name')}
|
errorMsg={getError('last_name') || getLocalError('last_name')}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
name="first_name"
|
name="first_name"
|
||||||
label="Prénom"
|
label="Prénom"
|
||||||
value={formData.first_name}
|
value={formData.first_name}
|
||||||
onChange={(e) => updateFormField('first_name', e.target.value)}
|
onChange={(e) => onChange('first_name', e.target.value)}
|
||||||
errorMsg={getError('first_name')}
|
errorMsg={getError('first_name') || getLocalError('first_name')}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
@ -81,43 +137,44 @@ export default function StudentInfoForm({
|
|||||||
label="Nationalité"
|
label="Nationalité"
|
||||||
value={formData.nationality}
|
value={formData.nationality}
|
||||||
required
|
required
|
||||||
onChange={(e) => updateFormField('nationality', e.target.value)}
|
onChange={(e) => onChange('nationality', e.target.value)}
|
||||||
|
errorMsg={getError('nationality') || getLocalError('nationality')}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
name="birth_date"
|
name="birth_date"
|
||||||
type="date"
|
type="date"
|
||||||
label="Date de Naissance"
|
label="Date de Naissance"
|
||||||
value={formData.birth_date}
|
value={formData.birth_date}
|
||||||
onChange={(e) => updateFormField('birth_date', e.target.value)}
|
onChange={(e) => onChange('birth_date', e.target.value)}
|
||||||
required
|
required
|
||||||
errorMsg={getError('birth_date')}
|
errorMsg={getError('birth_date') || getLocalError('birth_date')}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
name="birth_place"
|
name="birth_place"
|
||||||
label="Lieu de Naissance"
|
label="Lieu de Naissance"
|
||||||
value={formData.birth_place}
|
value={formData.birth_place}
|
||||||
onChange={(e) => updateFormField('birth_place', e.target.value)}
|
onChange={(e) => onChange('birth_place', e.target.value)}
|
||||||
required
|
required
|
||||||
errorMsg={getError('birth_place')}
|
errorMsg={getError('birth_place') || getLocalError('birth_place')}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
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) =>
|
||||||
updateFormField('birth_postal_code', e.target.value)
|
onChange('birth_postal_code', e.target.value)
|
||||||
}
|
}
|
||||||
required
|
required
|
||||||
errorMsg={getError('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
|
||||||
name="address"
|
name="address"
|
||||||
label="Adresse"
|
label="Adresse"
|
||||||
value={formData.address}
|
value={formData.address}
|
||||||
onChange={(e) => updateFormField('address', e.target.value)}
|
onChange={(e) => onChange('address', e.target.value)}
|
||||||
required
|
required
|
||||||
errorMsg={getError('address')}
|
errorMsg={getError('address') || getLocalError('address')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<InputText
|
<InputText
|
||||||
@ -125,25 +182,25 @@ export default function StudentInfoForm({
|
|||||||
label="Médecin Traitant"
|
label="Médecin Traitant"
|
||||||
value={formData.attending_physician}
|
value={formData.attending_physician}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
updateFormField('attending_physician', e.target.value)
|
onChange('attending_physician', e.target.value)
|
||||||
}
|
}
|
||||||
required
|
required
|
||||||
errorMsg={getError('attending_physician')}
|
errorMsg={getError('attending_physician') || getLocalError('attending_physician')}
|
||||||
/>
|
/>
|
||||||
<SelectChoice
|
<SelectChoice
|
||||||
name="level"
|
name="level"
|
||||||
label="Niveau"
|
label="Niveau"
|
||||||
placeHolder="Sélectionner un niveau"
|
placeHolder="Sélectionner un niveau"
|
||||||
selected={formData.level}
|
selected={formData.level}
|
||||||
callback={(e) => updateFormField('level', e.target.value)}
|
callback={(e) => onChange('level', e.target.value)}
|
||||||
choices={levels}
|
choices={levels}
|
||||||
required
|
required
|
||||||
errorMsg={getError('level')}
|
errorMsg={getError('level') || getLocalError('level')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<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">
|
||||||
<h2 className="text-xl font-bold mb-4 text-gray-800">Responsables</h2>
|
<h2 className="text-xl font-bold mb-4 text-gray-800">Responsables</h2>
|
||||||
<ResponsableInputFields
|
<ResponsableInputFields
|
||||||
guardians={guardians}
|
guardians={guardians}
|
||||||
@ -170,25 +227,27 @@ export default function StudentInfoForm({
|
|||||||
formData={formData}
|
formData={formData}
|
||||||
title="Frais d'inscription"
|
title="Frais d'inscription"
|
||||||
name="registration_payment"
|
name="registration_payment"
|
||||||
updateFormField={updateFormField}
|
onChange={onChange}
|
||||||
selected={formData.registration_payment}
|
selected={formData.registration_payment}
|
||||||
paymentModes={registrationPaymentModes}
|
paymentModes={registrationPaymentModes}
|
||||||
paymentModesOptions={paymentModesOptions}
|
paymentModesOptions={paymentModesOptions}
|
||||||
amount={formData.totalRegistrationFees}
|
amount={formData.totalRegistrationFees}
|
||||||
getError={getError}
|
getError={getError}
|
||||||
|
getLocalError={getLocalError}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PaymentMethodSelector
|
<PaymentMethodSelector
|
||||||
formData={formData}
|
formData={formData}
|
||||||
title="Frais de scolarité"
|
title="Frais de scolarité"
|
||||||
name="tuition_payment"
|
name="tuition_payment"
|
||||||
updateFormField={updateFormField}
|
onChange={onChange}
|
||||||
selected={formData.tuition_payment}
|
selected={formData.tuition_payment}
|
||||||
paymentModes={tuitionPaymentModes}
|
paymentModes={tuitionPaymentModes}
|
||||||
paymentModesOptions={paymentModesOptions}
|
paymentModesOptions={paymentModesOptions}
|
||||||
amount={formData.totalTuitionFees}
|
amount={formData.totalTuitionFees}
|
||||||
getError={getError}
|
getError={getError}
|
||||||
/>
|
getLocalError={getLocalError}
|
||||||
|
/> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user