feat: Ajout des Bundles de fichiers [#24]

This commit is contained in:
Luc SORIGNET
2025-02-10 18:35:24 +01:00
parent fb7fbaf839
commit ffc6ce8de8
25 changed files with 1736 additions and 743 deletions

View File

@ -0,0 +1,302 @@
import React, { useState, useEffect } from 'react';
import { Plus, Download, Edit, Trash2, FolderPlus } from 'lucide-react';
import Modal from '@/components/Modal';
import Table from '@/components/Table';
import FileUpload from '@/components/FileUpload';
import { formatDate } from '@/utils/Date';
import { BASE_URL } from '@/utils/Url';
import {
fetchRegisterFormFileTemplate,
createRegistrationFormFileTemplate,
editRegistrationFormFileTemplate,
deleteRegisterFormFileTemplate,
getRegisterFormFileTemplate
} from '@/app/lib/subscriptionAction';
import {
fetchRegistrationFileGroups,
createRegistrationFileGroup,
deleteRegistrationFileGroup,
editRegistrationFileGroup
} from '@/app/lib/registerFileGroupAction';
import RegistrationFileGroupForm from '@/components/RegistrationFileGroupForm';
export default function FilesManagement({ csrfToken }) {
const [fichiers, setFichiers] = useState([]);
const [groups, setGroups] = useState([]);
const [selectedGroup, setSelectedGroup] = useState(null);
const [isModalOpen, setIsModalOpen] = useState(false);
const [isEditing, setIsEditing] = useState(false);
const [fileToEdit, setFileToEdit] = useState(null);
const [isGroupModalOpen, setIsGroupModalOpen] = useState(false);
const [groupToEdit, setGroupToEdit] = useState(null);
// Fonction pour transformer les données des fichiers avec les informations complètes du groupe
const transformFileData = (file, groups) => {
if (!file.group) return file;
const groupInfo = groups.find(g => g.id === file.group);
return {
...file,
group: groupInfo || { id: file.group, name: 'Groupe inconnu' }
};
};
useEffect(() => {
Promise.all([
fetchRegisterFormFileTemplate(),
fetchRegistrationFileGroups()
]).then(([filesData, groupsData]) => {
setGroups(groupsData);
// 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);
}).catch(err => {
console.log(err.message);
});
}, []);
const handleFileDelete = (fileId) => {
deleteRegisterFormFileTemplate(fileId, csrfToken)
.then(response => {
if (response.ok) {
setFichiers(fichiers.filter(fichier => fichier.id !== fileId));
alert('Fichier supprimé avec succès.');
} else {
alert('Erreur lors de la suppression du fichier.');
}
})
.catch(error => {
console.error('Error deleting file:', error);
alert('Erreur lors de la suppression du fichier.');
});
};
const handleFileEdit = (file) => {
setIsEditing(true);
setFileToEdit(file);
setIsModalOpen(true);
};
const handleFileUpload = ({file, name, is_required, order, groupId}) => {
if (!name) {
alert('Veuillez entrer un nom de fichier.');
return;
}
const formData = new FormData();
if(file) {
formData.append('file', file);
}
formData.append('name', name);
formData.append('is_required', is_required);
formData.append('order', order);
// 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) {
editRegistrationFormFileTemplate(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 {
createRegistrationFormFileTemplate(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);
});
}
};
const handleGroupSubmit = async (groupData) => {
try {
if (groupToEdit) {
const updatedGroup = await editRegistrationFileGroup(groupToEdit.id, groupData, csrfToken);
setGroups(groups.map(group => group.id === groupToEdit.id ? updatedGroup : group));
setGroupToEdit(null);
} else {
const newGroup = await createRegistrationFileGroup(groupData, csrfToken);
setGroups([...groups, newGroup]);
}
setIsGroupModalOpen(false);
} catch (error) {
console.error('Error handling group:', error);
alert('Erreur lors de l\'opération sur le groupe');
}
};
const handleGroupEdit = (group) => {
setGroupToEdit(group);
setIsGroupModalOpen(true);
};
const handleGroupDelete = (groupId) => {
// Vérifier si des fichiers utilisent ce groupe
const filesInGroup = fichiers.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.');
return;
}
if (window.confirm('Êtes-vous sûr de vouloir supprimer ce groupe ?')) {
deleteRegistrationFileGroup(groupId, csrfToken)
.then((response) => {
if (response.status === 409) {
throw new Error('Ce groupe est lié à des inscriptions existantes.');
}
if (!response.ok) {
throw new Error('Erreur lors de la suppression du groupe.');
}
setGroups(groups.filter(group => group.id !== groupId));
alert('Groupe supprimé avec succès.');
})
.catch(error => {
console.error('Error deleting group:', error);
alert(error.message || 'Erreur lors de la suppression du groupe. Vérifiez qu\'aucune inscription n\'utilise ce groupe.');
});
}
};
// Ajouter cette fonction de filtrage
const filteredFiles = fichiers.filter(file => {
if (!selectedGroup) return true;
return file.group && file.group.id === parseInt(selectedGroup);
});
const columnsFiles = [
{ name: 'Nom du fichier', transform: (row) => row.name },
{ name: 'Groupe', transform: (row) => row.group ? row.group.name : 'Aucun' },
{ name: 'Date de création', transform: (row) => formatDate(new Date (row.date_added),"DD/MM/YYYY hh:mm:ss") },
{ name: 'Fichier Obligatoire', transform: (row) => row.is_required ? 'Oui' : 'Non' },
{ name: 'Ordre de fusion', transform: (row) => row.order },
{ name: 'Actions', transform: (row) => (
<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} />
</a>
)}
<button onClick={() => handleFileEdit(row)} className="text-blue-500 hover:text-blue-700">
<Edit size={16} />
</button>
<button onClick={() => handleFileDelete(row.id)} className="text-red-500 hover:text-red-700">
<Trash2 size={16} />
</button>
</div>
)}
];
const columnsGroups = [
{ name: 'Nom du groupe', transform: (row) => row.name },
{ name: 'Description', transform: (row) => row.description },
{ 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} />
</button>
<button onClick={() => handleGroupDelete(row.id)} className="text-red-500 hover:text-red-700">
<Trash2 size={16} />
</button>
</div>
)}
];
return (
<div>
<Modal
isOpen={isModalOpen}
setIsOpen={setIsModalOpen}
title={isEditing ? 'Modifier un fichier' : 'Ajouter un fichier'}
ContentComponent={() => (
<FileUpload
onFileUpload={handleFileUpload}
fileToEdit={fileToEdit}
/>
)}
/>
<Modal
isOpen={isGroupModalOpen}
setIsOpen={setIsGroupModalOpen}
title={groupToEdit ? "Modifier le groupe" : "Ajouter un groupe de fichiers"}
ContentComponent={() => (
<RegistrationFileGroupForm
onSubmit={handleGroupSubmit}
initialData={groupToEdit}
/>
)}
/>
<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>
<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"
>
<FolderPlus className="w-5 h-5" />
</button>
</div>
<Table
data={groups}
columns={columnsGroups}
itemsPerPage={5}
currentPage={1}
totalPages={Math.ceil(groups.length / 5)}
/>
</div>
{groups.length > 0 && (
<div className="mt-8">
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-bold">Fichiers</h2>
<div className="flex items-center gap-4">
<select
className="border rounded p-2"
value={selectedGroup || ''}
onChange={(e) => setSelectedGroup(e.target.value)}
>
<option value="">Tous les groupes</option>
{groups.map(group => (
<option key={group.id} value={group.id}>{group.name}</option>
))}
</select>
<button
onClick={() => { setIsModalOpen(true); setIsEditing(false); }}
className="flex items-center bg-emerald-600 text-white p-2 rounded-full shadow hover:bg-emerald-900 transition duration-200"
>
<Plus className="w-5 h-5" />
</button>
</div>
</div>
<Table
data={filteredFiles}
columns={columnsFiles}
itemsPerPage={10}
currentPage={1}
totalPages={Math.ceil(filteredFiles.length / 10)}
/>
</div>
)}
</div>
);
}