import React, { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { Edit, Trash2, FileText, Star, ChevronDown, Plus } from 'lucide-react'; import Modal from '@/components/Modal'; import { // GET fetchRegistrationFileGroups, fetchRegistrationSchoolFileMasters, fetchRegistrationParentFileMasters, // POST createRegistrationFileGroup, createRegistrationSchoolFileMaster, createRegistrationParentFileMaster, // PUT editRegistrationFileGroup, editRegistrationSchoolFileMaster, editRegistrationParentFileMaster, // DELETE deleteRegistrationFileGroup, deleteRegistrationSchoolFileMaster, deleteRegistrationParentFileMaster, } from '@/app/actions/registerFileGroupAction'; import RegistrationFileGroupForm from '@/components/Structure/Files/RegistrationFileGroupForm'; import logger from '@/utils/logger'; import Popup from '@/components/Popup'; import Loader from '@/components/Loader'; import { useNotification } from '@/context/NotificationContext'; import FileUpload from '@/components/Form/FileUpload'; import SectionTitle from '@/components/SectionTitle'; import DropdownMenu from '@/components/DropdownMenu'; import CheckBox from '@/components/Form/CheckBox'; import Button from '@/components/Form/Button'; import InputText from '@/components/Form/InputText'; import { getSecureFileUrl } from '@/utils/fileUrl'; import { FE_ADMIN_STRUCTURE_FORM_BUILDER_URL } from '@/utils/Url'; function getItemBgColor(type, selected, forceTheme = false) { // Colonne gauche : blanc si rien n'est sélectionné, emerald si sélectionné if (type === 'blue') { if (selected) return 'bg-primary/10'; return 'bg-white'; } // Colonne droite : thème selon type, jamais sélectionné if (forceTheme) { if (type === 'emerald') return 'bg-primary/5'; if (type === 'orange') return 'bg-orange-50'; return 'bg-gray-50'; } return 'bg-white'; } function SimpleList({ items, onSelect, selectedId, actionButtons, getItemType, title, minHeight = 'min-h-[200px]', selectable = true, forceTheme = false, headerClassName = '', listClassName = '', itemClassName = '', headerContent = null, showGroups = false, groupDocCount = null, }) { return (
{title && (
{headerContent ? ( headerContent ) : ( {title} )}
)}
); } export default function FilesGroupsManagement({ csrfToken, selectedEstablishmentId, profileRole, }) { const [schoolFileMasters, setSchoolFileMasters] = useState([]); const [parentFiles, setParentFileMasters] = useState([]); const [groups, setGroups] = useState([]); const router = useRouter(); const [isEditing, setIsEditing] = useState(false); const [fileToEdit, setFileToEdit] = useState(null); const [isGroupModalOpen, setIsGroupModalOpen] = useState(false); const [groupToEdit, setGroupToEdit] = useState(null); const [removePopupVisible, setRemovePopupVisible] = useState(false); const [removePopupMessage, setRemovePopupMessage] = useState(''); const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {}); const [isLoading, setIsLoading] = useState(false); const [selectedGroupId, setSelectedGroupId] = useState(null); const [showHelp, setShowHelp] = useState(false); const { showNotification } = useNotification(); const [isParentFileModalOpen, setIsParentFileModalOpen] = useState(false); const [editingParentFile, setEditingParentFile] = useState(null); // Pour la popup "Télécharger un document existant" const [isFileUploadPopupOpen, setIsFileUploadPopupOpen] = useState(false); // Dropdown pour création de document const [isDocDropdownOpen, setIsDocDropdownOpen] = useState(false); // Handler pour le dropdown document (ouvre la bonne modale) const handleDocDropdownSelect = (type) => { setIsDocDropdownOpen(false); if (type === 'formulaire') { const groupParam = selectedGroupId ? `?groupId=${selectedGroupId}` : ''; router.push(`${FE_ADMIN_STRUCTURE_FORM_BUILDER_URL}${groupParam}`); } else if (type === 'formulaire_existant') { setIsFileUploadPopupOpen(true); setFileToEdit({}); } else if (type === 'parent') { setEditingParentFile(null); setIsParentFileModalOpen(true); } }; const transformFileData = (file, groups) => { // file.groups peut contenir des IDs (number/string) ou des objets {id, name} const groupInfos = (file.groups || []).map((group) => { if (typeof group === 'object' && group !== null && 'id' in group) { // Déjà un objet groupe const found = groups.find((g) => g.id === group.id); return found || group; } else { // C'est un ID return ( groups.find((g) => g.id === group) || { id: group, name: 'Groupe inconnu', } ); } }); return { ...file, groups: groupInfos, }; }; // Ne pas transformer ici, stocker la donnée brute useEffect(() => { if (selectedEstablishmentId) { Promise.all([ fetchRegistrationSchoolFileMasters(selectedEstablishmentId), fetchRegistrationFileGroups(selectedEstablishmentId), fetchRegistrationParentFileMasters(selectedEstablishmentId), ]) .then(([dataSchoolFileMasters, groupsData, dataParentFileMasters]) => { setGroups(groupsData); setParentFileMasters(dataParentFileMasters); setSchoolFileMasters(dataSchoolFileMasters); // donnée brute }) .catch((err) => { logger.debug(err.message); }); } }, [selectedEstablishmentId]); const deleteTemplateMaster = (templateMaster) => { setRemovePopupVisible(true); setRemovePopupMessage( `Attention ! \nVous êtes sur le point de supprimer le formulaire "${templateMaster.name}".\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?` ); setRemovePopupOnConfirm(() => () => { setIsLoading(true); // Supprimer le formulaire de la base de données deleteRegistrationSchoolFileMaster(templateMaster.id, csrfToken) .then((response) => { if (response.ok) { setSchoolFileMasters( schoolFileMasters.filter( (fichier) => fichier.id !== templateMaster.id ) ); showNotification( `Le formulaire "${templateMaster.name}" a été correctement supprimé.`, 'success', 'Succès' ); setRemovePopupVisible(false); } else { showNotification( `Erreur lors de la suppression du formulaire "${templateMaster.name}".`, 'error', 'Erreur' ); setRemovePopupVisible(false); } }) .catch((error) => { logger.error('Error deleting file from database:', error); showNotification( `Erreur lors de la suppression du formulaire "${templateMaster.name}".`, 'error', 'Erreur' ); setRemovePopupVisible(false); }) .finally(() => { setIsLoading(false); }); }); }; const editTemplateMaster = (file) => { const isDynamic = file.formMasterData && Array.isArray(file.formMasterData.fields) && file.formMasterData.fields.length > 0; if (isDynamic) { router.push(`${FE_ADMIN_STRUCTURE_FORM_BUILDER_URL}?id=${file.id}`); } else { setFileToEdit(file); setIsEditing(true); setIsFileUploadPopupOpen(true); } }; const handleCreateSchoolFileMaster = ( { name, group_ids, formMasterData, file, requires_electronic_signature, }, onCreated ) => { // Toujours envoyer en FormData, même sans fichier const dataToSend = new FormData(); const jsonData = { name, groups: group_ids, formMasterData, establishment: selectedEstablishmentId, requires_electronic_signature: requires_electronic_signature || false, }; dataToSend.append('data', JSON.stringify(jsonData)); if (file) { // Récupérer l'extension du fichier d'origine let extension = ''; if (file.name && file.name.lastIndexOf('.') !== -1) { extension = file.name.substring(file.name.lastIndexOf('.')); } // Nettoyer le nom saisi pour le fichier (éviter les caractères spéciaux) const cleanName = (name || 'document') .replace(/[^a-zA-Z0-9_\-]/g, '_') .replace(/_+/g, '_') .replace(/^_+|_+$/g, ''); // Générer le nom de fichier final const finalFileName = `${cleanName}${extension}`; dataToSend.append('file', file, finalFileName); } createRegistrationSchoolFileMaster(dataToSend, csrfToken) .then((data) => { setSchoolFileMasters((prevFiles) => [...prevFiles, data]); showNotification( `Le formulaire "${name}" a été créé avec succès.`, 'success', 'Succès' ); if (onCreated) onCreated(data); }) .catch((error) => { logger.error('Error creating form:', error); showNotification( 'Erreur lors de la création du formulaire', 'error', 'Erreur' ); }); }; const handleEditSchoolFileMaster = ({ name, group_ids, formMasterData, id, file, requires_electronic_signature, }) => { // Correction : normaliser group_ids pour ne garder que les IDs (number/string) let normalizedGroupIds = []; if (Array.isArray(group_ids)) { normalizedGroupIds = group_ids.map((g) => typeof g === 'object' && g !== null && 'id' in g ? g.id : g ); } const dataToSend = new FormData(); const jsonData = { name: name, groups: normalizedGroupIds, formMasterData: formMasterData, establishment: selectedEstablishmentId, requires_electronic_signature: requires_electronic_signature || false, }; dataToSend.append('data', JSON.stringify(jsonData)); // Cas 1 : Nouveau fichier sélectionné (File/Blob) if (file instanceof File || file instanceof Blob) { let extension = ''; if (file.name && file.name.lastIndexOf('.') !== -1) { extension = file.name.substring(file.name.lastIndexOf('.')); } const cleanName = (name || 'document') .replace(/[^a-zA-Z0-9_\-]/g, '_') .replace(/_+/g, '_') .replace(/^_+|_+$/g, ''); const finalFileName = `${cleanName}${extension}`; dataToSend.append('file', file, finalFileName); } // Cas 2 : Pas de nouveau fichier, mais le nom a changé → renvoyer le fichier existant avec le nouveau nom else if (typeof file === 'string' && file) { // Extraire l'extension du path existant let extension = ''; const lastDot = file.lastIndexOf('.'); if (lastDot !== -1) { extension = file.substring(lastDot); } const cleanName = (name || 'document') .replace(/[^a-zA-Z0-9_\-]/g, '_') .replace(/_+/g, '_') .replace(/^_+|_+$/g, ''); const finalFileName = `${cleanName}${extension}`; // Correction : il faut récupérer le fichier à l'URL d'origine, pas à la nouvelle URL renommée // On utilise le path original (file) pour le fetch, pas le chemin avec le nouveau nom fetch(getSecureFileUrl(file)) .then((response) => { if (!response.ok) throw new Error('Fichier distant introuvable'); return response.blob(); }) .then((blob) => { dataToSend.append('file', blob, finalFileName); editRegistrationSchoolFileMaster(id, dataToSend, csrfToken) .then((data) => { setSchoolFileMasters((prevFichiers) => prevFichiers.map((f) => (f.id === id ? data : f)) ); showNotification( `Le formulaire "${name}" a été modifié avec succès.`, 'success', 'Succès' ); }) .catch((error) => { logger.error('Error editing form:', error); showNotification( 'Erreur lors de la modification du formulaire', 'error', 'Erreur' ); }); }) .catch((error) => { logger.error( 'Erreur lors de la récupération du fichier existant pour renommage:', error ); showNotification( 'Erreur lors de la récupération du fichier existant pour renommage', 'error', 'Erreur' ); }); return; // On sort ici car l'appel API est fait dans le fetch } // Cas standard (nouveau fichier ou pas de renommage) editRegistrationSchoolFileMaster(id, dataToSend, csrfToken) .then((data) => { setSchoolFileMasters((prevFichiers) => prevFichiers.map((f) => (f.id === id ? data : f)) ); showNotification( `Le formulaire "${name}" a été modifié avec succès.`, 'success', 'Succès' ); }) .catch((error) => { logger.error('Error editing form:', error); showNotification( 'Erreur lors de la modification du formulaire', 'error', 'Erreur' ); }); }; const handleGroupSubmit = (groupData) => { if (groupToEdit) { editRegistrationFileGroup(groupToEdit.id, groupData, csrfToken) .then((updatedGroup) => { setGroups( groups.map((group) => group.id === groupToEdit.id ? updatedGroup : group ) ); setGroupToEdit(null); setIsGroupModalOpen(false); }) .catch((error) => { logger.error('Error handling group:', error); showNotification( "Erreur lors de l'opération sur le groupe", 'error', 'Erreur' ); }); } else { // Ajouter l'établissement sélectionné lors de la création d'un nouveau groupe const newGroupData = { ...groupData, establishment: selectedEstablishmentId, }; createRegistrationFileGroup(newGroupData, csrfToken) .then((newGroup) => { setGroups([...groups, newGroup]); setIsGroupModalOpen(false); }) .catch((error) => { logger.error('Error handling group:', error); showNotification( "Erreur lors de l'opération sur le groupe", 'error', 'Erreur' ); }); } }; const handleGroupEdit = (group) => { setGroupToEdit(group); setIsGroupModalOpen(true); }; // Handler pour sélectionner/désélectionner un groupe (simple) const handleGroupSelect = (groupId) => { setSelectedGroupId((prev) => (prev === groupId ? null : groupId)); }; // Handler pour tout désélectionner const clearGroupSelection = () => setSelectedGroupId(null); const handleGroupDelete = (groupId) => { // Vérifier si des schoolFileMasters utilisent ce groupe const filesInGroup = schoolFileMasters.filter( (file) => file.group && file.group.id === groupId ); if (filesInGroup.length > 0) { showNotification( "Impossible de supprimer ce groupe car il contient déjà des formulaires. Veuillez d'abord retirer tous les formules de ce groupe.", 'error', 'Erreur' ); return; } setRemovePopupVisible(true); setRemovePopupMessage( 'Attentions ! \nÊtes-vous sûr de vouloir supprimer ce groupe ?' ); setRemovePopupOnConfirm(() => () => { setIsLoading(true); 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)); // Purger la sélection si le groupe supprimé était sélectionné setSelectedGroupId((prev) => (prev === groupId ? null : prev)); setRemovePopupVisible(false); setIsLoading(false); showNotification('Groupe supprimé avec succès.', 'success', 'Succès'); }) .catch((error) => { logger.error('Error deleting group:', error); setRemovePopupVisible(false); setIsLoading(false); showNotification( error.message || "Erreur lors de la suppression du groupe. Vérifiez qu'aucune inscription n'utilise ce groupe.", 'error', 'Erreur' ); }); }); }; const handleCreate = (newParentFile) => { return createRegistrationParentFileMaster(newParentFile, csrfToken) .then((response) => { const createdFile = response; // Ajouter le nouveau fichier parent à la liste existante setParentFileMasters((prevFiles) => [...prevFiles, createdFile]); logger.debug('Document parent créé avec succès:', createdFile); return createdFile; }) .catch((error) => { logger.error('Erreur lors de la création du document parent:', error); showNotification( 'Une erreur est survenue lors de la création du document parent.', 'error', 'Erreur' ); throw error; }); }; // Correction du bug : ne pas supprimer l'élément lors de l'édition d'un doc parent const handleEdit = (id, updatedFile) => { logger.debug( '[FilesGroupsManagement] handleEdit called with:', id, updatedFile ); if (typeof updatedFile !== 'object' || updatedFile === null) { logger.error( '[FilesGroupsManagement] handleEdit: updatedFile is not an object', updatedFile ); return Promise.reject(new Error('updatedFile is not an object')); } logger.debug( '[FilesGroupsManagement] handleEdit payload:', JSON.stringify(updatedFile) ); return editRegistrationParentFileMaster(id, updatedFile, csrfToken) .then((response) => { logger.debug( '[FilesGroupsManagement] editRegistrationParentFileMaster response:', response ); const modifiedFile = response.data || response; setParentFileMasters((prevFiles) => prevFiles.map((file) => (file.id === id ? modifiedFile : file)) ); // Correction : ne pas filtrer/supprimer l'élément, juste le remplacer logger.debug('Document parent mis à jour avec succès:', modifiedFile); return modifiedFile; }) .catch((error) => { logger.error( 'Erreur lors de la modification du document parent:', error ); showNotification( 'Une erreur est survenue lors de la modification du document parent.', 'error', 'Erreur' ); throw error; }); }; const handleDelete = (id) => { // Vérification avant suppression : afficher une popup de confirmation setRemovePopupMessage( "Attention !\nVous êtes sur le point de supprimer la pièce à fournir.\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?" ); setRemovePopupOnConfirm(() => () => { deleteRegistrationParentFileMaster(id, csrfToken) .then(() => { setParentFileMasters((prevFiles) => prevFiles.filter((file) => file.id !== id) ); logger.debug('Document parent supprimé avec succès:', id); showNotification( 'La pièce à fournir a été supprimée avec succès.', 'success', 'Succès' ); setRemovePopupVisible(false); }) .catch((error) => { logger.error( 'Erreur lors de la suppression du fichier parent:', error ); showNotification( 'Erreur lors de la suppression de la pièce à fournir.', 'error', 'Erreur' ); setRemovePopupVisible(false); }); }); setRemovePopupVisible(true); }; // Ouvre la modale de création d'une pièce à fournir const openParentFileModal = () => { setEditingParentFile(null); setIsParentFileModalOpen(true); }; // Ouvre la modale d'édition d'une pièce à fournir const openEditParentFileModal = (file) => { setEditingParentFile(file); setIsParentFileModalOpen(true); setIsEditing(true); }; // Ferme la modale de pièce à fournir const closeParentFileModal = () => { setEditingParentFile(null); setIsParentFileModalOpen(false); }; // Nouvelle aide adaptée const renderExplanation = () => (
{showHelp && (

Gestion des dossiers et documents d'inscription

Organisation de la page :
Colonne de gauche {' '} : liste des dossiers d'inscription (groupes/classes).
Colonne de droite {' '} : liste des documents à fournir pour l'inscription.

Ajout de dossiers :
Cliquez sur le bouton{' '} + {' '} à droite de la liste pour créer un nouveau dossier d'inscription.

Ajout de documents :
Cliquez sur le bouton{' '} + {' '} à droite de la liste des documents pour ajouter :

  • Formulaire existant {' '} : importez un PDF ou autre document à faire remplir. Vous pouvez activer la signature électronique.
  • Pièce à fournir {' '} : document à déposer par la famille (ex : RIB, justificatif de domicile).
Astuce : Créez d'abord vos dossiers d'inscription avant d'ajouter des documents à fournir.
)}
); // Filtrage des formulaires et pièces selon le dossier sélectionné // Si aucun groupe sélectionné, la colonne de droite est vide let filteredFiles = []; let filteredParentFiles = []; if (selectedGroupId) { filteredFiles = schoolFileMasters .map((file) => transformFileData(file, groups)) .filter( (file) => file.groups && file.groups.some((group) => group.id === selectedGroupId) ); filteredParentFiles = parentFiles.filter( (file) => file.groups && file.groups.some( (gid) => (typeof gid === 'object' ? gid.id : gid) === selectedGroupId ) ); } const mergedDocuments = selectedGroupId ? [ ...filteredFiles.map((doc) => ({ ...doc, _type: 'emerald' })), ...filteredParentFiles.map((doc) => ({ ...doc, _type: 'orange' })), ] : []; // Calcul du nombre de documents par groupe const getGroupDocCount = (group) => { const groupId = group.id; let count = 0; // Documents école count += schoolFileMasters.filter((file) => Array.isArray(file.groups) ? file.groups.some( (g) => (typeof g === 'object' ? g.id : g) === groupId ) : false ).length; // Pièces à fournir count += parentFiles.filter((file) => Array.isArray(file.groups) ? file.groups.some( (g) => (typeof g === 'object' ? g.id : g) === groupId ) : false ).length; return count; }; return (
{/* Aide optionnelle */}
{renderExplanation()}
{/* 2 colonnes : groupes à gauche, documents à droite */}
{/* Colonne groupes (plein écran mobile/tablette, 1/3 desktop) */}
{profileRole !== 0 && ( )}
'blue'} minHeight="min-h-[60px]" selectable={true} forceTheme={false} groupDocCount={getGroupDocCount} actionButtons={(row) => (
)} />
{/* Colonne documents (plein écran mobile/tablette, 2/3 desktop) */}
{profileRole !== 0 && ( } items={[ { type: 'item', label: ( Formulaire existant ), onClick: () => handleDocDropdownSelect('formulaire_existant'), }, { type: 'item', label: ( Pièce à fournir ), onClick: () => handleDocDropdownSelect('parent'), }, ]} buttonClassName="flex items-center justify-center bg-primary hover:bg-primary text-white px-3 py-2 rounded-lg shadow transition text-base font-semibold" menuClassName="absolute right-0 mt-2 w-56 bg-white border border-gray-200 rounded shadow-lg z-20" dropdownOpen={isDocDropdownOpen} setDropdownOpen={setIsDocDropdownOpen} /> )}
{!selectedGroupId ? (
Sélectionner un dossier d'inscription
) : ( item._type} minHeight="min-h-[240px]" selectable={false} forceTheme={true} listClassName="" itemClassName="text-gray-800 bg-white" title="" headerContent={null} showGroups={false} actionButtons={(row) => (
)} /> )}
{/* Popup pour création/édition d'un groupe de documents */} { setIsGroupModalOpen(isOpen); if (!isOpen) { setGroupToEdit(null); } }} modalClassName="max-w-md sm:max-w-md sm:min-w-0" title={ groupToEdit ? 'Modifier le dossier' : "Création d'un nouveau dossier" } >
{ handleGroupSubmit(data); setIsGroupModalOpen(false); }} initialData={groupToEdit} />
{/* Popup pour création/édition d'un formulaire d'école déjà existant */}
{fileToEdit && fileToEdit.id ? (
{ e.preventDefault(); if ( !fileToEdit?.name || !fileToEdit?.groups || fileToEdit.groups.length === 0 || !fileToEdit?.file ) return; if (isEditing) { handleEditSchoolFileMaster({ id: fileToEdit.id, name: fileToEdit.name, group_ids: fileToEdit.groups, file: fileToEdit.file, formMasterData: fileToEdit.formMasterData, requires_electronic_signature: fileToEdit.requires_electronic_signature || false, }); } else { handleCreateSchoolFileMaster({ name: fileToEdit.name, group_ids: fileToEdit.groups, file: fileToEdit.file, requires_electronic_signature: fileToEdit.requires_electronic_signature || false, }); } setIsFileUploadPopupOpen(false); setFileToEdit(null); }} > setFileToEdit({ ...fileToEdit, name: e.target.value }) } required />
{groups && groups.length > 0 ? ( groups.map((group) => { const selectedGroupIds = (fileToEdit?.groups || []).map( (g) => typeof g === 'object' && g !== null && 'id' in g ? g.id : g ); return ( { let group_ids = selectedGroupIds; if (group_ids.includes(group.id)) { group_ids = group_ids.filter( (id) => id !== group.id ); } else { group_ids = [...group_ids, group.id]; } setFileToEdit({ ...fileToEdit, groups: group_ids }); }} fieldName="groups" itemLabelFunc={() => group.name} /> ); }) ) : (

Aucun groupe disponible

)}
{/* Label document sélectionné sans icône œil */} {fileToEdit?.file && (
{fileToEdit.file.name || fileToEdit.file.path || 'Document sélectionné'}
)} setFileToEdit({ ...fileToEdit, file })} required enable /> setFileToEdit({ ...fileToEdit, requires_electronic_signature: !fileToEdit?.requires_electronic_signature, }) } fieldName="requires_electronic_signature" itemLabelFunc={() => 'À signer électroniquement'} />
{/* Popup pour création/édition d'un document parent */} { setIsParentFileModalOpen(open); if (!open) setEditingParentFile(null); }} modalClassName="max-w-md sm:max-w-md sm:min-w-0" title={ editingParentFile && editingParentFile.id ? 'Modifier la pièce à fournir' : 'Créer une pièce à fournir' } >
{ e.preventDefault(); if ( !editingParentFile?.name || !editingParentFile?.groups || editingParentFile.groups.length === 0 ) return; const payload = { name: editingParentFile.name, description: editingParentFile.description || '', groups: editingParentFile.groups, is_required: !!editingParentFile.is_required, }; if (editingParentFile?.id) { handleEdit(editingParentFile.id, payload); } else { handleCreate(payload); } setIsParentFileModalOpen(false); setEditingParentFile(null); }} > setEditingParentFile({ ...editingParentFile, name: e.target.value, }) } required /> setEditingParentFile({ ...editingParentFile, description: e.target.value, }) } required={false} />
{groups && groups.length > 0 ? ( groups.map((group) => { const selectedGroupIds = ( editingParentFile?.groups || [] ).map((g) => typeof g === 'object' && g !== null && 'id' in g ? g.id : g ); return ( { let group_ids = selectedGroupIds; if (group_ids.includes(group.id)) { group_ids = group_ids.filter( (id) => id !== group.id ); } else { group_ids = [...group_ids, group.id]; } setEditingParentFile({ ...editingParentFile, groups: group_ids, }); }} fieldName="groups" itemLabelFunc={() => group.name} /> ); }) ) : (

Aucun groupe disponible

)}
setEditingParentFile({ ...editingParentFile, is_required: !editingParentFile?.is_required, }) } fieldName="is_required" itemLabelFunc={() => 'Requis'} />
setRemovePopupVisible(false)} /> {isLoading && }
); }