// Import des dépendances nécessaires import React, { useState, useEffect } from 'react'; import Button from '@/components/Button'; import DjangoCSRFToken from '@/components/DjangoCSRFToken'; import { fetchSchoolFileTemplatesFromRegistrationFiles, fetchParentFileTemplatesFromRegistrationFiles, } from '@/app/actions/subscriptionAction'; import { downloadTemplate, editRegistrationSchoolFileTemplates, editRegistrationParentFileTemplates, } from '@/app/actions/registerFileGroupAction'; import { fetchRegistrationPaymentModes, fetchTuitionPaymentModes, } from '@/app/actions/schoolAction'; import { BASE_URL } from '@/utils/Url'; import logger from '@/utils/logger'; import FilesToUpload from '@/components/Inscription/FilesToUpload'; 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'; import { CheckCircle, Loader2 } from 'lucide-react'; /** * Composant de formulaire d'inscription partagé * @param {string} studentId - ID de l'étudiant * @param {string} csrfToken - Token CSRF pour la sécurité * @param {function} onSubmit - Fonction de soumission du formulaire * @param {string} cancelUrl - URL de redirection en cas d'annulation * @param {object} errors - Erreurs de validation du formulaire */ export default function InscriptionFormShared({ studentId, csrfToken, selectedEstablishmentId, onSubmit, errors = {}, // Nouvelle prop pour les erreurs }) { // États pour gérer les données du formulaire const [formData, setFormData] = useState({ id: '', last_name: '', first_name: '', address: '', birth_date: '', birth_place: '', birth_postal_code: '', nationality: '', attending_physician: '', level: '', registration_payment: '', tuition_payment: '', }); const [guardians, setGuardians] = useState([]); const [registrationPaymentModes, setRegistrationPaymentModes] = useState([]); const [tuitionPaymentModes, setTuitionPaymentModes] = useState([]); // États pour la gestion des fichiers const [uploadedFiles, setUploadedFiles] = useState([]); const [schoolFileTemplates, setSchoolFileTemplates] = useState([]); const [parentFileTemplates, setParentFileTemplates] = useState([]); 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); // État pour suivre l'index du fichier en cours const [currentTemplateIndex, setCurrentTemplateIndex] = useState(0); useEffect(() => { // Trouver le premier template non signé const firstUnsignedIndex = schoolFileTemplates.findIndex( (template) => template.file === null ); // Mettre à jour l'index du template actuel if (firstUnsignedIndex !== -1) { setCurrentTemplateIndex(firstUnsignedIndex); } else { // Si tous les templates sont signés, définir un index hors limites setCurrentTemplateIndex(schoolFileTemplates.length); } }, [schoolFileTemplates]); useEffect(() => { // Vérifier si tous les templates ont leur champ "file" différent de null const allSigned = schoolFileTemplates.every( (template) => template.file !== null ); // Mettre à jour isPage4Valid en fonction de cette condition setIsPage4Valid(allSigned); if (allSigned) { setCurrentTemplateIndex(0); } }, [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é."); return; } downloadTemplate(template.slug) .then((data) => fetch(data)) .then((response) => response.blob()) .then((blob) => { const file = new File([blob], `${template.name}.pdf`, { type: blob.type, }); const updateData = new FormData(); updateData.append('file', file); return editRegistrationSchoolFileTemplates( template.id, updateData, csrfToken ); }) .then((data) => { logger.debug('Template mis à jour avec succès :', data); // Mettre à jour l'état local de schoolFileTemplates setSchoolFileTemplates((prevTemplates) => prevTemplates.map((t, i) => i === index ? { ...t, file: data.file } : t ) ); }) .catch((error) => { logger.error('Erreur lors de la mise à jour du template :', error); }); }; useEffect(() => { fetchSchoolFileTemplatesFromRegistrationFiles(studentId).then((data) => { setSchoolFileTemplates(data); }); fetchParentFileTemplatesFromRegistrationFiles(studentId).then((data) => { setParentFileTemplates(data); // Initialiser uploadedFiles avec uniquement les fichiers dont `file` n'est pas null const filteredFiles = data .filter((item) => item.file !== null) .map((item) => ({ id: item.id, fileName: item.file, })); setUploadedFiles(filteredFiles); }); if (selectedEstablishmentId) { // Fetch data for registration payment modes handleRegistrationPaymentModes(); // Fetch data for tuition payment modes handleTuitionPaymentModes(); } }, [selectedEstablishmentId]); const handleRegistrationPaymentModes = () => { fetchRegistrationPaymentModes(selectedEstablishmentId) .then((data) => { const activePaymentModes = data.filter( (mode) => mode.is_active === true ); setRegistrationPaymentModes(activePaymentModes); }) .catch((error) => logger.error('Error fetching registration payment modes:', error) ); }; const handleTuitionPaymentModes = () => { fetchTuitionPaymentModes(selectedEstablishmentId) .then((data) => { const activePaymentModes = data.filter( (mode) => mode.is_active === true ); setTuitionPaymentModes(activePaymentModes); }) .catch((error) => logger.error('Error fetching tuition payment modes:', error) ); }; const handleFileUpload = (file, selectedFile) => { if (!file || !selectedFile) { logger.error('Données manquantes pour le téléversement.'); return Promise.reject( new Error('Données manquantes pour le téléversement.') ); } const updateData = new FormData(); updateData.append('file', file); return editRegistrationParentFileTemplates( selectedFile.id, updateData, csrfToken ) .then((response) => { logger.debug('Template mis à jour avec succès :', response); setUploadedFiles((prev) => { const updatedFiles = prev.map((uploadedFile) => uploadedFile.id === selectedFile.id ? { ...uploadedFile, fileName: response.data.file } // Met à jour le fichier téléversé : uploadedFile ); // Si le fichier n'existe pas encore, l'ajouter if (!updatedFiles.find((file) => file.id === selectedFile.id)) { updatedFiles.push({ id: selectedFile.id, fileName: response.data.file, }); } 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) => { logger.error('Erreur lors de la mise à jour du fichier :', error); throw error; // Relancer l'erreur pour que l'appelant puisse la capturer }); }; const handleDeleteFile = (templateId) => { const fileToDelete = uploadedFiles.find( (file) => parseInt(file.id) === templateId && file.fileName ); if (!fileToDelete) { logger.error('Aucun fichier trouvé pour suppression.'); return; } // Créer un FormData avec un champ vide pour "file" const updateData = new FormData(); updateData.append('file', ''); // Envoyer chaine vide pour indiquer qu'aucun fichier n'est uploadé return editRegistrationParentFileTemplates( templateId, updateData, csrfToken ) .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) => uploadedFile.id === templateId ? { ...uploadedFile, fileName: null, fileUrl: null } // Réinitialiser les champs liés au fichier : 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) => { logger.error( 'Erreur lors de la suppression du fichier dans la base :', error ); throw error; }); }; // Soumission du formulaire const handleSubmit = (e) => { e.preventDefault(); const data = { student: { ...formData, guardians, }, establishment: selectedEstablishmentId, status: 3, tuition_payment: formData.tuition_payment, registration_payment: formData.registration_payment, }; onSubmit(data); }; const handleNextPage = () => { setCurrentPage(currentPage + 1); }; const handlePreviousPage = () => { setCurrentPage(currentPage - 1); }; const stepTitles = { 1: 'Elève', 2: 'Responsables légaux', 3: 'Modalités de paiement', 4: 'Formulaires à signer', 5: 'Pièces à fournir', }; const steps = [ 'Élève', 'Responsable', 'Paiement', 'Formulaires', 'Documents parent', ]; const isStepValid = (stepNumber) => { switch (stepNumber) { case 1: return isPage1Valid; case 2: return isPage2Valid; case 3: return isPage3Valid; case 4: return isPage4Valid; case 5: return isPage5Valid; default: return false; } }; // Rendu du composant return (
{/* Page 1 : Informations sur l'élève */} {currentPage === 1 && ( )} {/* Page 2 : Informations sur les responsables légaux */} {currentPage === 2 && ( )} {/* Page 3 : Informations sur les modalités de paiement */} {currentPage === 3 && ( <> )} {/* Pages suivantes : Section Fichiers d'inscription */} {currentPage === 4 && (
{/* Liste des états de signature */}

Documents

    {schoolFileTemplates.map((template, index) => (
  • setCurrentTemplateIndex(index)} // Mettre à jour l'index du template actuel > {template.file !== null ? ( ) : ( )} {template.name || 'Document sans nom'}
  • ))}
{/* Affichage du fichier actuel */}
{currentTemplateIndex < schoolFileTemplates.length && (

{schoolFileTemplates[currentTemplateIndex].name || 'Document sans nom'}

{schoolFileTemplates[currentTemplateIndex].description || 'Aucune description disponible pour ce document.'}

{schoolFileTemplates[currentTemplateIndex].file === null ? ( handleTemplateSigned(currentTemplateIndex) } /> ) : (