mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: Ajout des payementPlans dans le formulaire / ajout de la photo
This commit is contained in:
@ -3,7 +3,7 @@ from django.utils.timezone import now
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from School.models import SchoolClass, Fee, Discount, PaymentModeType
|
from School.models import SchoolClass, Fee, Discount, PaymentModeType, PaymentPlanType
|
||||||
from Auth.models import ProfileRole
|
from Auth.models import ProfileRole
|
||||||
from Establishment.models import Establishment
|
from Establishment.models import Establishment
|
||||||
|
|
||||||
@ -229,6 +229,8 @@ class RegistrationForm(models.Model):
|
|||||||
establishment = models.ForeignKey(Establishment, on_delete=models.CASCADE, related_name='register_forms')
|
establishment = models.ForeignKey(Establishment, on_delete=models.CASCADE, related_name='register_forms')
|
||||||
registration_payment = models.IntegerField(choices=PaymentModeType.choices, null=True, blank=True)
|
registration_payment = models.IntegerField(choices=PaymentModeType.choices, null=True, blank=True)
|
||||||
tuition_payment = models.IntegerField(choices=PaymentModeType.choices, null=True, blank=True)
|
tuition_payment = models.IntegerField(choices=PaymentModeType.choices, null=True, blank=True)
|
||||||
|
registration_payment_plan = models.IntegerField(choices=PaymentPlanType.choices, null=True, blank=True)
|
||||||
|
tuition_payment_plan = models.IntegerField(choices=PaymentPlanType.choices, null=True, blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "RF_" + self.student.last_name + "_" + self.student.first_name
|
return "RF_" + self.student.last_name + "_" + self.student.first_name
|
||||||
|
|||||||
@ -231,6 +231,7 @@ class RegisterFormWithIdView(APIView):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
studentForm_data = request.data.get('data', '{}')
|
studentForm_data = request.data.get('data', '{}')
|
||||||
|
print(f'studentForm_data : {studentForm_data}')
|
||||||
try:
|
try:
|
||||||
data = json.loads(studentForm_data)
|
data = json.loads(studentForm_data)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
@ -239,10 +240,16 @@ class RegisterFormWithIdView(APIView):
|
|||||||
# Extraire le fichier photo
|
# Extraire le fichier photo
|
||||||
photo_file = request.FILES.get('photo')
|
photo_file = request.FILES.get('photo')
|
||||||
|
|
||||||
|
# Extraire le fichier photo
|
||||||
|
sepa_file = request.FILES.get('sepa_file')
|
||||||
|
|
||||||
# Ajouter la photo aux données de l'étudiant
|
# Ajouter la photo aux données de l'étudiant
|
||||||
if photo_file:
|
if photo_file:
|
||||||
data['student']['photo'] = photo_file
|
data['student']['photo'] = photo_file
|
||||||
|
|
||||||
|
if sepa_file:
|
||||||
|
data['sepa_file'] = sepa_file
|
||||||
|
|
||||||
# Gérer le champ `_status`
|
# Gérer le champ `_status`
|
||||||
_status = data.pop('status', 0)
|
_status = data.pop('status', 0)
|
||||||
_status = int(_status)
|
_status = int(_status)
|
||||||
@ -307,7 +314,7 @@ class RegisterFormWithIdView(APIView):
|
|||||||
|
|
||||||
elif _status == RegistrationForm.RegistrationFormStatus.RF_VALIDATED:
|
elif _status == RegistrationForm.RegistrationFormStatus.RF_VALIDATED:
|
||||||
# Vérifier si le paramètre fusion est activé via l'URL
|
# Vérifier si le paramètre fusion est activé via l'URL
|
||||||
fusion = studentForm_data.get('fusion', False)
|
fusion = data.get('fusion', False)
|
||||||
if fusion:
|
if fusion:
|
||||||
# Fusion des documents
|
# Fusion des documents
|
||||||
# Récupération des fichiers schoolFileTemplates
|
# Récupération des fichiers schoolFileTemplates
|
||||||
|
|||||||
@ -375,8 +375,15 @@ export default function Page({ params: { locale } }) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Préparer les données JSON
|
||||||
|
const jsonData = {
|
||||||
|
status: 7,
|
||||||
|
};
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('status', 7);
|
|
||||||
|
// Ajouter les données JSON sous forme de chaîne
|
||||||
|
formData.append('data', JSON.stringify(jsonData));
|
||||||
formData.append('sepa_file', file);
|
formData.append('sepa_file', file);
|
||||||
|
|
||||||
// Appeler l'API pour uploader le fichier SEPA
|
// Appeler l'API pour uploader le fichier SEPA
|
||||||
@ -868,7 +875,7 @@ export default function Page({ params: { locale } }) {
|
|||||||
<img
|
<img
|
||||||
src={`${BASE_URL}${row.student.photo}`}
|
src={`${BASE_URL}${row.student.photo}`}
|
||||||
alt={`${row.student.first_name} ${row.student.last_name}`}
|
alt={`${row.student.first_name} ${row.student.last_name}`}
|
||||||
className="w-10 h-10 object-cover transition-transform duration-200 hover:scale-125 cursor-pointer"
|
className="w-10 h-10 object-cover transition-transform duration-200 hover:scale-125 cursor-pointer rounded-full"
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@ -23,10 +23,8 @@ export default function Page() {
|
|||||||
const csrfToken = useCsrfToken();
|
const csrfToken = useCsrfToken();
|
||||||
|
|
||||||
const handleAcceptRF = (data) => {
|
const handleAcceptRF = (data) => {
|
||||||
const { status, fusionParam } = data;
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('status', status); // Ajoute le statut
|
formData.append('data', JSON.stringify(data));
|
||||||
formData.append('fusion', fusionParam);
|
|
||||||
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
// Appeler l'API pour mettre à jour le RF
|
// Appeler l'API pour mettre à jour le RF
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { useSearchParams, useRouter } from 'next/navigation';
|
|||||||
import { useCsrfToken } from '@/context/CsrfContext';
|
import { useCsrfToken } from '@/context/CsrfContext';
|
||||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
import { FE_PARENTS_HOME_URL } from '@/utils/Url';
|
import { FE_PARENTS_HOME_URL } from '@/utils/Url';
|
||||||
import { editRegisterForm } from '@/app/actions/subscriptionAction';
|
import { editRegisterFormWithBinaryFile } from '@/app/actions/subscriptionAction';
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
@ -18,7 +18,11 @@ export default function Page() {
|
|||||||
|
|
||||||
const handleSubmit = async (data) => {
|
const handleSubmit = async (data) => {
|
||||||
try {
|
try {
|
||||||
const result = await editRegisterForm(studentId, data, csrfToken);
|
const result = await editRegisterFormWithBinaryFile(
|
||||||
|
studentId,
|
||||||
|
data,
|
||||||
|
csrfToken
|
||||||
|
);
|
||||||
logger.debug('Success:', result);
|
logger.debug('Success:', result);
|
||||||
router.push(FE_PARENTS_HOME_URL);
|
router.push(FE_PARENTS_HOME_URL);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -66,9 +66,12 @@ export default function ParentHomePage() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const jsonData = {
|
||||||
|
status: 3,
|
||||||
|
};
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
formData.append('data', JSON.stringify(jsonData));
|
||||||
formData.append('sepa_file', uploadedFile); // Ajoute le fichier SEPA
|
formData.append('sepa_file', uploadedFile); // Ajoute le fichier SEPA
|
||||||
formData.append('status', 3); // Statut à envoyer
|
|
||||||
|
|
||||||
editRegisterFormWithBinaryFile(uploadingStudentId, formData, csrfToken)
|
editRegisterFormWithBinaryFile(uploadingStudentId, formData, csrfToken)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
|
|||||||
@ -6,6 +6,9 @@ export default function FileUpload({
|
|||||||
selectionMessage,
|
selectionMessage,
|
||||||
onFileSelect,
|
onFileSelect,
|
||||||
uploadedFileName,
|
uploadedFileName,
|
||||||
|
existingFile,
|
||||||
|
required,
|
||||||
|
errorMsg,
|
||||||
}) {
|
}) {
|
||||||
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
|
||||||
@ -31,7 +34,10 @@ export default function FileUpload({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border p-4 rounded-md shadow-md">
|
<div className="border p-4 rounded-md shadow-md">
|
||||||
<h3 className="text-lg font-semibold mb-4">{`${selectionMessage}`}</h3>
|
<h3 className="text-lg font-semibold mb-4">
|
||||||
|
{`${selectionMessage}`}
|
||||||
|
{required && <span className="text-red-500 ml-1">*</span>}
|
||||||
|
</h3>
|
||||||
<div
|
<div
|
||||||
className="border-2 border-dashed border-gray-500 p-6 rounded-lg flex flex-col items-center justify-center cursor-pointer hover:border-emerald-500"
|
className="border-2 border-dashed border-gray-500 p-6 rounded-lg flex flex-col items-center justify-center cursor-pointer hover:border-emerald-500"
|
||||||
onClick={() => fileInputRef.current.click()} // Utilisation de la référence pour ouvrir l'explorateur
|
onClick={() => fileInputRef.current.click()} // Utilisation de la référence pour ouvrir l'explorateur
|
||||||
@ -52,10 +58,24 @@ export default function FileUpload({
|
|||||||
Déposez votre fichier ici
|
Déposez votre fichier ici
|
||||||
</p>
|
</p>
|
||||||
<p className="text-sm text-gray-500 mt-2">
|
<p className="text-sm text-gray-500 mt-2">
|
||||||
ou cliquez pour sélectionner un fichier PDF
|
ou cliquez pour sélectionner un fichier
|
||||||
</p>
|
</p>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Affichage du fichier existant */}
|
||||||
|
{existingFile && !localFileName && (
|
||||||
|
<div className="mt-4 flex items-center space-x-4 bg-gray-100 p-3 rounded-md shadow-sm">
|
||||||
|
<CloudUpload className="w-6 h-6 text-emerald-500" />
|
||||||
|
<p className="text-sm font-medium text-gray-800">
|
||||||
|
<span className="font-semibold">
|
||||||
|
{existingFile.split('/').pop()}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Affichage du fichier sélectionné */}
|
||||||
{localFileName && (
|
{localFileName && (
|
||||||
<div className="mt-4 flex items-center space-x-4 bg-gray-100 p-3 rounded-md shadow-sm">
|
<div className="mt-4 flex items-center space-x-4 bg-gray-100 p-3 rounded-md shadow-sm">
|
||||||
<CloudUpload className="w-6 h-6 text-emerald-500" />
|
<CloudUpload className="w-6 h-6 text-emerald-500" />
|
||||||
@ -64,6 +84,9 @@ export default function FileUpload({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Message d'erreur */}
|
||||||
|
{errorMsg && <p className="mt-2 text-sm text-red-600">{errorMsg}</p>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,8 @@ import {
|
|||||||
import {
|
import {
|
||||||
fetchRegistrationPaymentModes,
|
fetchRegistrationPaymentModes,
|
||||||
fetchTuitionPaymentModes,
|
fetchTuitionPaymentModes,
|
||||||
|
fetchRegistrationPaymentPlans,
|
||||||
|
fetchTuitionPaymentPlans,
|
||||||
} 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';
|
||||||
@ -53,13 +55,14 @@ export default function InscriptionFormShared({
|
|||||||
nationality: '',
|
nationality: '',
|
||||||
attending_physician: '',
|
attending_physician: '',
|
||||||
level: '',
|
level: '',
|
||||||
registration_payment: '',
|
photo: '',
|
||||||
tuition_payment: '',
|
|
||||||
});
|
});
|
||||||
const [guardians, setGuardians] = useState([]);
|
const [guardians, setGuardians] = useState([]);
|
||||||
|
|
||||||
const [registrationPaymentModes, setRegistrationPaymentModes] = useState([]);
|
const [registrationPaymentModes, setRegistrationPaymentModes] = useState([]);
|
||||||
const [tuitionPaymentModes, setTuitionPaymentModes] = useState([]);
|
const [tuitionPaymentModes, setTuitionPaymentModes] = useState([]);
|
||||||
|
const [registrationPaymentPlans, setRegistrationPaymentPlans] = useState([]);
|
||||||
|
const [tuitionPaymentPlans, setTuitionPaymentPlans] = useState([]);
|
||||||
|
|
||||||
// États pour la gestion des fichiers
|
// États pour la gestion des fichiers
|
||||||
const [uploadedFiles, setUploadedFiles] = useState([]);
|
const [uploadedFiles, setUploadedFiles] = useState([]);
|
||||||
@ -194,6 +197,12 @@ export default function InscriptionFormShared({
|
|||||||
|
|
||||||
// Fetch data for tuition payment modes
|
// Fetch data for tuition payment modes
|
||||||
handleTuitionPaymentModes();
|
handleTuitionPaymentModes();
|
||||||
|
|
||||||
|
// Fetch data for registration payment plans
|
||||||
|
handleRegistrationPaymentPlans();
|
||||||
|
|
||||||
|
// Fetch data for tuition payment plans
|
||||||
|
handleTuitionnPaymentPlans();
|
||||||
}
|
}
|
||||||
}, [selectedEstablishmentId]);
|
}, [selectedEstablishmentId]);
|
||||||
|
|
||||||
@ -223,6 +232,32 @@ export default function InscriptionFormShared({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRegistrationPaymentPlans = () => {
|
||||||
|
fetchRegistrationPaymentPlans(selectedEstablishmentId)
|
||||||
|
.then((data) => {
|
||||||
|
const activePaymentPlans = data.filter(
|
||||||
|
(mode) => mode.is_active === true
|
||||||
|
);
|
||||||
|
setRegistrationPaymentPlans(activePaymentPlans);
|
||||||
|
})
|
||||||
|
.catch((error) =>
|
||||||
|
logger.error('Error fetching registration payment plans:', error)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTuitionnPaymentPlans = () => {
|
||||||
|
fetchTuitionPaymentPlans(selectedEstablishmentId)
|
||||||
|
.then((data) => {
|
||||||
|
const activePaymentPlans = data.filter(
|
||||||
|
(mode) => mode.is_active === true
|
||||||
|
);
|
||||||
|
setTuitionPaymentPlans(activePaymentPlans);
|
||||||
|
})
|
||||||
|
.catch((error) =>
|
||||||
|
logger.error('Error fetching registration tuition plans:', error)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
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.');
|
||||||
@ -344,8 +379,12 @@ export default function InscriptionFormShared({
|
|||||||
status: isSepaPayment ? 8 : 3,
|
status: isSepaPayment ? 8 : 3,
|
||||||
tuition_payment: formData.tuition_payment,
|
tuition_payment: formData.tuition_payment,
|
||||||
registration_payment: formData.registration_payment,
|
registration_payment: formData.registration_payment,
|
||||||
|
tuition_payment_plan: formData.tuition_payment_plan,
|
||||||
|
registration_payment_plan: formData.registration_payment_plan,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log('jsonData : ', jsonData);
|
||||||
|
|
||||||
// Créer un objet FormData
|
// Créer un objet FormData
|
||||||
const formDataToSend = new FormData();
|
const formDataToSend = new FormData();
|
||||||
|
|
||||||
@ -450,6 +489,8 @@ export default function InscriptionFormShared({
|
|||||||
setFormData={setFormData}
|
setFormData={setFormData}
|
||||||
registrationPaymentModes={registrationPaymentModes}
|
registrationPaymentModes={registrationPaymentModes}
|
||||||
tuitionPaymentModes={tuitionPaymentModes}
|
tuitionPaymentModes={tuitionPaymentModes}
|
||||||
|
registrationPaymentPlans={registrationPaymentPlans}
|
||||||
|
tuitionPaymentPlans={tuitionPaymentPlans}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
setIsPageValid={setIsPage3Valid}
|
setIsPageValid={setIsPage3Valid}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import SelectChoice from '@/components/SelectChoice';
|
import SelectChoice from '@/components/SelectChoice';
|
||||||
|
import RadioList from '@/components/RadioList';
|
||||||
|
|
||||||
export default function PaymentMethodSelector({
|
export default function PaymentMethodSelector({
|
||||||
formData,
|
formData,
|
||||||
setFormData,
|
setFormData,
|
||||||
registrationPaymentModes,
|
registrationPaymentModes,
|
||||||
tuitionPaymentModes,
|
tuitionPaymentModes,
|
||||||
|
registrationPaymentPlans,
|
||||||
|
tuitionPaymentPlans,
|
||||||
errors,
|
errors,
|
||||||
setIsPageValid,
|
setIsPageValid,
|
||||||
}) {
|
}) {
|
||||||
@ -14,6 +17,7 @@ export default function PaymentMethodSelector({
|
|||||||
(field) => getLocalError(field) !== ''
|
(field) => getLocalError(field) !== ''
|
||||||
);
|
);
|
||||||
setIsPageValid(isValid);
|
setIsPageValid(isValid);
|
||||||
|
console.log('formdata : ', formData);
|
||||||
}, [formData, setIsPageValid]);
|
}, [formData, setIsPageValid]);
|
||||||
|
|
||||||
const paymentModesOptions = [
|
const paymentModesOptions = [
|
||||||
@ -23,19 +27,31 @@ export default function PaymentMethodSelector({
|
|||||||
{ id: 4, name: 'Espèce' },
|
{ id: 4, name: 'Espèce' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const paymentPlansOptions = [
|
||||||
|
{ id: 1, name: '1 fois' },
|
||||||
|
{ id: 3, name: '3 fois' },
|
||||||
|
{ id: 10, name: '10 fois' },
|
||||||
|
{ id: 12, name: '12 fois' },
|
||||||
|
];
|
||||||
|
|
||||||
const getError = (field) => {
|
const getError = (field) => {
|
||||||
return errors?.student?.[field]?.[0];
|
return errors?.student?.[field]?.[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
const getLocalError = (field) => {
|
const getLocalError = (field) => {
|
||||||
if (
|
if (
|
||||||
// Student Form
|
|
||||||
(field === 'registration_payment' &&
|
(field === 'registration_payment' &&
|
||||||
(!formData.registration_payment ||
|
(!formData.registration_payment ||
|
||||||
String(formData.registration_payment).trim() === '')) ||
|
String(formData.registration_payment).trim() === '')) ||
|
||||||
(field === 'tuition_payment' &&
|
(field === 'tuition_payment' &&
|
||||||
(!formData.tuition_payment ||
|
(!formData.tuition_payment ||
|
||||||
String(formData.tuition_payment).trim() === ''))
|
String(formData.tuition_payment).trim() === '')) ||
|
||||||
|
(field === 'registration_payment_plan' &&
|
||||||
|
(!formData.registration_payment_plan ||
|
||||||
|
String(formData.registration_payment_plan).trim() === '')) ||
|
||||||
|
(field === 'tuition_payment_plan' &&
|
||||||
|
(!formData.tuition_payment_plan ||
|
||||||
|
String(formData.tuition_payment_plan).trim() === ''))
|
||||||
) {
|
) {
|
||||||
return 'Champs requis';
|
return 'Champs requis';
|
||||||
}
|
}
|
||||||
@ -48,13 +64,12 @@ export default function PaymentMethodSelector({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{/* Frais d'inscription */}
|
||||||
<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 */}
|
|
||||||
<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 */}
|
|
||||||
<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>{' '}
|
<strong className="text-gray-900">Montant :</strong>{' '}
|
||||||
@ -80,15 +95,42 @@ export default function PaymentMethodSelector({
|
|||||||
getLocalError('registration_payment')
|
getLocalError('registration_payment')
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<RadioList
|
||||||
|
sectionLabel="Choisissez une option"
|
||||||
|
required
|
||||||
|
items={paymentPlansOptions
|
||||||
|
.filter((option) =>
|
||||||
|
registrationPaymentPlans.some(
|
||||||
|
(plan) => plan.frequency === option.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.map((option) => ({
|
||||||
|
id: option.id,
|
||||||
|
label: option.name,
|
||||||
|
}))}
|
||||||
|
formData={{
|
||||||
|
...formData,
|
||||||
|
registration_payment_plan: parseInt(
|
||||||
|
formData.registration_payment_plan,
|
||||||
|
10
|
||||||
|
), // S'assurer que la valeur est un entier
|
||||||
|
}}
|
||||||
|
handleChange={(e) => {
|
||||||
|
const value = parseInt(e.target.value, 10);
|
||||||
|
onChange('registration_payment_plan', value); // Convertir la valeur en entier
|
||||||
|
}}
|
||||||
|
fieldName="registration_payment_plan"
|
||||||
|
className="mt-4"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Frais de scolarité */}
|
||||||
<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 */}
|
|
||||||
<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 */}
|
|
||||||
<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>{' '}
|
<strong className="text-gray-900">Montant :</strong>{' '}
|
||||||
@ -113,6 +155,26 @@ export default function PaymentMethodSelector({
|
|||||||
getError('tuition_payment') || getLocalError('tuition_payment')
|
getError('tuition_payment') || getLocalError('tuition_payment')
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<RadioList
|
||||||
|
sectionLabel="Choisissez une option"
|
||||||
|
items={paymentPlansOptions
|
||||||
|
.filter((option) =>
|
||||||
|
tuitionPaymentPlans.some((plan) => plan.frequency === option.id)
|
||||||
|
)
|
||||||
|
.map((option) => ({
|
||||||
|
id: option.id,
|
||||||
|
label: option.name,
|
||||||
|
}))}
|
||||||
|
formData={formData}
|
||||||
|
handleChange={(e) => onChange('tuition_payment_plan', e.target.value)}
|
||||||
|
fieldName="tuition_payment_plan"
|
||||||
|
className="mt-4"
|
||||||
|
errorMsg={
|
||||||
|
getError('tuition_payment_plan') ||
|
||||||
|
getLocalError('tuition_payment_plan')
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -51,6 +51,8 @@ export default function StudentInfoForm({
|
|||||||
level: data?.student?.level || '',
|
level: data?.student?.level || '',
|
||||||
registration_payment: data?.registration_payment || '',
|
registration_payment: data?.registration_payment || '',
|
||||||
tuition_payment: data?.tuition_payment || '',
|
tuition_payment: data?.tuition_payment || '',
|
||||||
|
registration_payment_plan: data?.registration_payment_plan || '',
|
||||||
|
tuition_payment_plan: data?.tuition_payment_plan || '',
|
||||||
totalRegistrationFees: data?.totalRegistrationFees,
|
totalRegistrationFees: data?.totalRegistrationFees,
|
||||||
totalTuitionFees: data?.totalTuitionFees,
|
totalTuitionFees: data?.totalTuitionFees,
|
||||||
});
|
});
|
||||||
@ -96,7 +98,8 @@ export default function StudentInfoForm({
|
|||||||
(!formData.attending_physician ||
|
(!formData.attending_physician ||
|
||||||
formData.attending_physician.trim() === '')) ||
|
formData.attending_physician.trim() === '')) ||
|
||||||
(field === 'level' &&
|
(field === 'level' &&
|
||||||
(!formData.level || String(formData.level).trim() === ''))
|
(!formData.level || String(formData.level).trim() === '')) ||
|
||||||
|
(field === 'photo' && !formData.photo)
|
||||||
) {
|
) {
|
||||||
return 'Champs requis';
|
return 'Champs requis';
|
||||||
}
|
}
|
||||||
@ -230,6 +233,9 @@ export default function StudentInfoForm({
|
|||||||
<FileUpload
|
<FileUpload
|
||||||
selectionMessage="Sélectionnez une photo à uploader"
|
selectionMessage="Sélectionnez une photo à uploader"
|
||||||
onFileSelect={(file) => handlePhotoUpload(file)}
|
onFileSelect={(file) => handlePhotoUpload(file)}
|
||||||
|
existingFile={formData.photo}
|
||||||
|
required
|
||||||
|
errorMsg={getError('photo') || getLocalError('photo')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -7,9 +7,17 @@ const RadioList = ({
|
|||||||
fieldName,
|
fieldName,
|
||||||
icon: Icon,
|
icon: Icon,
|
||||||
className,
|
className,
|
||||||
|
sectionLabel,
|
||||||
|
required,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className={`mb-4 ${className}`}>
|
<div className={`mb-4 ${className}`}>
|
||||||
|
{sectionLabel && (
|
||||||
|
<h3 className="text-lg font-semibold text-gray-800 mb-2">
|
||||||
|
{sectionLabel}
|
||||||
|
{required && <span className="text-red-500 ml-1">*</span>}
|
||||||
|
</h3>
|
||||||
|
)}
|
||||||
<div className="grid grid-cols-1 gap-4">
|
<div className="grid grid-cols-1 gap-4">
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
<div key={item.id} className="flex items-center">
|
<div key={item.id} className="flex items-center">
|
||||||
|
|||||||
Reference in New Issue
Block a user