feat: Suppression des templates docuseal [#22]

This commit is contained in:
N3WT DE COMPET
2025-03-01 15:06:57 +01:00
parent 4b8f85e68d
commit 081dc06001
11 changed files with 388 additions and 292 deletions

View File

@ -1,7 +1,8 @@
from django.urls import path, re_path
from .views import generate_jwt_token, clone_template
from .views import generate_jwt_token, clone_template, remove_template
urlpatterns = [
re_path(r'generateToken$', generate_jwt_token, name='generate_jwt_token'),
re_path(r'cloneTemplate$', clone_template, name='clone_template'),
re_path(r'removeTemplate/(?P<id>[0-9]+)$', remove_template, name='remove_template'),
]

View File

@ -71,7 +71,7 @@ def clone_template(request):
'X-Auth-Token': settings.DOCUSEAL_JWT['API_KEY']
})
if response.status_code != 200:
if response.status_code != status.HTTP_200_OK:
return Response({'error': 'Failed to clone template'}, status=response.status_code)
data = response.json()
@ -79,3 +79,29 @@ def clone_template(request):
except requests.RequestException as e:
return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@csrf_exempt
@api_view(['DELETE'])
def remove_template(request, id):
# Vérifier la clé API
api_key = request.headers.get('X-Auth-Token')
if not api_key or api_key != settings.DOCUSEAL_JWT["API_KEY"]:
return Response({'error': 'Invalid API key'}, status=status.HTTP_401_UNAUTHORIZED)
# URL de l'API de DocuSeal pour cloner le template
clone_url = f'https://docuseal.com/api/templates/{id}'
# Faire la requête pour cloner le template
try:
response = requests.delete(clone_url, headers={
'X-Auth-Token': settings.DOCUSEAL_JWT['API_KEY']
})
if response.status_code != status.HTTP_200_OK:
return Response({'error': 'Failed to remove template'}, status=response.status_code)
data = response.json()
return Response(data, status=status.HTTP_200_OK)
except requests.RequestException as e:
return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

View File

@ -44,7 +44,7 @@ class RegistrationTemplateMasterSimpleView(APIView):
}
)
def get(self, request, id):
master = bdd.getObject(_objectName=RegistrationTemplateMaster, _columnName='id', _value=id)
master = bdd.getObject(_objectName=RegistrationTemplateMaster, _columnName='template_id', _value=id)
if master is None:
return JsonResponse({"errorMessage":'Le master de template n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationTemplateMasterSerializer(master)
@ -60,7 +60,7 @@ class RegistrationTemplateMasterSimpleView(APIView):
}
)
def put(self, request, id):
master = bdd.getObject(_objectName=RegistrationTemplateMaster, _columnName='id', _value=id)
master = bdd.getObject(_objectName=RegistrationTemplateMaster, _columnName='template_id', _value=id)
if master is None:
return JsonResponse({'erreur': 'Le master de template n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationTemplateMasterSerializer(master, data=request.data)
@ -77,7 +77,7 @@ class RegistrationTemplateMasterSimpleView(APIView):
}
)
def delete(self, request, id):
master = bdd.getObject(_objectName=RegistrationTemplateMaster, _columnName='id', _value=id)
master = bdd.getObject(_objectName=RegistrationTemplateMaster, _columnName='template_id', _value=id)
if master is not None:
master.delete()
return JsonResponse({'message': 'La suppression du master de template a été effectuée avec succès'}, safe=False, status=status.HTTP_204_NO_CONTENT)
@ -118,7 +118,7 @@ class RegistrationTemplateSimpleView(APIView):
}
)
def get(self, request, id):
template = bdd.getObject(_objectName=RegistrationTemplate, _columnName='id', _value=id)
template = bdd.getObject(_objectName=RegistrationTemplate, _columnName='template_id', _value=id)
if template is None:
return JsonResponse({"errorMessage":'Le template d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationTemplateSerializer(template)
@ -134,7 +134,7 @@ class RegistrationTemplateSimpleView(APIView):
}
)
def put(self, request, id):
template = bdd.getObject(_objectName=RegistrationTemplate, _columnName='id', _value=id)
template = bdd.getObject(_objectName=RegistrationTemplate, _columnName='template_id', _value=id)
if template is None:
return JsonResponse({'erreur': 'Le template d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationTemplateSerializer(template, data=request.data)
@ -151,7 +151,7 @@ class RegistrationTemplateSimpleView(APIView):
}
)
def delete(self, request, id):
template = bdd.getObject(_objectName=RegistrationTemplate, _columnName='id', _value=id)
template = bdd.getObject(_objectName=RegistrationTemplate, _columnName='template_id', _value=id)
if template is not None:
template.delete()
return JsonResponse({'message': 'La suppression du template a été effectuée avec succès'}, safe=False, status=status.HTTP_204_NO_CONTENT)

