mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: Ajout de la photo pour le dossier de l'élève + correction
sauvegarde des datas des responsables
This commit is contained in:
@ -42,7 +42,7 @@ export default function FileUpload({
|
||||
{/* Icône de cloud */}
|
||||
<input
|
||||
type="file"
|
||||
accept=".pdf"
|
||||
accept=".pdf, .png, .jpg, .jpeg, .gif, .bmp"
|
||||
onChange={handleFileChange}
|
||||
className="hidden"
|
||||
ref={fileInputRef} // Attachement de la référence
|
||||
|
||||
@ -43,6 +43,7 @@ export default function InscriptionFormShared({
|
||||
// États pour gérer les données du formulaire
|
||||
const [formData, setFormData] = useState({
|
||||
id: '',
|
||||
photo: null,
|
||||
last_name: '',
|
||||
first_name: '',
|
||||
address: '',
|
||||
@ -55,7 +56,6 @@ export default function InscriptionFormShared({
|
||||
registration_payment: '',
|
||||
tuition_payment: '',
|
||||
});
|
||||
|
||||
const [guardians, setGuardians] = useState([]);
|
||||
|
||||
const [registrationPaymentModes, setRegistrationPaymentModes] = useState([]);
|
||||
@ -333,10 +333,12 @@ export default function InscriptionFormShared({
|
||||
// Vérifier si le mode de paiement sélectionné est un prélèvement SEPA
|
||||
const isSepaPayment =
|
||||
formData.registration_payment === '1' || formData.tuition_payment === '1';
|
||||
const data = {
|
||||
|
||||
// Préparer les données JSON
|
||||
const jsonData = {
|
||||
student: {
|
||||
...formData,
|
||||
guardians,
|
||||
guardians: guardians,
|
||||
},
|
||||
establishment: selectedEstablishmentId,
|
||||
status: isSepaPayment ? 8 : 3,
|
||||
@ -344,7 +346,19 @@ export default function InscriptionFormShared({
|
||||
registration_payment: formData.registration_payment,
|
||||
};
|
||||
|
||||
onSubmit(data);
|
||||
// Créer un objet FormData
|
||||
const formDataToSend = new FormData();
|
||||
|
||||
// Ajouter les données JSON sous forme de chaîne
|
||||
formDataToSend.append('data', JSON.stringify(jsonData));
|
||||
|
||||
// Ajouter la photo si elle est présente
|
||||
if (formData.photo) {
|
||||
formDataToSend.append('photo', formData.photo);
|
||||
}
|
||||
|
||||
// Appeler la fonction onSubmit avec les données FormData
|
||||
onSubmit(formDataToSend);
|
||||
};
|
||||
|
||||
const handleNextPage = () => {
|
||||
|
||||
@ -4,6 +4,7 @@ import React, { useEffect } from 'react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { Trash2, Plus, Users } from 'lucide-react';
|
||||
import SectionHeader from '@/components/SectionHeader';
|
||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||
|
||||
export default function ResponsableInputFields({
|
||||
guardians,
|
||||
@ -12,6 +13,7 @@ export default function ResponsableInputFields({
|
||||
setIsPageValid,
|
||||
}) {
|
||||
const t = useTranslations('ResponsableInputFields');
|
||||
const { selectedEstablishmentId } = useEstablishment();
|
||||
|
||||
useEffect(() => {
|
||||
const isValid =
|
||||
@ -38,7 +40,7 @@ export default function ResponsableInputFields({
|
||||
(field === 'first_name' &&
|
||||
(!guardians[index].first_name ||
|
||||
guardians[index].first_name.trim() === '')) ||
|
||||
(field === 'email' &&
|
||||
(field === 'associated_profile_email' &&
|
||||
(!guardians[index].associated_profile_email ||
|
||||
guardians[index].associated_profile_email.trim() === '')) ||
|
||||
(field === 'birth_date' &&
|
||||
@ -56,16 +58,45 @@ export default function ResponsableInputFields({
|
||||
};
|
||||
|
||||
const onGuardiansChange = (id, field, value) => {
|
||||
const updatedGuardians = guardians.map((guardian) =>
|
||||
guardian.id === id ? { ...guardian, [field]: value } : guardian
|
||||
);
|
||||
const updatedGuardians = guardians.map((guardian) => {
|
||||
if (guardian.id === id) {
|
||||
const updatedGuardian = { ...guardian, [field]: value };
|
||||
|
||||
// Synchroniser profile_data.email et profile_data.username avec associated_profile_email
|
||||
if (field === 'associated_profile_email') {
|
||||
updatedGuardian.profile_role_data.profile_data.email = value;
|
||||
updatedGuardian.profile_role_data.profile_data.username = value;
|
||||
}
|
||||
|
||||
return updatedGuardian;
|
||||
}
|
||||
return guardian;
|
||||
});
|
||||
|
||||
setGuardians(updatedGuardians);
|
||||
};
|
||||
|
||||
const addGuardian = () => {
|
||||
setGuardians([
|
||||
...guardians,
|
||||
{ id: Date.now(), name: '', email: '', phone: '' },
|
||||
{
|
||||
profile_role_data: {
|
||||
establishment: selectedEstablishmentId,
|
||||
role_type: 2,
|
||||
is_active: false,
|
||||
profile_data: {
|
||||
email: '',
|
||||
password: 'Provisoire01!',
|
||||
username: '',
|
||||
},
|
||||
},
|
||||
last_name: '',
|
||||
first_name: '',
|
||||
birth_date: '',
|
||||
address: '',
|
||||
phone: '',
|
||||
profession: '',
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
@ -143,7 +174,8 @@ export default function ResponsableInputFields({
|
||||
}}
|
||||
required
|
||||
errorMsg={
|
||||
getError(index, 'email') || getLocalError(index, 'email')
|
||||
getError(index, 'associated_profile_email') ||
|
||||
getLocalError(index, 'associated_profile_email')
|
||||
}
|
||||
/>
|
||||
<InputPhone
|
||||
|
||||
@ -6,6 +6,7 @@ import { fetchRegisterForm } from '@/app/actions/subscriptionAction';
|
||||
import logger from '@/utils/logger';
|
||||
import SectionHeader from '@/components/SectionHeader';
|
||||
import { User } from 'lucide-react';
|
||||
import FileUpload from '@/components/FileUpload';
|
||||
|
||||
const levels = [
|
||||
{ value: '1', label: 'TPS - Très Petite Section' },
|
||||
@ -38,6 +39,7 @@ export default function StudentInfoForm({
|
||||
|
||||
setFormData({
|
||||
id: data?.student?.id || '',
|
||||
photo: data?.student?.photo || null,
|
||||
last_name: data?.student?.last_name || '',
|
||||
first_name: data?.student?.first_name || '',
|
||||
address: data?.student?.address || '',
|
||||
@ -110,6 +112,16 @@ export default function StudentInfoForm({
|
||||
}
|
||||
};
|
||||
|
||||
const handlePhotoUpload = (file) => {
|
||||
if (file) {
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
photo: file,
|
||||
}));
|
||||
logger.debug('Photo sélectionnée :', file.name);
|
||||
}
|
||||
};
|
||||
|
||||
// Affichage du loader pendant le chargement
|
||||
if (isLoading) return <Loader />;
|
||||
|
||||
@ -208,54 +220,18 @@ export default function StudentInfoForm({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* <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>
|
||||
<ResponsableInputFields
|
||||
guardians={guardians}
|
||||
onGuardiansChange={(id, field, value) => {
|
||||
const updatedGuardians = guardians.map((resp) =>
|
||||
resp.id === id ? { ...resp, [field]: value } : resp
|
||||
);
|
||||
setGuardians(updatedGuardians);
|
||||
}}
|
||||
addGuardian={(e) => {
|
||||
e.preventDefault();
|
||||
setGuardians([...guardians, { id: Date.now() }]);
|
||||
}}
|
||||
deleteGuardian={(index) => {
|
||||
const newArray = [...guardians];
|
||||
newArray.splice(index, 1);
|
||||
setGuardians(newArray);
|
||||
}}
|
||||
errors={errors?.student?.guardians || []}
|
||||
{/* Section pour l'upload des fichiers */}
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200 mt-6">
|
||||
<SectionHeader
|
||||
icon={User}
|
||||
title={`Photo de l'élève`}
|
||||
description={`Ajoutez une photo de votre enfant`}
|
||||
/>
|
||||
<FileUpload
|
||||
selectionMessage="Sélectionnez une photo à uploader"
|
||||
onFileSelect={(file) => handlePhotoUpload(file)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<PaymentMethodSelector
|
||||
formData={formData}
|
||||
title="Frais d'inscription"
|
||||
name="registration_payment"
|
||||
onChange={onChange}
|
||||
selected={formData.registration_payment}
|
||||
paymentModes={registrationPaymentModes}
|
||||
paymentModesOptions={paymentModesOptions}
|
||||
amount={formData.totalRegistrationFees}
|
||||
getError={getError}
|
||||
getLocalError={getLocalError}
|
||||
/>
|
||||
|
||||
<PaymentMethodSelector
|
||||
formData={formData}
|
||||
title="Frais de scolarité"
|
||||
name="tuition_payment"
|
||||
onChange={onChange}
|
||||
selected={formData.tuition_payment}
|
||||
paymentModes={tuitionPaymentModes}
|
||||
paymentModesOptions={paymentModesOptions}
|
||||
amount={formData.totalTuitionFees}
|
||||
getError={getError}
|
||||
getLocalError={getLocalError}
|
||||
/> */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import logger from '@/utils/logger';
|
||||
import MultiSelect from '@/components/MultiSelect'; // Import du composant MultiSelect
|
||||
import { useCsrfToken } from '@/context/CsrfContext';
|
||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||
import Popup from '@/components/Popup';
|
||||
|
||||
export default function FileUploadDocuSeal({
|
||||
handleCreateTemplateMaster,
|
||||
@ -24,6 +25,9 @@ export default function FileUploadDocuSeal({
|
||||
const [selectedGroups, setSelectedGroups] = useState([]);
|
||||
const [guardianDetails, setGuardianDetails] = useState([]);
|
||||
|
||||
const [popupVisible, setPopupVisible] = useState(false);
|
||||
const [popupMessage, setPopupMessage] = useState('');
|
||||
|
||||
const csrfToken = useCsrfToken();
|
||||
|
||||
const { selectedEstablishmentId } = useEstablishment();
|
||||
@ -84,6 +88,17 @@ export default function FileUploadDocuSeal({
|
||||
};
|
||||
|
||||
const handleSubmit = (data) => {
|
||||
// Vérifier si au moins un champ a la propriété "required" à true
|
||||
const hasRequiredField = data.fields.some(
|
||||
(field) => field.required === true
|
||||
);
|
||||
|
||||
if (!hasRequiredField) {
|
||||
setPopupMessage('Veuillez définir au moins un champ comme requis.');
|
||||
setPopupVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const is_required = data.fields.length > 0;
|
||||
if (fileToEdit) {
|
||||
logger.debug('Modification du template master:', templateMaster?.id);
|
||||
@ -139,6 +154,13 @@ export default function FileUploadDocuSeal({
|
||||
|
||||
return (
|
||||
<div className="h-full flex flex-col mt-4 space-y-6">
|
||||
<Popup
|
||||
visible={popupVisible}
|
||||
message={popupMessage}
|
||||
onConfirm={() => setPopupVisible(false)}
|
||||
onCancel={() => setPopupVisible(false)}
|
||||
uniqueConfirmButton={true}
|
||||
/>
|
||||
{/* Contenu principal */}
|
||||
<div className="grid grid-cols-10 gap-6 items-start">
|
||||
{/* Sélection des groupes */}
|
||||
|
||||
Reference in New Issue
Block a user