mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 07:53:23 +00:00
feat: Gestion de la sauvegarde du fichier d'inscription / affichage du
fichier avec le bon nom / possibilité de refuser un DI
This commit is contained in:
@ -44,6 +44,11 @@
|
|||||||
"from": "ENVOYE",
|
"from": "ENVOYE",
|
||||||
"to": "ARCHIVE"
|
"to": "ARCHIVE"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "refuseDI",
|
||||||
|
"from": "EN_VALIDATION",
|
||||||
|
"to": "ENVOYE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "valideDI",
|
"name": "valideDI",
|
||||||
"from": "EN_VALIDATION",
|
"from": "EN_VALIDATION",
|
||||||
|
|||||||
@ -16,7 +16,9 @@ from enum import Enum
|
|||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
from rest_framework.parsers import JSONParser
|
from rest_framework.parsers import JSONParser
|
||||||
import pymupdf
|
from PyPDF2 import PdfMerger
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
|
||||||
def recupereListeFichesInscription():
|
def recupereListeFichesInscription():
|
||||||
"""
|
"""
|
||||||
@ -96,23 +98,29 @@ def merge_files_pdf(filenames, output_filename):
|
|||||||
Fusionne plusieurs fichiers PDF en un seul document.
|
Fusionne plusieurs fichiers PDF en un seul document.
|
||||||
Vérifie l'existence des fichiers sources avant la fusion.
|
Vérifie l'existence des fichiers sources avant la fusion.
|
||||||
"""
|
"""
|
||||||
merger = pymupdf.open()
|
merger = PdfMerger()
|
||||||
valid_files = []
|
valid_files = []
|
||||||
|
|
||||||
# Vérifier l'existence des fichiers et ne garder que ceux qui existent
|
# Vérifier l'existence des fichiers et ne garder que ceux qui existent
|
||||||
|
print(f'filenames : {filenames}')
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
|
print(f'check exists filename : {filename}')
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
|
print(f'append filename : {filename}')
|
||||||
valid_files.append(filename)
|
valid_files.append(filename)
|
||||||
|
|
||||||
# Fusionner les fichiers valides
|
if not valid_files:
|
||||||
|
raise FileNotFoundError("Aucun fichier valide à fusionner.")
|
||||||
|
|
||||||
|
# Ajouter les fichiers valides au merger
|
||||||
for filename in valid_files:
|
for filename in valid_files:
|
||||||
merger.insert_file(filename)
|
merger.append(filename)
|
||||||
|
|
||||||
# S'assurer que le dossier de destination existe
|
# S'assurer que le dossier de destination existe
|
||||||
os.makedirs(os.path.dirname(output_filename), exist_ok=True)
|
os.makedirs(os.path.dirname(output_filename), exist_ok=True)
|
||||||
|
|
||||||
# Sauvegarder le fichier fusionné
|
# Sauvegarder le fichier fusionné
|
||||||
merger.save(output_filename)
|
merger.write(output_filename)
|
||||||
merger.close()
|
merger.close()
|
||||||
|
|
||||||
return output_filename
|
return output_filename
|
||||||
@ -134,6 +142,11 @@ def rfToPDF(registerForm, filename):
|
|||||||
# Générer le PDF
|
# Générer le PDF
|
||||||
pdf = renderers.render_to_pdf('pdfs/dossier_inscription.html', data)
|
pdf = renderers.render_to_pdf('pdfs/dossier_inscription.html', data)
|
||||||
|
|
||||||
|
# Vérifier si un fichier avec le même nom existe déjà et le supprimer
|
||||||
|
if registerForm.registration_file and os.path.exists(registerForm.registration_file.path):
|
||||||
|
os.remove(registerForm.registration_file.path)
|
||||||
|
registerForm.registration_file.delete(save=False)
|
||||||
|
|
||||||
# Écrire le fichier directement
|
# Écrire le fichier directement
|
||||||
with open(filename, 'wb') as f:
|
with open(filename, 'wb') as f:
|
||||||
f.write(pdf.content)
|
f.write(pdf.content)
|
||||||
@ -146,4 +159,16 @@ def rfToPDF(registerForm, filename):
|
|||||||
save=True
|
save=True
|
||||||
)
|
)
|
||||||
|
|
||||||
return registerForm.registration_file
|
return filename
|
||||||
|
|
||||||
|
def delete_registration_files(registerForm):
|
||||||
|
"""
|
||||||
|
Supprime le fichier et le dossier associés à un RegistrationForm.
|
||||||
|
"""
|
||||||
|
base_dir = f"registration_files/dossier_rf_{registerForm.pk}"
|
||||||
|
if registerForm.registration_file and os.path.exists(registerForm.registration_file.path):
|
||||||
|
os.remove(registerForm.registration_file.path)
|
||||||
|
registerForm.registration_file.delete(save=False)
|
||||||
|
|
||||||
|
if os.path.exists(base_dir):
|
||||||
|
shutil.rmtree(base_dir)
|
||||||
@ -4,10 +4,12 @@ from rest_framework.views import APIView
|
|||||||
from drf_yasg.utils import swagger_auto_schema
|
from drf_yasg.utils import swagger_auto_schema
|
||||||
from drf_yasg import openapi
|
from drf_yasg import openapi
|
||||||
|
|
||||||
from Subscriptions.models import Guardian, Student
|
from Subscriptions.models import Guardian, Student, RegistrationForm
|
||||||
from Auth.models import ProfileRole
|
from Auth.models import ProfileRole
|
||||||
from N3wtSchool import bdd
|
from N3wtSchool import bdd
|
||||||
|
|
||||||
|
import Subscriptions.util as util
|
||||||
|
|
||||||
class GuardianView(APIView):
|
class GuardianView(APIView):
|
||||||
"""
|
"""
|
||||||
Gestion des responsables légaux.
|
Gestion des responsables légaux.
|
||||||
@ -74,6 +76,16 @@ class DissociateGuardianView(APIView):
|
|||||||
# Supprimer le guardian
|
# Supprimer le guardian
|
||||||
guardian.delete()
|
guardian.delete()
|
||||||
|
|
||||||
|
# Récupérer le RegistrationForm associé au Student
|
||||||
|
registerForm = bdd.getObject(RegistrationForm, "student__id", student_id)
|
||||||
|
if registerForm:
|
||||||
|
# Réinitialiser le statut en "Créé"
|
||||||
|
registerForm.status = RegistrationForm.RegistrationFormStatus.RF_CREATED
|
||||||
|
registerForm.save()
|
||||||
|
|
||||||
|
# Supprimer le fichier et le dossier associés
|
||||||
|
util.delete_registration_files(registerForm)
|
||||||
|
|
||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{
|
{
|
||||||
"message": f"Le guardian {guardian.last_name} {guardian.first_name} a été dissocié de l'étudiant {student.last_name} {student.first_name}.",
|
"message": f"Le guardian {guardian.last_name} {guardian.first_name} a été dissocié de l'étudiant {student.last_name} {student.first_name}.",
|
||||||
|
|||||||
@ -238,7 +238,7 @@ class RegisterFormWithIdView(APIView):
|
|||||||
if _status == RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW:
|
if _status == RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW:
|
||||||
try:
|
try:
|
||||||
# Génération de la fiche d'inscription au format PDF
|
# Génération de la fiche d'inscription au format PDF
|
||||||
base_dir = f"data/registration_files/dossier_rf_{registerForm.pk}"
|
base_dir = f"registration_files/dossier_rf_{registerForm.pk}"
|
||||||
os.makedirs(base_dir, exist_ok=True)
|
os.makedirs(base_dir, exist_ok=True)
|
||||||
|
|
||||||
# Fichier PDF initial
|
# Fichier PDF initial
|
||||||
@ -248,11 +248,13 @@ class RegisterFormWithIdView(APIView):
|
|||||||
|
|
||||||
# Récupération des fichiers d'inscription
|
# Récupération des fichiers d'inscription
|
||||||
fileNames = RegistrationTemplate.get_files_from_rf(registerForm.pk)
|
fileNames = RegistrationTemplate.get_files_from_rf(registerForm.pk)
|
||||||
|
|
||||||
if registerForm.registration_file:
|
if registerForm.registration_file:
|
||||||
fileNames.insert(0, registerForm.registration_file.path)
|
fileNames.insert(0, registerForm.registration_file.path)
|
||||||
|
|
||||||
# Création du fichier PDF Fusionné
|
# Création du fichier PDF Fusionné
|
||||||
merged_pdf = f"{base_dir}/dossier_complet_{registerForm.pk}.pdf"
|
merged_pdf = f"{base_dir}/dossier_complet_{registerForm.pk}.pdf"
|
||||||
|
|
||||||
util.merge_files_pdf(fileNames, merged_pdf)
|
util.merge_files_pdf(fileNames, merged_pdf)
|
||||||
|
|
||||||
# Mise à jour du champ registration_file avec le fichier fusionné
|
# Mise à jour du champ registration_file avec le fichier fusionné
|
||||||
@ -271,6 +273,14 @@ class RegisterFormWithIdView(APIView):
|
|||||||
# L'école a validé le dossier d'inscription
|
# L'école a validé le dossier d'inscription
|
||||||
# Mise à jour de l'automate
|
# Mise à jour de l'automate
|
||||||
updateStateMachine(registerForm, 'valideDI')
|
updateStateMachine(registerForm, 'valideDI')
|
||||||
|
elif _status == RegistrationForm.RegistrationFormStatus.RF_SENT:
|
||||||
|
# Vérifier si l'étape précédente était RF_UNDER_REVIEW
|
||||||
|
if registerForm.status == RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW:
|
||||||
|
# Mise à jour de l'automate
|
||||||
|
updateStateMachine(registerForm, 'refuseDI')
|
||||||
|
|
||||||
|
# Supprimer le fichier et le dossier associés
|
||||||
|
util.delete_registration_files(registerForm)
|
||||||
|
|
||||||
studentForm_serializer = RegistrationFormSerializer(registerForm, data=studentForm_data)
|
studentForm_serializer = RegistrationFormSerializer(registerForm, data=studentForm_data)
|
||||||
if studentForm_serializer.is_valid():
|
if studentForm_serializer.is_valid():
|
||||||
|
|||||||
Binary file not shown.
@ -1,7 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import Table from '@/components/Table';
|
import Table from '@/components/Table';
|
||||||
import {mockFicheInscription} from '@/data/mockFicheInscription';
|
|
||||||
import Tab from '@/components/Tab';
|
import Tab from '@/components/Tab';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import StatusLabel from '@/components/StatusLabel';
|
import StatusLabel from '@/components/StatusLabel';
|
||||||
@ -11,7 +10,7 @@ import Loader from '@/components/Loader';
|
|||||||
import AlertWithModal from '@/components/AlertWithModal';
|
import AlertWithModal from '@/components/AlertWithModal';
|
||||||
import DropdownMenu from "@/components/DropdownMenu";
|
import DropdownMenu from "@/components/DropdownMenu";
|
||||||
import { formatPhoneNumber } from '@/utils/Telephone';
|
import { formatPhoneNumber } from '@/utils/Telephone';
|
||||||
import { MoreVertical, Send, Edit, Trash2, FileText, CheckCircle, Plus } from 'lucide-react';
|
import { MoreVertical, Send, Edit, Trash2, FileText, CheckCircle, Plus, TicketX } from 'lucide-react';
|
||||||
import Modal from '@/components/Modal';
|
import Modal from '@/components/Modal';
|
||||||
import InscriptionForm from '@/components/Inscription/InscriptionForm'
|
import InscriptionForm from '@/components/Inscription/InscriptionForm'
|
||||||
import AffectationClasseForm from '@/components/AffectationClasseForm'
|
import AffectationClasseForm from '@/components/AffectationClasseForm'
|
||||||
@ -364,8 +363,27 @@ useEffect(()=>{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const refuseRegistrationForm = (id, lastname, firstname, guardianEmail) => {
|
||||||
|
const data = { status: 2, establishment: selectedEstablishmentId };
|
||||||
|
|
||||||
|
setPopup({
|
||||||
|
visible: true,
|
||||||
|
message: `Avertissement ! \nVous êtes sur le point de refuser le dossier d'inscription de ${lastname} ${firstname}\nUne notification va être envoyée à l'adresse ${guardianEmail}\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?`,
|
||||||
|
onConfirm: () => {
|
||||||
|
editRegisterForm(id, data, csrfToken)
|
||||||
|
.then(data => {
|
||||||
|
logger.debug('Success:', data);
|
||||||
|
setReloadFetch(true);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
logger.error('Error refusing RF:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const updateStatusAction = (id, newStatus) => {
|
const updateStatusAction = (id, newStatus) => {
|
||||||
logger.debug('Edit fiche inscription with id:', id);
|
logger.debug(`Mise à jour du statut du dossier d'inscription avec l'ID : ${id} vers le statut : ${newStatus}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSearchChange = (event) => {
|
const handleSearchChange = (event) => {
|
||||||
@ -447,7 +465,7 @@ useEffect(()=>{
|
|||||||
.then(clonedDocument => {
|
.then(clonedDocument => {
|
||||||
// Sauvegarde des templates clonés dans la base de données
|
// Sauvegarde des templates clonés dans la base de données
|
||||||
const cloneData = {
|
const cloneData = {
|
||||||
name: `clone_${clonedDocument.id}`,
|
name: `${templateMaster.name}_${updatedData.guardianFirstName}_${updatedData.guardianLastName}`,
|
||||||
slug: clonedDocument.slug,
|
slug: clonedDocument.slug,
|
||||||
id: clonedDocument.id,
|
id: clonedDocument.id,
|
||||||
master: templateMaster.id,
|
master: templateMaster.id,
|
||||||
@ -555,6 +573,80 @@ useEffect(()=>{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getActionsByStatus = (row) => {
|
||||||
|
const actions = {
|
||||||
|
1: [
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<>
|
||||||
|
<Send size={16} className="mr-2" /> Envoyer
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
onClick: () => sendConfirmRegisterForm(row.student.id, row.student.last_name, row.student.first_name),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<>
|
||||||
|
<Edit size={16} className="mr-2" /> Modifier
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
onClick: () => window.location.href = `${FE_ADMIN_SUBSCRIPTIONS_EDIT_URL}?studentId=${row.student.id}&id=1`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
2: [
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<>
|
||||||
|
<Edit size={16} className="mr-2" /> Modifier
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
onClick: () => window.location.href = `${FE_ADMIN_SUBSCRIPTIONS_EDIT_URL}?studentId=${row.student.id}&id=1`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
3: [
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<>
|
||||||
|
<CheckCircle size={16} className="mr-2" /> Valider
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
onClick: () => openModalAssociationEleve(row.student),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<>
|
||||||
|
<TicketX size={16} className="mr-2 text-red-700" /> Refuser
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
onClick: () => refuseRegistrationForm(row.student.id, row.student.last_name, row.student.first_name, row.student.guardians[0].associated_profile_email),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
5: [
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<>
|
||||||
|
<CheckCircle size={16} className="mr-2" /> Rattacher
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
onClick: () => openModalAssociationEleve(row.student),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<>
|
||||||
|
<Trash2 size={16} className="mr-2 text-red-700" /> Archiver
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
onClick: () => archiveFicheInscription(row.student.id, row.student.last_name, row.student.first_name),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Combine actions for the specific status and default actions
|
||||||
|
return [...(actions[row.status] || []), ...(row.status !== 6 ? actions.default : [])];
|
||||||
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ name: t('studentName'), transform: (row) => row.student.last_name },
|
{ name: t('studentName'), transform: (row) => row.student.last_name },
|
||||||
{ name: t('studentFistName'), transform: (row) => row.student.first_name },
|
{ name: t('studentFistName'), transform: (row) => row.student.first_name },
|
||||||
@ -588,69 +680,21 @@ const columns = [
|
|||||||
{ name: t('files'), transform: (row) =>
|
{ name: t('files'), transform: (row) =>
|
||||||
(row.registration_file != null) &&(
|
(row.registration_file != null) &&(
|
||||||
<ul>
|
<ul>
|
||||||
<li className="flex items-center gap-2">
|
<li className="flex justify-center items-center gap-2">
|
||||||
<FileText size={16} />
|
<FileText size={16} />
|
||||||
<a href={ `${BASE_URL}${row.registration_file}`} target='_blank'>{row.registration_file?.split('/').pop()}</a>
|
<a href={ `${BASE_URL}${row.registration_file}`} target='_blank'>{row.registration_file?.split('/').pop()}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
) },
|
) },
|
||||||
{ name: 'Actions', transform: (row) => (
|
{ name: 'Actions',
|
||||||
<DropdownMenu
|
transform: (row) => (
|
||||||
buttonContent={<MoreVertical size={20} className="text-gray-400 hover:text-gray-600" />}
|
<DropdownMenu
|
||||||
items={[
|
buttonContent={<MoreVertical size={20} className="text-gray-400 hover:text-gray-600" />}
|
||||||
...(row.status === 1 ? [{
|
items={getActionsByStatus(row)}
|
||||||
label: (
|
buttonClassName="text-gray-400 hover:text-gray-600"
|
||||||
<>
|
menuClassName="absolute right-0 mt-2 w-48 bg-white border border-gray-200 rounded-md shadow-lg z-10 flex flex-col items-center"
|
||||||
<Send size={16} className="mr-2" /> Envoyer
|
/>
|
||||||
</>
|
), },
|
||||||
),
|
|
||||||
onClick: () => sendConfirmRegisterForm(row.student.id, row.student.last_name, row.student.first_name),
|
|
||||||
}] : []),
|
|
||||||
...(row.status === 1 ? [{
|
|
||||||
label: (
|
|
||||||
<>
|
|
||||||
<Edit size={16} className="mr-2" /> Modifier
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
onClick: () => window.location.href = `${FE_ADMIN_SUBSCRIPTIONS_EDIT_URL}?studentId=${row.student.id}&id=1`,
|
|
||||||
}] : []),
|
|
||||||
...(row.status === 2 ? [{
|
|
||||||
label: (
|
|
||||||
<>
|
|
||||||
<Edit size={16} className="mr-2" /> Modifier
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
onClick: () => window.location.href = `${FE_ADMIN_SUBSCRIPTIONS_EDIT_URL}?studentId=${row.student.id}&id=1`,
|
|
||||||
}] : []),
|
|
||||||
...(row.status === 3 ? [{
|
|
||||||
label: (
|
|
||||||
<>
|
|
||||||
<CheckCircle size={16} className="mr-2" /> Valider
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
onClick: () => openModalAssociationEleve(row.student),
|
|
||||||
}] : []),
|
|
||||||
...(row.status === 5 ? [{
|
|
||||||
label: (
|
|
||||||
<>
|
|
||||||
<CheckCircle size={16} className="mr-2" /> Rattacher
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
onClick: () => openModalAssociationEleve(row.student),
|
|
||||||
}] : []),
|
|
||||||
...(row.status !== 6 ? [{
|
|
||||||
label: (
|
|
||||||
<>
|
|
||||||
<Trash2 size={16} className="mr-2 text-red-700" /> Archiver
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
onClick: () => archiveFicheInscription(row.student.id, row.student.last_name, row.student.first_name),
|
|
||||||
}] : []),
|
|
||||||
]}
|
|
||||||
buttonClassName="text-gray-400 hover:text-gray-600"
|
|
||||||
menuClassName="absolute right-0 mt-2 w-48 bg-white border border-gray-200 rounded-md shadow-lg z-10 flex flex-col items-center"
|
|
||||||
/>
|
|
||||||
) },
|
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -83,7 +83,8 @@ export default function ParentHomePage() {
|
|||||||
|
|
||||||
// Définir les colonnes du tableau
|
// Définir les colonnes du tableau
|
||||||
const childrenColumns = [
|
const childrenColumns = [
|
||||||
{ name: 'Nom', transform: (row) => `${row.student.last_name} ${row.student.first_name}` },
|
{ name: 'Nom', transform: (row) => `${row.student.last_name}` },
|
||||||
|
{ name: 'Prénom', transform: (row) => `${row.student.first_name}` },
|
||||||
{
|
{
|
||||||
name: 'Statut',
|
name: 'Statut',
|
||||||
transform: (row) => (
|
transform: (row) => (
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import DraggableFileUpload from '@/components/DraggableFileUpload';
|
|||||||
import Modal from '@/components/Modal';
|
import Modal from '@/components/Modal';
|
||||||
import FileStatusLabel from '@/components/FileStatusLabel';
|
import FileStatusLabel from '@/components/FileStatusLabel';
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
import StudentInfoForm from '@/components/Inscription/StudentInfoForm';
|
import StudentInfoForm, { validateStudentInfo } from '@/components/Inscription/StudentInfoForm';
|
||||||
import FilesToSign from '@/components/Inscription/FilesToSign';
|
import FilesToSign from '@/components/Inscription/FilesToSign';
|
||||||
import FilesToUpload from '@/components/Inscription/FilesToUpload';
|
import FilesToUpload from '@/components/Inscription/FilesToUpload';
|
||||||
import { DocusealForm } from '@docuseal/react';
|
import { DocusealForm } from '@docuseal/react';
|
||||||
@ -70,6 +70,14 @@ export default function InscriptionFormShared({
|
|||||||
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
|
||||||
|
const isCurrentPageValid = () => {
|
||||||
|
if (currentPage === 1) {
|
||||||
|
const isValid = validateStudentInfo(formData);
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
// Chargement initial des données
|
// Chargement initial des données
|
||||||
// Mettre à jour les données quand initialData change
|
// Mettre à jour les données quand initialData change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -178,12 +186,25 @@ export default function InscriptionFormShared({
|
|||||||
...formData,
|
...formData,
|
||||||
guardians
|
guardians
|
||||||
},
|
},
|
||||||
establishment: ESTABLISHMENT_ID,
|
establishment: 1,
|
||||||
status:3
|
status:3
|
||||||
}
|
}
|
||||||
onSubmit(data);
|
onSubmit(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Soumission du formulaire
|
||||||
|
const handleSave = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const data ={
|
||||||
|
student: {
|
||||||
|
...formData,
|
||||||
|
guardians
|
||||||
|
},
|
||||||
|
establishment: 1
|
||||||
|
}
|
||||||
|
onSubmit(data);
|
||||||
|
};
|
||||||
|
|
||||||
// Récupération des messages d'erreur
|
// Récupération des messages d'erreur
|
||||||
const getError = (field) => {
|
const getError = (field) => {
|
||||||
return errors?.student?.[field]?.[0];
|
return errors?.student?.[field]?.[0];
|
||||||
@ -276,31 +297,52 @@ export default function InscriptionFormShared({
|
|||||||
{/* Pages suivantes : Section Fichiers d'inscription */}
|
{/* Pages suivantes : Section Fichiers d'inscription */}
|
||||||
{currentPage > 1 && currentPage <= requiredFileTemplates.length + 1 && (
|
{currentPage > 1 && currentPage <= requiredFileTemplates.length + 1 && (
|
||||||
<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">{requiredFileTemplates[currentPage - 2].name}</h2>
|
{/* Titre du document */}
|
||||||
<DocusealForm
|
<div className="mb-4">
|
||||||
id="docusealForm"
|
<h2 className="text-lg font-semibold text-gray-800">
|
||||||
src={"https://docuseal.com/s/"+requiredFileTemplates[currentPage - 2].slug}
|
{requiredFileTemplates[currentPage - 2].name || "Document sans nom"}
|
||||||
withDownloadButton={false}
|
</h2>
|
||||||
onComplete={() => {
|
<p className="text-sm text-gray-500">
|
||||||
downloadTemplate(requiredFileTemplates[currentPage - 2].slug)
|
{requiredFileTemplates[currentPage - 2].description || "Aucune description disponible pour ce document."}
|
||||||
.then((data) => fetch(data))
|
</p>
|
||||||
.then((response) => response.blob())
|
</div>
|
||||||
.then((blob) => {
|
|
||||||
const file = new File([blob], `${requiredFileTemplates[currentPage - 2].name}.pdf`, { type: blob.type });
|
{/* Affichage du formulaire ou du document */}
|
||||||
const updateData = new FormData();
|
{requiredFileTemplates[currentPage - 2].file === "" ? (
|
||||||
updateData.append('file', file);
|
<DocusealForm
|
||||||
|
id="docusealForm"
|
||||||
return editRegistrationTemplates(requiredFileTemplates[currentPage - 2].id, updateData, csrfToken);
|
src={"https://docuseal.com/s/" + requiredFileTemplates[currentPage - 2].slug}
|
||||||
})
|
withDownloadButton={false}
|
||||||
.then((data) => {
|
onComplete={() => {
|
||||||
logger.debug("EDIT TEMPLATE : ", data);
|
downloadTemplate(requiredFileTemplates[currentPage - 2].slug)
|
||||||
})
|
.then((data) => fetch(data))
|
||||||
.catch((error) => {
|
.then((response) => response.blob())
|
||||||
logger.error("error editing template : ", error);
|
.then((blob) => {
|
||||||
});
|
const file = new File([blob], `${requiredFileTemplates[currentPage - 2].name}.pdf`, { type: blob.type });
|
||||||
}}
|
const updateData = new FormData();
|
||||||
>
|
updateData.append('file', file);
|
||||||
</DocusealForm>
|
|
||||||
|
return editRegistrationTemplates(requiredFileTemplates[currentPage - 2].id, updateData, csrfToken);
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
logger.debug("EDIT TEMPLATE : ", data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
logger.error("error editing template : ", error);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<iframe
|
||||||
|
src={`${BASE_URL}/${requiredFileTemplates[currentPage - 2].file}`}
|
||||||
|
title="Document Viewer"
|
||||||
|
className="w-full"
|
||||||
|
style={{
|
||||||
|
height: '75vh', // Ajuster la hauteur à 75% de la fenêtre
|
||||||
|
border: 'none',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -316,11 +358,29 @@ export default function InscriptionFormShared({
|
|||||||
|
|
||||||
{/* Boutons de contrôle */}
|
{/* Boutons de contrôle */}
|
||||||
<div className="flex justify-end space-x-4">
|
<div className="flex justify-end space-x-4">
|
||||||
|
<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 text="Précédent" onClick={(e) => { e.preventDefault(); handlePreviousPage(); }} />
|
<Button text="Précédent" onClick={(e) => { e.preventDefault(); handlePreviousPage(); }} />
|
||||||
)}
|
)}
|
||||||
{currentPage < requiredFileTemplates.length + 2 && (
|
{currentPage < requiredFileTemplates.length + 2 && (
|
||||||
<Button text="Suivant" onClick={(e) => { e.preventDefault(); handleNextPage(); }} />
|
<Button
|
||||||
|
text="Suivant"
|
||||||
|
onClick={(e) => { e.preventDefault(); handleNextPage(); }}
|
||||||
|
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
|
||||||
|
!isCurrentPageValid()
|
||||||
|
? "bg-gray-300 text-gray-700 cursor-not-allowed"
|
||||||
|
: "bg-emerald-500 text-white hover:bg-emerald-600"
|
||||||
|
}`}
|
||||||
|
disabled={!isCurrentPageValid()}
|
||||||
|
primary
|
||||||
|
name="Next"
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{currentPage === requiredFileTemplates.length + 2 && (
|
{currentPage === requiredFileTemplates.length + 2 && (
|
||||||
<Button type="submit" text="Valider" primary />
|
<Button type="submit" text="Valider" primary />
|
||||||
|
|||||||
@ -56,8 +56,8 @@ export default function ResponsableInputFields({guardians, onGuardiansChange, ad
|
|||||||
name="mailResponsable"
|
name="mailResponsable"
|
||||||
type="email"
|
type="email"
|
||||||
label={t('email')}
|
label={t('email')}
|
||||||
value={item.email}
|
value={item.associated_profile_email}
|
||||||
onChange={(event) => {onGuardiansChange(item.id, "email", event.target.value)}}
|
onChange={(event) => {onGuardiansChange(item.id, "associated_profile_email", event.target.value)}}
|
||||||
required
|
required
|
||||||
errorMsg={getError(index, 'email')}
|
errorMsg={getError(index, 'email')}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -10,6 +10,28 @@ const levels = [
|
|||||||
{ value:'4', label: 'GS - Grande Section'},
|
{ value:'4', label: 'GS - Grande Section'},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// 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({ formData, updateFormField, guardians, setGuardians, errors }) {
|
export default function StudentInfoForm({ formData, updateFormField, guardians, setGuardians, errors }) {
|
||||||
const getError = (field) => {
|
const getError = (field) => {
|
||||||
return errors?.student?.[field]?.[0];
|
return errors?.student?.[field]?.[0];
|
||||||
|
|||||||
@ -66,7 +66,7 @@ export default function FileUpload({ handleCreateTemplateMaster, handleEditTempl
|
|||||||
const details = selectedGroups.flatMap(group =>
|
const details = selectedGroups.flatMap(group =>
|
||||||
group.registration_forms.flatMap(form =>
|
group.registration_forms.flatMap(form =>
|
||||||
form.guardians.map(guardian => ({
|
form.guardians.map(guardian => ({
|
||||||
email: guardian.email,
|
email: guardian.associated_profile_email,
|
||||||
last_name: form.last_name,
|
last_name: form.last_name,
|
||||||
first_name: form.first_name,
|
first_name: form.first_name,
|
||||||
registration_form: form.student_id
|
registration_form: form.student_id
|
||||||
|
|||||||
Reference in New Issue
Block a user