mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: Création de clones lors de la création de RF [#22]
This commit is contained in:
@ -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,15 +383,48 @@ useEffect(()=>{
|
|||||||
|
|
||||||
createRegisterForm(data, csrfToken)
|
createRegisterForm(data, csrfToken)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
// Mise à jour immédiate des données
|
// Cloner les templates pour chaque templateMaster du fileGroup
|
||||||
setRegistrationFormsDataPending(prevState => [...(prevState || []), data]);
|
const masters = templateMasters.filter(file => file.groups.includes(selectedFileGroup));
|
||||||
setTotalPending(prev => prev + 1);
|
const clonePromises = masters.map((templateMaster, index) => {
|
||||||
if (updatedData.autoMail) {
|
return cloneTemplate(templateMaster.template_id, guardianEmail)
|
||||||
sendConfirmRegisterForm(data.student.id, updatedData.studentLastName, updatedData.studentFirstName);
|
.then(clonedDocument => {
|
||||||
}
|
// Sauvegarde des templates clonés dans la base de données
|
||||||
closeModal();
|
const cloneData = {
|
||||||
// Forcer le rechargement complet des données
|
name: `clone_${clonedDocument.id}`,
|
||||||
setReloadFetch(true);
|
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
|
||||||
|
setRegistrationFormsDataPending(prevState => [...(prevState || []), data]);
|
||||||
|
setTotalPending(prev => prev + 1);
|
||||||
|
if (updatedData.autoMail) {
|
||||||
|
sendConfirmRegisterForm(data.student.id, updatedData.studentLastName, updatedData.studentFirstName);
|
||||||
|
}
|
||||||
|
closeModal();
|
||||||
|
// Forcer le rechargement complet des données
|
||||||
|
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,20 +460,60 @@ useEffect(()=>{
|
|||||||
|
|
||||||
createRegisterForm(data, csrfToken)
|
createRegisterForm(data, csrfToken)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
// Mise à jour immédiate des données
|
// Cloner les templates pour chaque templateMaster du fileGroup
|
||||||
setRegistrationFormsDataPending(prevState => [...(prevState || []), data]);
|
const masters = templateMasters.filter(file => file.groups.includes(selectedFileGroup));
|
||||||
setTotalPending(prev => prev + 1);
|
const clonePromises = masters.map((templateMaster, index) => {
|
||||||
if (updatedData.autoMail) {
|
return cloneTemplate(templateMaster.template_id, updatedData.guardianEmail)
|
||||||
sendConfirmRegisterForm(data.student.id, updatedData.studentLastName, updatedData.studentFirstName);
|
.then(clonedDocument => {
|
||||||
}
|
// Sauvegarde des templates clonés dans la base de données
|
||||||
closeModal();
|
const cloneData = {
|
||||||
logger.debug('Success:', data);
|
name: `clone_${clonedDocument.id}`,
|
||||||
// Forcer le rechargement complet des données
|
template_id: clonedDocument.id,
|
||||||
setReloadFetch(true);
|
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
|
||||||
|
setRegistrationFormsDataPending(prevState => [...(prevState || []), data]);
|
||||||
|
setTotalPending(prev => prev + 1);
|
||||||
|
|
||||||
|
if (updatedData.autoMail) {
|
||||||
|
sendConfirmRegisterForm(data.student.id, updatedData.studentLastName, updatedData.studentFirstName);
|
||||||
|
}
|
||||||
|
closeModal();
|
||||||
|
logger.debug('Success:', data);
|
||||||
|
// Forcer le rechargement complet des données
|
||||||
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -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}`,
|
||||||
|
|||||||
@ -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) => {
|
||||||
@ -193,4 +194,18 @@ export const editRegistrationTemplateMaster = (fileId, data, csrfToken) => {
|
|||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
})
|
})
|
||||||
.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)
|
||||||
}
|
}
|
||||||
@ -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);
|
||||||
? prevData.selectedGuardians.filter(id => id !== guardianId)
|
const selectedGuardians = isSelected
|
||||||
: [...prevData.selectedGuardians, guardianId];
|
? prevData.selectedGuardians.filter(id => id !== guardianId)
|
||||||
return { ...prevData, selectedGuardians };
|
: [...prevData.selectedGuardians, guardianId];
|
||||||
|
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}`}
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
@ -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));
|
||||||
|
|||||||
@ -86,4 +86,7 @@ export const FE_ADMIN_SETTINGS_URL = `/admin/settings`
|
|||||||
export const FE_PARENTS_HOME_URL = `/parents`
|
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`
|
||||||
Reference in New Issue
Block a user