View File

@ -23,7 +23,9 @@ import { createDatas,
fetchTuitionPaymentModes } from '@/app/actions/schoolAction';
import SidebarTabs from '@/components/SidebarTabs';
import FilesGroupsManagement from '@/components/Structure/Files/FilesGroupsManagement';
import { fetchRegistrationTemplateMaster } from '@/app/actions/subscriptionAction';
import {
fetchRegistrationTemplateMaster
} from "@/app/actions/registerFileGroupAction";
import logger from '@/utils/logger';

View File

@ -24,10 +24,13 @@ import {
createRegisterForm,
sendRegisterForm,
archiveRegisterForm,
fetchRegistrationTemplateMaster,
fetchStudents,
editRegisterForm } from "@/app/actions/subscriptionAction"
import {
fetchRegistrationTemplateMaster
} from "@/app/actions/registerFileGroupAction";
import {
fetchClasses,
fetchRegistrationDiscounts,

View File

@ -1,4 +1,19 @@
import { BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL } from '@/utils/Url';
import { BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL,
BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL,
BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL
} from '@/utils/Url';
const requestResponseHandler = async (response) => {
const body = await response.json();
if (response.ok) {
return body;
}
// Throw an error with the JSON body containing the form errors
const error = new Error('Form submission error');
error.details = body;
throw error;
}
export async function fetchRegistrationFileGroups() {
const response = await fetch(`${BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL}`, {
@ -72,3 +87,110 @@ export const fetchRegistrationFileFromGroup = async (groupId) => {
}
return response.json();
}
export const fetchRegistrationTemplates = (id = null) => {
let url = `${BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL}`
if (id) {
url = `${BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL}/${id}`;
}
const request = new Request(
`${url}`,
{
method:'GET',
headers: {
'Content-Type':'application/json'
},
}
);
return fetch(request).then(requestResponseHandler)
};
export const editRegistrationTemplates = (fileId, data, csrfToken) => {
return fetch(`${BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL}/${fileId}`, {
method: 'PUT',
body: data,
headers: {
'X-CSRFToken': csrfToken,
},
credentials: 'include',
})
.then(requestResponseHandler)
}
export const createRegistrationTemplates = (data,csrfToken) => {
return fetch(`${BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL}`, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'X-CSRFToken': csrfToken,
'Content-Type': 'application/json',
},
credentials: 'include',
})
.then(requestResponseHandler)
}
export const deleteRegistrationTemplates = (fileId,csrfToken) => {
return fetch(`${BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL}/${fileId}`, {
method: 'DELETE',
headers: {
'X-CSRFToken': csrfToken,
},
credentials: 'include',
})
}
export const fetchRegistrationTemplateMaster = (id = null) => {
let url = `${BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL}`;
if(id){
url = `${BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL}/${id}`;
}
const request = new Request(
`${url}`,
{
method:'GET',
headers: {
'Content-Type':'application/json'
},
}
);
return fetch(request).then(requestResponseHandler)
};
export const createRegistrationTemplateMaster = (data,csrfToken) => {
return fetch(`${BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL}`, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'X-CSRFToken': csrfToken,
'Content-Type':'application/json'
},
credentials: 'include',
})
.then(requestResponseHandler)
}
export const deleteRegistrationTemplateMaster = (fileId,csrfToken) => {
return fetch(`${BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL}/${fileId}`, {
method: 'DELETE',
headers: {
'X-CSRFToken': csrfToken,
},
credentials: 'include',
})
}
export const editRegistrationTemplateMaster = (fileId, data, csrfToken) => {
return fetch(`${BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL}/${fileId}`, {
method: 'PUT',
body: JSON.stringify(data),
headers: {
'X-CSRFToken': csrfToken,
'Content-Type':'application/json'
},
credentials: 'include',
})
.then(requestResponseHandler)
}

