feat: Création de clones lors de la création de RF [#22]

This commit is contained in:
N3WT DE COMPET
2025-03-01 17:50:54 +01:00
parent b97cf6e02b
commit d1a0067f7b
7 changed files with 145 additions and 64 deletions

View File

@ -28,7 +28,10 @@ import {
editRegisterForm } from "@/app/actions/subscriptionAction" editRegisterForm } from "@/app/actions/subscriptionAction"
import { import {
fetchRegistrationTemplateMaster fetchRegistrationTemplateMaster,
createRegistrationTemplates,
fetchRegistrationFileGroups,
cloneTemplate
} from "@/app/actions/registerFileGroupAction"; } from "@/app/actions/registerFileGroupAction";
import { import {
@ -38,7 +41,7 @@ import {
fetchRegistrationFees, fetchRegistrationFees,
fetchTuitionFees } from '@/app/actions/schoolAction'; fetchTuitionFees } from '@/app/actions/schoolAction';
import { createProfile } from '@/app/actions/authAction'; import { createProfile, deleteProfile } from '@/app/actions/authAction';
import { import {
BASE_URL, BASE_URL,
@ -46,7 +49,6 @@ import {
import DjangoCSRFToken from '@/components/DjangoCSRFToken' import DjangoCSRFToken from '@/components/DjangoCSRFToken'
import { useCsrfToken } from '@/context/CsrfContext'; import { useCsrfToken } from '@/context/CsrfContext';
import { fetchRegistrationFileGroups } from '@/app/actions/registerFileGroupAction';
import { ESTABLISHMENT_ID } from '@/utils/Url'; import { ESTABLISHMENT_ID } from '@/utils/Url';
import logger from '@/utils/logger'; import logger from '@/utils/logger';
@ -71,7 +73,7 @@ export default function Page({ params: { locale } }) {
const [totalArchives, setTotalArchives] = useState(0); const [totalArchives, setTotalArchives] = useState(0);
const [itemsPerPage, setItemsPerPage] = useState(5); // Définir le nombre d'éléments par page const [itemsPerPage, setItemsPerPage] = useState(5); // Définir le nombre d'éléments par page
const [fichiers, setFichiers] = useState([]); const [templateMasters, setTemplateMasters] = useState([]);
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [isOpenAffectationClasse, setIsOpenAffectationClasse] = useState(false); const [isOpenAffectationClasse, setIsOpenAffectationClasse] = useState(false);
const [student, setStudent] = useState(''); const [student, setStudent] = useState('');
@ -202,7 +204,7 @@ useEffect(() => {
.then((data)=> { .then((data)=> {
logger.debug(data); logger.debug(data);
setFichiers(data) setTemplateMasters(data)
}) })
.catch((err)=>{ err = err.message; logger.debug(err);}) .catch((err)=>{ err = err.message; logger.debug(err);})
fetchRegistrationDiscounts() fetchRegistrationDiscounts()
@ -258,7 +260,7 @@ useEffect(() => {
.then(registerFormArchivedDataHandler) .then(registerFormArchivedDataHandler)
.catch(requestErrorHandler) .catch(requestErrorHandler)
fetchRegistrationTemplateMaster() fetchRegistrationTemplateMaster()
.then((data)=> {setFichiers(data)}) .then((data)=> {setTemplateMasters(data)})
.catch((err)=>{ err = err.message; logger.debug(err);}); .catch((err)=>{ err = err.message; logger.debug(err);});
} else { } else {
setTimeout(() => { setTimeout(() => {
@ -365,6 +367,8 @@ useEffect(()=>{
if (updatedData.selectedGuardians.length !== 0) { if (updatedData.selectedGuardians.length !== 0) {
const selectedGuardiansIds = updatedData.selectedGuardians.map(guardianId => guardianId) const selectedGuardiansIds = updatedData.selectedGuardians.map(guardianId => guardianId)
const guardianEmail = updatedData.guardianEmail
const data = { const data = {
student: { student: {
last_name: updatedData.studentLastName, last_name: updatedData.studentLastName,
@ -379,6 +383,35 @@ useEffect(()=>{
createRegisterForm(data, csrfToken) createRegisterForm(data, csrfToken)
.then(data => { .then(data => {
// Cloner les templates pour chaque templateMaster du fileGroup
const masters = templateMasters.filter(file => file.groups.includes(selectedFileGroup));
const clonePromises = masters.map((templateMaster, index) => {
return cloneTemplate(templateMaster.template_id, guardianEmail)
.then(clonedDocument => {
// Sauvegarde des templates clonés dans la base de données
const cloneData = {
name: `clone_${clonedDocument.id}`,
template_id: clonedDocument.id,
master: templateMaster.template_id,
registration_form: data.student.id
};
return createRegistrationTemplates(cloneData, csrfToken)
.then(response => {
logger.debug('Template enregistré avec succès:', response);
})
.catch(error => {
logger.error('Erreur lors de l\'enregistrement du template:', error);
});
})
.catch(error => {
logger.error('Error during cloning or sending:', error);
});
});
// Attendre que tous les clones soient créés
Promise.all(clonePromises)
.then(() => {
// Mise à jour immédiate des données // Mise à jour immédiate des données
setRegistrationFormsDataPending(prevState => [...(prevState || []), data]); setRegistrationFormsDataPending(prevState => [...(prevState || []), data]);
setTotalPending(prev => prev + 1); setTotalPending(prev => prev + 1);
@ -389,6 +422,10 @@ useEffect(()=>{
// Forcer le rechargement complet des données // Forcer le rechargement complet des données
setReloadFetch(true); setReloadFetch(true);
}) })
.catch(error => {
logger.error('Error during cloning or sending:', error);
});
})
.catch((error) => { .catch((error) => {
logger.error('Error:', error); logger.error('Error:', error);
}); });
@ -423,9 +460,39 @@ useEffect(()=>{
createRegisterForm(data, csrfToken) createRegisterForm(data, csrfToken)
.then(data => { .then(data => {
// Cloner les templates pour chaque templateMaster du fileGroup
const masters = templateMasters.filter(file => file.groups.includes(selectedFileGroup));
const clonePromises = masters.map((templateMaster, index) => {
return cloneTemplate(templateMaster.template_id, updatedData.guardianEmail)
.then(clonedDocument => {
// Sauvegarde des templates clonés dans la base de données
const cloneData = {
name: `clone_${clonedDocument.id}`,
template_id: clonedDocument.id,
master: templateMaster.template_id,
registration_form: data.student.id
};
return createRegistrationTemplates(cloneData, csrfToken)
.then(response => {
logger.debug('Template enregistré avec succès:', response);
})
.catch(error => {
logger.error('Erreur lors de l\'enregistrement du template:', error);
});
})
.catch(error => {
logger.error('Error during cloning or sending:', error);
});
});
// Attendre que tous les clones soient créés
Promise.all(clonePromises)
.then(() => {
// Mise à jour immédiate des données // Mise à jour immédiate des données
setRegistrationFormsDataPending(prevState => [...(prevState || []), data]); setRegistrationFormsDataPending(prevState => [...(prevState || []), data]);
setTotalPending(prev => prev + 1); setTotalPending(prev => prev + 1);
if (updatedData.autoMail) { if (updatedData.autoMail) {
sendConfirmRegisterForm(data.student.id, updatedData.studentLastName, updatedData.studentFirstName); sendConfirmRegisterForm(data.student.id, updatedData.studentLastName, updatedData.studentFirstName);
} }
@ -434,9 +501,19 @@ useEffect(()=>{
// Forcer le rechargement complet des données // Forcer le rechargement complet des données
setReloadFetch(true); setReloadFetch(true);
}) })
.catch(error => {
logger.error('Error during cloning or sending:', error);
});
})
.catch((error) => { .catch((error) => {
logger.error('Error:', error); logger.error('Error:', error);
//deleteProfile(response.id, csrfToken); deleteProfile(response.id, csrfToken)
.then(() => {
logger.debug('Profile deleted due to RF creation failure');
})
.catch(deleteError => {
logger.error('Error deleting profile:', deleteError);
});
}); });
} }
}) })

View File

@ -89,6 +89,20 @@ export const createProfile = (data, csrfToken) => {
return fetch(request).then(requestResponseHandler); return fetch(request).then(requestResponseHandler);
}; };
export const deleteProfile = (id, csrfToken) => {
const request = new Request(
`${BE_AUTH_PROFILES_URL}/${id}`,
{
method: 'DELETE',
headers: {
'X-CSRFToken': csrfToken
},
credentials: 'include'
}
);
return fetch(request).then(requestResponseHandler);
};
export const updateProfile = (id, data, csrfToken) => { export const updateProfile = (id, data, csrfToken) => {
const request = new Request( const request = new Request(
`${BE_AUTH_PROFILES_URL}/${id}`, `${BE_AUTH_PROFILES_URL}/${id}`,

View File

@ -1,6 +1,7 @@
import { BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL, import { BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL,
BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL, BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL,
BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL,
FE_API_DOCUSEAL_CLONE_URL
} from '@/utils/Url'; } from '@/utils/Url';
const requestResponseHandler = async (response) => { const requestResponseHandler = async (response) => {
@ -194,3 +195,17 @@ export const editRegistrationTemplateMaster = (fileId, data, csrfToken) => {
}) })
.then(requestResponseHandler) .then(requestResponseHandler)
} }
export const cloneTemplate = (templateId, email) => {
return fetch(`${FE_API_DOCUSEAL_CLONE_URL}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId,
email
})
})
.then(requestResponseHandler)
}

View File

@ -119,12 +119,13 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
setExistingGuardians(student.guardians); setExistingGuardians(student.guardians);
}; };
const handleResponsableSelection = (guardianId) => { const handleResponsableSelection = (guardianId, guardianEmail) => {
setFormData((prevData) => { setFormData((prevData) => {
const selectedGuardians = prevData.selectedGuardians.includes(guardianId) const isSelected = prevData.selectedGuardians.includes(guardianId);
const selectedGuardians = isSelected
? prevData.selectedGuardians.filter(id => id !== guardianId) ? prevData.selectedGuardians.filter(id => id !== guardianId)
: [...prevData.selectedGuardians, guardianId]; : [...prevData.selectedGuardians, guardianId];
return { ...prevData, selectedGuardians }; return { ...prevData, selectedGuardians, guardianEmail };
}); });
}; };
@ -345,7 +346,7 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
type="checkbox" type="checkbox"
checked={formData.selectedGuardians.includes(guardian.id)} checked={formData.selectedGuardians.includes(guardian.id)}
className="form-checkbox h-5 w-5 text-emerald-600" className="form-checkbox h-5 w-5 text-emerald-600"
onChange={() => handleResponsableSelection(guardian.id)} onChange={() => handleResponsableSelection(guardian.id, guardian.email)}
/> />
<span className="text-gray-900"> <span className="text-gray-900">
{guardian.last_name && guardian.first_name ? `${guardian.last_name} ${guardian.first_name}` : `${guardian.email}`} {guardian.last_name && guardian.first_name ? `${guardian.last_name} ${guardian.first_name}` : `${guardian.email}`}

View File

@ -1,12 +1,11 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import ToggleSwitch from '@/components/ToggleSwitch'; // Import du composant ToggleSwitch import ToggleSwitch from '@/components/ToggleSwitch'; // Import du composant ToggleSwitch
import { fetchRegistrationFileGroups } from '@/app/actions/registerFileGroupAction'; import { fetchRegistrationFileGroups, createRegistrationTemplates, cloneTemplate } from '@/app/actions/registerFileGroupAction';
import { DocusealBuilder } from '@docuseal/react'; import { DocusealBuilder } from '@docuseal/react';
import logger from '@/utils/logger'; import logger from '@/utils/logger';
import { BE_DOCUSEAL_GET_JWT, BASE_URL } from '@/utils/Url'; import { BE_DOCUSEAL_GET_JWT, BASE_URL } from '@/utils/Url';
import Button from '@/components/Button'; // Import du composant Button import Button from '@/components/Button'; // Import du composant Button
import MultiSelect from '@/components/MultiSelect'; // Import du composant MultiSelect import MultiSelect from '@/components/MultiSelect'; // Import du composant MultiSelect
import { createRegistrationTemplates } from '@/app/actions/registerFileGroupAction';
import { useCsrfToken } from '@/context/CsrfContext'; import { useCsrfToken } from '@/context/CsrfContext';
export default function FileUpload({ handleCreateTemplateMaster, handleEditTemplateMaster, fileToEdit = null, onSuccess }) { export default function FileUpload({ handleCreateTemplateMaster, handleEditTemplateMaster, fileToEdit = null, onSuccess }) {
@ -138,33 +137,6 @@ export default function FileUpload({ handleCreateTemplateMaster, handleEditTempl
}; };
const cloneTemplate = (templateId, email) => {
return fetch('/api/docuseal/cloneTemplate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
templateId,
email
})
})
.then(response => {
if (!response.ok) {
return response.json().then(err => { throw new Error(err.message); });
}
return response.json();
})
.then(data => {
logger.debug('Template cloned successfully:', data);
return data;
})
.catch(error => {
console.error('Error cloning template:', error);
throw error;
});
};
return ( return (
<div className="h-full flex flex-col mt-4 space-y-4"> <div className="h-full flex flex-col mt-4 space-y-4">
<div className="grid grid-cols-10 gap-4 items-start"> <div className="grid grid-cols-10 gap-4 items-start">

View File

@ -66,7 +66,6 @@ export default function FilesGroupsManagement({ csrfToken }) {
const deleteTemplateMaster = (templateMaster) => { const deleteTemplateMaster = (templateMaster) => {
// Supprimer les clones associés via l'API DocuSeal // Supprimer les clones associés via l'API DocuSeal
console.log(templates)
const removeClonesPromises = templates const removeClonesPromises = templates
.filter(template => template.master === templateMaster.template_id) .filter(template => template.master === templateMaster.template_id)
.map(template => removeTemplate(template.template_id)); .map(template => removeTemplate(template.template_id));

View File

@ -87,3 +87,6 @@ export const FE_PARENTS_HOME_URL = `/parents`
export const FE_PARENTS_MESSAGERIE_URL = `/parents/messagerie` export const FE_PARENTS_MESSAGERIE_URL = `/parents/messagerie`
export const FE_PARENTS_SETTINGS_URL = `/parents/settings` export const FE_PARENTS_SETTINGS_URL = `/parents/settings`
export const FE_PARENTS_EDIT_INSCRIPTION_URL = `/parents/editInscription` export const FE_PARENTS_EDIT_INSCRIPTION_URL = `/parents/editInscription`
// API DOCUSEAL
export const FE_API_DOCUSEAL_CLONE_URL = `/api/docuseal/cloneTemplate`