View File

@ -2,9 +2,7 @@ import {
BE_SUBSCRIPTION_STUDENTS_URL,
BE_SUBSCRIPTION_CHILDRENS_URL,
BE_SUBSCRIPTION_REGISTERFORMS_URL,
BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL,
BE_SUBSCRIPTION_LAST_GUARDIAN_ID_URL,
BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL
BE_SUBSCRIPTION_LAST_GUARDIAN_ID_URL
} from '@/utils/Url';
export const PENDING = 'pending';
@ -101,112 +99,6 @@ export const archiveRegisterForm = (id) => {
}).then(requestResponseHandler)
}
export const fetchRegistrationTemplates = (id = null) => {
let url = `${BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL}`
if (id) {
url = `${BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL}/${id}`;
}
const request = new Request(
`${url}`,
{
method:'GET',
headers: {
'Content-Type':'application/json'
},
}
);
return fetch(request).then(requestResponseHandler)
};
export const editRegistrationTemplates= (fileId, data, csrfToken) => {
return fetch(`${BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL}/${fileId}`, {
method: 'PUT',
body: data,
headers: {
'X-CSRFToken': csrfToken,
},
credentials: 'include',
})
.then(requestResponseHandler)
}
export const createRegistrationTemplates = (data,csrfToken) => {
return fetch(`${BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL}`, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'X-CSRFToken': csrfToken,
'Content-Type': 'application/json',
},
credentials: 'include',
})
.then(requestResponseHandler)
}
export const deleteRegistrationTemplates= (fileId,csrfToken) => {
return fetch(`${BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL}/${fileId}`, {
method: 'DELETE',
headers: {
'X-CSRFToken': csrfToken,
},
credentials: 'include',
})
}
export const fetchRegistrationTemplateMaster = (id = null) => {
let url = `${BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL}`;
if(id){
url = `${BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL}/${id}`;
}
const request = new Request(
`${url}`,
{
method:'GET',
headers: {
'Content-Type':'application/json'
},
}
);
return fetch(request).then(requestResponseHandler)
};
export const createRegistrationTemplateMaster = (data,csrfToken) => {
return fetch(`${BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL}`, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'X-CSRFToken': csrfToken,
'Content-Type':'application/json'
},
credentials: 'include',
})
.then(requestResponseHandler)
}
export const deleteRegistrationTemplateMaster = (fileId,csrfToken) => {
return fetch(`${BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL}/${fileId}`, {
method: 'DELETE',
headers: {
'X-CSRFToken': csrfToken,
},
credentials: 'include',
})
}
export const editRegistrationTemplateMaster = (fileId, data, csrfToken) => {
return fetch(`${BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL}/${fileId}`, {
method: 'PUT',
body: data,
headers: {
'X-CSRFToken': csrfToken,
},
credentials: 'include',
})
.then(requestResponseHandler)
}
export const fetchStudents = (id) => {
const url = (id)?`${BE_SUBSCRIPTION_STUDENTS_URL}/${id}`:`${BE_SUBSCRIPTION_STUDENTS_URL}`;
const request = new Request(

View File

@ -1,15 +1,15 @@
import React, { useState, useEffect } from 'react';
import ToggleSwitch from '@/components/ToggleSwitch'; // Import du composant ToggleSwitch
import { fetchRegistrationFileGroups } from '@/app/actions/registerFileGroupAction';
import DocusealBuilder from '@/components/DocusealBuilder'; // Import du composant wrapper
import { DocusealBuilder } from '@docuseal/react';
import logger from '@/utils/logger';
import { BE_DOCUSEAL_GET_JWT, BASE_URL } from '@/utils/Url';
import Button from '@/components/Button'; // Import du composant Button
import MultiSelect from '@/components/MultiSelect'; // Import du composant MultiSelect
import { createRegistrationTemplates } from '@/app/actions/subscriptionAction'; // Import de la fonction createRegistrationTemplates
import { createRegistrationTemplates } from '@/app/actions/registerFileGroupAction';
import { useCsrfToken } from '@/context/CsrfContext';
export default function FileUpload({ handleCreateTemplateMaster, fileToEdit = null }) {
export default function FileUpload({ handleCreateTemplateMaster, handleEditTemplateMaster, fileToEdit = null, onSuccess }) {
const [isRequired, setIsRequired] = useState(false); // État pour le toggle isRequired
const [order, setOrder] = useState(0);
const [groups, setGroups] = useState([]);
@ -75,7 +75,12 @@ export default function FileUpload({ handleCreateTemplateMaster, fileToEdit = nu
const handleLoad = (detail) => {
const templateId = detail?.id;
setTemplateMaster(detail);
logger.debug('Master template created with ID:', templateId);
if (fileToEdit) {
logger.debug('Editing master ID :', templateId);
}
else {
logger.debug('Opening master ID :', templateId);
}
}
const handleUpload = (detail) => {
@ -84,41 +89,53 @@ export default function FileUpload({ handleCreateTemplateMaster, fileToEdit = nu
};
const handleSubmit = () => {
logger.debug('Création du template master:', templateMaster?.id);
handleCreateTemplateMaster({
name: uploadedFileName,
group_ids: selectedGroups.map(group => group.id),
template_id: templateMaster?.id
});
if (fileToEdit) {
logger.debug('Modification du template master:', templateMaster?.id);
handleEditTemplateMaster({
name: uploadedFileName,
group_ids: selectedGroups.map(group => group.id),
template_id: templateMaster?.id
});
}
else {
logger.debug('Création du template master:', templateMaster?.id);
handleCreateTemplateMaster({
name: uploadedFileName,
group_ids: selectedGroups.map(group => group.id),
template_id: templateMaster?.id
});
guardianEmails.forEach((email, index) => {
cloneTemplate(templateMaster?.id, email)
.then(clonedDocument => {
guardianEmails.forEach((email, index) => {
cloneTemplate(templateMaster?.id, email)
.then(clonedDocument => {
// Sauvegarde des templates clonés dans la base de données
const data = {
name: `clone_${clonedDocument.id}`,
template_id: clonedDocument.id,
master: templateMaster?.id,
registration_form: registrationFormIds[index]
};
// Sauvegarde des templates clonés dans la base de données
const data = {
name: `clone_${clonedDocument.id}`,
template_id: clonedDocument.id,
master: templateMaster?.id,
registration_form: registrationFormIds[index]
};
createRegistrationTemplates(data, csrfToken)
.then(response => {
logger.debug('Template enregistré avec succès:', response);
})
.catch(error => {
logger.error('Erreur lors de l\'enregistrement du template:', error);
});
createRegistrationTemplates(data, csrfToken)
.then(response => {
logger.debug('Template enregistré avec succès:', response);
onSuccess();
})
.catch(error => {
logger.error('Erreur lors de l\'enregistrement du template:', error);
});
// Logique pour envoyer chaque template au submitter
logger.debug('Sending template to:', email);
})
.catch(error => {
logger.error('Error during cloning or sending:', error);
});
});
// Logique pour envoyer chaque template au submitter
logger.debug('Sending template to:', email);
})
.catch(error => {
logger.error('Error during cloning or sending:', error);
});
});
}
};
const cloneTemplate = (templateId, email) => {
@ -161,7 +178,7 @@ export default function FileUpload({ handleCreateTemplateMaster, fileToEdit = nu
errorMsg={null}
/>
</div>
<div className="col-span-7">
<div className="col-span-8">
{token && (
<DocusealBuilder
token={token}
@ -169,11 +186,13 @@ export default function FileUpload({ handleCreateTemplateMaster, fileToEdit = nu
'Authorization': `Bearer ${token}`
}}
withSendButton={false}
withSaveButton={false}
withSignYourselfButton={false}
autosave={true}
autosave={false}
language={'fr'}
onLoad={handleLoad}
onUpload={handleUpload}
onSave={handleSubmit}
className="h-full overflow-auto" // Ajouter overflow-auto pour permettre le défilement
style={{ maxHeight: '70vh' }} // Limiter la hauteur maximale du composant
// Il faut auter l'host correspondant (une fois passé en HTTPS)
@ -181,19 +200,6 @@ export default function FileUpload({ handleCreateTemplateMaster, fileToEdit = nu
/>
)}
</div>
<div className="col-span-1 flex justify-end">
<Button
text="Valider"
onClick={handleSubmit}
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
(uploadedFileName === '' || selectedGroups.length === 0)
? "bg-gray-300 text-gray-700 cursor-not-allowed"
: "bg-emerald-500 text-white hover:bg-emerald-600"
}`}
primary
disabled={uploadedFileName === '' || selectedGroups.length === 0}
/>
</div>
</div>
</div>
);

View File

@ -1,27 +1,26 @@
import React, { useState, useEffect } from 'react';
import { Plus, Download, Edit, Trash2, FolderPlus, Signature } from 'lucide-react';
import { Plus, Download, Edit3, Trash2, FolderPlus, Signature } from 'lucide-react';
import Modal from '@/components/Modal';
import Table from '@/components/Table';
import FileUpload from '@/components/Structure/Files/FileUpload';
import { formatDate } from '@/utils/Date';
import { BASE_URL } from '@/utils/Url';
import {
fetchRegistrationTemplateMaster,
createRegistrationTemplateMaster,
editRegistrationTemplateMaster,
deleteRegistrationTemplateMaster,
getRegisterFormFileTemplate
} from '@/app/actions/subscriptionAction';
import {
fetchRegistrationFileGroups,
createRegistrationFileGroup,
deleteRegistrationFileGroup,
editRegistrationFileGroup
editRegistrationFileGroup,
fetchRegistrationTemplateMaster,
createRegistrationTemplateMaster,
editRegistrationTemplateMaster,
deleteRegistrationTemplateMaster,
fetchRegistrationTemplates
} from '@/app/actions/registerFileGroupAction';
import RegistrationFileGroupForm from '@/components/Structure/Files/RegistrationFileGroupForm';
import logger from '@/utils/logger';
export default function FilesGroupsManagement({ csrfToken }) {
const [fichiers, setFichiers] = useState([]);
const [templateMasters, setTemplateMasters] = useState([]);
const [templates, setTemplates] = useState([]);
const [groups, setGroups] = useState([]);
const [selectedGroup, setSelectedGroup] = useState(null);
const [isModalOpen, setIsModalOpen] = useState(false);
@ -29,6 +28,11 @@ export default function FilesGroupsManagement({ csrfToken }) {
const [fileToEdit, setFileToEdit] = useState(null);
const [isGroupModalOpen, setIsGroupModalOpen] = useState(false);
const [groupToEdit, setGroupToEdit] = useState(null);
const [reloadTemplates, setReloadTemplates] = useState(false);
const handleReloadTemplates = () => {
setReloadTemplates(true);
}
const transformFileData = (file, groups) => {
const groupInfos = file.groups.map(groupId => groups.find(g => g.id === groupId) || { id: groupId, name: 'Groupe inconnu' });
@ -41,38 +45,91 @@ export default function FilesGroupsManagement({ csrfToken }) {
useEffect(() => {
Promise.all([
fetchRegistrationTemplateMaster(),
fetchRegistrationFileGroups()
]).then(([filesData, groupsData]) => {
fetchRegistrationFileGroups(),
fetchRegistrationTemplates()
]).then(([filesTemplateMasters, groupsData, filesTemplates]) => {
setGroups(groupsData);
setTemplates(filesTemplates);
console.log("coucou : ", filesTemplates)
// Sélectionner automatiquement le premier groupe s'il existe
if (groupsData.length > 0) {
setSelectedGroup(groupsData[0].id.toString());
}
// Transformer chaque fichier pour inclure les informations complètes du groupe
const transformedFiles = filesData.map(file => transformFileData(file, groupsData));
setFichiers(transformedFiles);
const transformedFiles = filesTemplateMasters.map(file => transformFileData(file, groupsData));
setTemplateMasters(transformedFiles);
}).catch(err => {
console.log(err.message);
}).finally(() => {
setReloadTemplates(false);
});
}, []);
}, [reloadTemplates]);
const handleFileDelete = (fileId) => {
deleteRegistrationTemplateMaster(fileId, csrfToken)
.then(response => {
if (response.ok) {
setFichiers(fichiers.filter(fichier => fichier.id !== fileId));
alert('Fichier supprimé avec succès.');
const deleteTemplateMaster = (templateMaster) => {
// Supprimer les clones associés via l'API DocuSeal
console.log(templates)
const removeClonesPromises = templates
.filter(template => template.master === templateMaster.template_id)
.map(template => removeTemplate(template.template_id));
// Ajouter la suppression du master à la liste des promesses
removeClonesPromises.push(removeTemplate(templateMaster.template_id));
// Attendre que toutes les suppressions dans DocuSeal soient terminées
Promise.all(removeClonesPromises)
.then(responses => {
const allSuccessful = responses.every(response => response.ok);
if (allSuccessful) {
logger.debug('Master et clones supprimés avec succès de DocuSeal.');
// Supprimer le template master de la base de données
deleteRegistrationTemplateMaster(templateMaster.template_id, csrfToken)
.then(response => {
if (response.ok) {
setTemplateMasters(templateMasters.filter(fichier => fichier.template_id !== templateMaster.template_id));
alert('Fichier supprimé avec succès.');
} else {
alert('Erreur lors de la suppression du fichier dans la base de données.');
}
})
.catch(error => {
console.error('Error deleting file from database:', error);
alert('Erreur lors de la suppression du fichier dans la base de données.');
});
} else {
alert('Erreur lors de la suppression du fichier.');
alert('Erreur lors de la suppression du master ou des clones dans DocuSeal.');
}
})
.catch(error => {
console.error('Error deleting file:', error);
alert('Erreur lors de la suppression du fichier.');
console.error('Error removing template from DocuSeal:', error);
alert('Erreur lors de la suppression du master ou des clones dans DocuSeal.');
});
};
const handleFileEdit = (file) => {
const removeTemplate = (templateId) => {
return fetch('/api/docuseal/removeTemplate/', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({
templateId
})
})
.then(response => {
if (!response.ok) {
return response.json().then(err => { throw new Error(err.message); });
}
return response;
})
.catch(error => {
console.error('Error removing template:', error);
throw error;
});
};
const editTemplateMaster = (file) => {
setIsEditing(true);
setFileToEdit(file);
setIsModalOpen(true);
@ -84,87 +141,40 @@ export default function FilesGroupsManagement({ csrfToken }) {
template_id: template_id,
groups: group_ids
};
console.log(data);
logger.debug(data);
if (isEditing && fileToEdit) {
editRegistrationTemplateMaster(fileToEdit.id, data, csrfToken)
.then(data => {
// Transformer le fichier mis à jour avec les informations du groupe
const transformedFile = transformFileData(data, groups);
setFichiers(prevFichiers =>
prevFichiers.map(f => f.id === fileToEdit.id ? transformedFile : f)
);
setIsModalOpen(false);
setFileToEdit(null);
setIsEditing(false);
})
.catch(error => {
console.error('Error editing file:', error);
alert('Erreur lors de la modification du fichier');
});
} else {
createRegistrationTemplateMaster(data, csrfToken)
.then(data => {
// Transformer le nouveau fichier avec les informations du groupe
const transformedFile = transformFileData(data, groups);
setFichiers(prevFiles => [...prevFiles, transformedFile]);
setIsModalOpen(false);
})
.catch(error => {
console.error('Error uploading file:', error);
});
}
createRegistrationTemplateMaster(data, csrfToken)
.then(data => {
// Transformer le nouveau fichier avec les informations du groupe
const transformedFile = transformFileData(data, groups);
setTemplateMasters(prevFiles => [...prevFiles, transformedFile]);
setIsModalOpen(false);
})
.catch(error => {
console.error('Error uploading file:', error);
});
};
const handleTemplate = ({name, is_required, order, groupId, document_id}) => {
if (!name) {
alert('Veuillez entrer un nom de fichier.');
return;
}
const handleEditTemplateMaster = ({name, group_ids, template_id}) => {
const data = {
name: name,
template_id: template_id,
groups: group_ids
};
logger.debug(data);
const formData = new FormData();
if(file) {
formData.append('file', file);
}
formData.append('name', name);
formData.append('is_required', is_required);
formData.append('order', order);
formData.append('document_id', document_id);
// Modification ici : vérifier si groupId existe et n'est pas vide
if (groupId && groupId !== '') {
formData.append('group', groupId); // Notez que le nom du champ est 'group' et non 'group_id'
}
if (isEditing && fileToEdit) {
editRegistrationTemplateMaster(fileToEdit.id, formData, csrfToken)
.then(data => {
// Transformer le fichier mis à jour avec les informations du groupe
const transformedFile = transformFileData(data, groups);
setFichiers(prevFichiers =>
prevFichiers.map(f => f.id === fileToEdit.id ? transformedFile : f)
);
setIsModalOpen(false);
setFileToEdit(null);
setIsEditing(false);
})
.catch(error => {
console.error('Error editing file:', error);
alert('Erreur lors de la modification du fichier');
});
} else {
createRegistrationTemplateMaster(formData, csrfToken)
.then(data => {
// Transformer le nouveau fichier avec les informations du groupe
const transformedFile = transformFileData(data, groups);
setFichiers(prevFiles => [...prevFiles, transformedFile]);
setIsModalOpen(false);
})
.catch(error => {
console.error('Error uploading file:', error);
});
}
editRegistrationTemplateMaster(template_id, data, csrfToken)
.then(data => {
// Transformer le fichier mis à jour avec les informations du groupe
const transformedFile = transformFileData(data, groups);
setTemplateMasters(prevFichiers =>
prevFichiers.map(f => f.id === template_id ? transformedFile : f)
);
})
.catch(error => {
console.error('Error editing file:', error);
alert('Erreur lors de la modification du fichier');
});
};
const handleGroupSubmit = (groupData) => {
@ -198,10 +208,10 @@ export default function FilesGroupsManagement({ csrfToken }) {
};
const handleGroupDelete = (groupId) => {
// Vérifier si des fichiers utilisent ce groupe
const filesInGroup = fichiers.filter(file => file.group && file.group.id === groupId);
// Vérifier si des templateMasters utilisent ce groupe
const filesInGroup = templateMasters.filter(file => file.group && file.group.id === groupId);
if (filesInGroup.length > 0) {
alert('Impossible de supprimer ce groupe car il contient des fichiers. Veuillez d\'abord retirer tous les fichiers de ce groupe.');
alert('Impossible de supprimer ce groupe car il contient des templateMasters. Veuillez d\'abord retirer tous les templateMasters de ce groupe.');
return;
}
@ -224,7 +234,7 @@ export default function FilesGroupsManagement({ csrfToken }) {
}
};
const filteredFiles = fichiers.filter(file => {
const filteredFiles = templateMasters.filter(file => {
if (!selectedGroup) return true;
return file.groups && file.groups.some(group => group.id === parseInt(selectedGroup));
});
@ -236,14 +246,14 @@ export default function FilesGroupsManagement({ csrfToken }) {
<div className="flex items-center justify-center gap-2">
{row.file && (
<a href={`${BASE_URL}${row.file}`} target='_blank' className="text-blue-500 hover:text-blue-700">
<Download size={16} />
<Download className="w-5 h-5" />
</a>
)}
<button onClick={() => handleFileEdit(row)} className="text-blue-500 hover:text-blue-700">
<Edit size={16} />
<button onClick={() => editTemplateMaster(row)} className="text-blue-500 hover:text-blue-700">
<Edit3 className="w-5 h-5" />
</button>
<button onClick={() => handleFileDelete(row.id)} className="text-red-500 hover:text-red-700">
<Trash2 size={16} />
<button onClick={() => deleteTemplateMaster(row)} className="text-red-500 hover:text-red-700">
<Trash2 className="w-5 h-5" />
</button>
</div>
)}
@ -255,10 +265,10 @@ export default function FilesGroupsManagement({ csrfToken }) {
{ name: 'Actions', transform: (row) => (
<div className="flex items-center justify-center gap-2">
<button onClick={() => handleGroupEdit(row)} className="text-blue-500 hover:text-blue-700">
<Edit size={16} />
<Edit3 className="w-5 h-5" />
</button>
<button onClick={() => handleGroupDelete(row.id)} className="text-red-500 hover:text-red-700">
<Trash2 size={16} />
<Trash2 className="w-5 h-5" />
</button>
</div>
)}
@ -278,7 +288,9 @@ export default function FilesGroupsManagement({ csrfToken }) {
ContentComponent={() => (
<FileUpload
handleCreateTemplateMaster={handleCreateTemplateMaster}
handleEditTemplateMaster={handleEditTemplateMaster}
fileToEdit={fileToEdit}
onSuccess={handleReloadTemplates}
/>
)}
modalClassName='w-4/5 h-4/5'
@ -286,7 +298,7 @@ export default function FilesGroupsManagement({ csrfToken }) {
<Modal
isOpen={isGroupModalOpen}
setIsOpen={setIsGroupModalOpen}
title={groupToEdit ? "Modifier le groupe" : "Ajouter un groupe de fichiers"}
title={groupToEdit ? "Modifier le groupe" : "Ajouter un groupe de templateMasters"}
ContentComponent={() => (
<RegistrationFileGroupForm
onSubmit={handleGroupSubmit}
@ -296,7 +308,7 @@ export default function FilesGroupsManagement({ csrfToken }) {
/>
<div className="mt-8 mb-4">
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-bold">Groupes de fichiers</h2>
<h2 className="text-xl font-bold">Groupes de templateMasters</h2>
<button
onClick={() => setIsGroupModalOpen(true)}
className="flex items-center bg-blue-600 text-white p-2 rounded-full shadow hover:bg-blue-900 transition duration-200"
@ -315,7 +327,7 @@ export default function FilesGroupsManagement({ csrfToken }) {
{groups.length > 0 && (
<div className="mt-8">
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-bold">Fichiers</h2>
<h2 className="text-xl font-bold">templateMasters</h2>
<div className="flex items-center gap-4">
<select
className="border rounded p-2"

View File

@ -0,0 +1,31 @@
import { BE_DOCUSEAL_REMOVE_TEMPLATE } from '@/utils/Url';
export default function handler(req, res) {
if (req.method === 'DELETE') {
const { templateId } = req.body;
fetch(`${BE_DOCUSEAL_REMOVE_TEMPLATE}/${templateId}`, {
method: 'DELETE',
headers: {
'X-Auth-Token': process.env.DOCUSEAL_API_KEY
}
})
.then(response => {
if (!response.ok) {
return response.json().then(err => { throw new Error(err.message); });
}
return response.json();
})
.then(data => {
console.log('Template removed successfully:', data);
res.status(200).json(data);
})
.catch(error => {
console.error('Error removing template:', error);
res.status(500).json({ error: 'Internal Server Error' });
});
} else {
res.setHeader('Allow', ['DELETE']);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
}

View File

@ -7,6 +7,7 @@ export const BASE_URL = process.env.NEXT_PUBLIC_API_URL;
// GESTION DocuSeal
export const BE_DOCUSEAL_GET_JWT = `${BASE_URL}/DocuSeal/generateToken`
export const BE_DOCUSEAL_CLONE_TEMPLATE = `${BASE_URL}/DocuSeal/cloneTemplate`
export const BE_DOCUSEAL_REMOVE_TEMPLATE = `${BASE_URL}/DocuSeal/removeTemplate`
// GESTION LOGIN
export const BE_AUTH_NEW_PASSWORD_URL = `${BASE_URL}/Auth/newPassword`