mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
364 lines
12 KiB
JavaScript
364 lines
12 KiB
JavaScript
import React, { useState } from 'react';
|
||
import { Plus, Edit3, Trash2, Check, X, FileText } from 'lucide-react';
|
||
import logger from '@/utils/logger';
|
||
import { createRegistrationParentFileTemplate } from '@/app/actions/registerFileGroupAction';
|
||
import { useCsrfToken } from '@/context/CsrfContext';
|
||
import { useNotification } from '@/context/NotificationContext';
|
||
import Popup from '@/components/Popup';
|
||
import InputText from '@/components/Form/InputText';
|
||
import MultiSelect from '@/components/Form/MultiSelect';
|
||
import ToggleSwitch from '@/components/Form/ToggleSwitch';
|
||
|
||
export default function ParentFilesSection({
|
||
parentFiles,
|
||
groups,
|
||
handleCreate,
|
||
handleEdit,
|
||
handleDelete,
|
||
hideCreateButton = false,
|
||
tableContainerClass = '',
|
||
headerClassName = '',
|
||
TableComponent,
|
||
SectionHeaderComponent,
|
||
}) {
|
||
const [editingDocumentId, setEditingDocumentId] = useState(null);
|
||
const [formData, setFormData] = useState(null);
|
||
const [selectedGroups, setSelectedGroups] = useState([]); // Gestion des groupes sélectionnés
|
||
|
||
const [guardianDetails, setGuardianDetails] = useState([]);
|
||
|
||
const [removePopupVisible, setRemovePopupVisible] = useState(false);
|
||
const [removePopupMessage, setRemovePopupMessage] = useState('');
|
||
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
|
||
|
||
const csrfToken = useCsrfToken();
|
||
const { showNotification } = useNotification();
|
||
|
||
const handleAddEmptyRequiredDocument = () => {
|
||
setEditingDocumentId('new');
|
||
setFormData({ name: '', description: '', groups: [], is_required: false }); // Add is_required
|
||
setSelectedGroups([]); // Réinitialiser les groupes sélectionnés
|
||
};
|
||
|
||
const handleEditDocument = (document) => {
|
||
setEditingDocumentId(document.id);
|
||
setFormData(document);
|
||
const initialSelectedGroups = document.groups.map((groupId) =>
|
||
groups.find((group) => group.id === groupId)
|
||
);
|
||
setSelectedGroups(initialSelectedGroups);
|
||
};
|
||
|
||
const handleSaveDocument = () => {
|
||
if (!formData.name) {
|
||
showNotification(
|
||
"Veuillez saisir un nom de document pour valider l'opération",
|
||
'error',
|
||
'Erreur'
|
||
);
|
||
return;
|
||
}
|
||
if (selectedGroups.length === 0) {
|
||
showNotification(
|
||
"Veuillez sélectionner au moins un dossier d'inscription pour valider l'opération",
|
||
'error',
|
||
'Erreur'
|
||
);
|
||
return;
|
||
}
|
||
|
||
const updatedFormData = {
|
||
...formData,
|
||
groups: selectedGroups.map((group) => group.id),
|
||
};
|
||
|
||
if (editingDocumentId === 'new') {
|
||
handleCreate(updatedFormData).then((createdDocument) => {
|
||
setEditingDocumentId(null);
|
||
setFormData(null);
|
||
setSelectedGroups([]);
|
||
|
||
guardianDetails.forEach((guardian) => {
|
||
// Création des templates
|
||
const data = {
|
||
master: createdDocument?.id,
|
||
registration_form: guardian.registration_form,
|
||
};
|
||
createRegistrationParentFileTemplate(data, csrfToken)
|
||
.then((response) => {
|
||
logger.debug('Template enregistré avec succès:', response);
|
||
})
|
||
.catch((error) => {
|
||
logger.error(
|
||
"Erreur lors de l'enregistrement du template:",
|
||
error
|
||
);
|
||
});
|
||
});
|
||
});
|
||
} else {
|
||
handleEdit(editingDocumentId, updatedFormData).then(() => {
|
||
setEditingDocumentId(null);
|
||
setFormData(null);
|
||
setSelectedGroups([]);
|
||
});
|
||
}
|
||
};
|
||
|
||
const handleRemoveDocument = (id) => {
|
||
return handleDelete(id)
|
||
.then(() => {
|
||
setEditingDocumentId(null);
|
||
setFormData(null);
|
||
setSelectedGroups([]);
|
||
})
|
||
.catch((error) => {
|
||
logger.error(error);
|
||
});
|
||
};
|
||
|
||
const handleCancelEdit = () => {
|
||
setEditingDocumentId(null);
|
||
setFormData(null);
|
||
setSelectedGroups([]);
|
||
};
|
||
|
||
const handleGroupChange = (selected) => {
|
||
setSelectedGroups(selected);
|
||
|
||
// Extraire les guardians associés aux register_forms des groupes sélectionnés
|
||
const details = selected.flatMap((group) =>
|
||
group.registration_forms.flatMap((form) =>
|
||
form.guardians.map((guardian) => ({
|
||
email: guardian.associated_profile_email,
|
||
last_name: form.last_name, // Extraire depuis form
|
||
first_name: form.first_name, // Extraire depuis form
|
||
registration_form: form.student_id, // Utiliser student_id comme ID du register_form
|
||
}))
|
||
)
|
||
);
|
||
setGuardianDetails(details); // Mettre à jour la variable d'état avec les détails des guardians
|
||
};
|
||
|
||
const renderRequiredDocumentCell = (document, column) => {
|
||
const isEditing =
|
||
editingDocumentId === document.id ||
|
||
(editingDocumentId === 'new' && !document.id);
|
||
|
||
if (isEditing) {
|
||
switch (column) {
|
||
case 'Nom de la pièce':
|
||
return (
|
||
<InputText
|
||
name="name"
|
||
value={formData.name}
|
||
onChange={(e) =>
|
||
setFormData({ ...formData, name: e.target.value })
|
||
}
|
||
placeholder="Nom de la pièce"
|
||
className="w-full"
|
||
/>
|
||
);
|
||
case 'Description':
|
||
return (
|
||
<InputText
|
||
name="description"
|
||
value={formData.description}
|
||
onChange={(e) =>
|
||
setFormData({ ...formData, description: e.target.value })
|
||
}
|
||
placeholder="Description"
|
||
className="w-full"
|
||
/>
|
||
);
|
||
case "Dossiers d'inscription":
|
||
return (
|
||
<MultiSelect
|
||
name="groups"
|
||
label="Sélection dossier d'inscription"
|
||
options={groups}
|
||
selectedOptions={selectedGroups}
|
||
onChange={handleGroupChange}
|
||
errorMsg={null}
|
||
/>
|
||
);
|
||
case 'Obligatoire':
|
||
return (
|
||
<div className="flex justify-center items-center">
|
||
<ToggleSwitch
|
||
name="is_required"
|
||
checked={formData.is_required} // Utilise la valeur booléenne de is_required
|
||
onChange={(e) => {
|
||
const { checked } = e.target; // Récupère l'état du toggle
|
||
setFormData((prevData) => ({
|
||
...prevData,
|
||
is_required: checked, // Met à jour directement le champ is_required
|
||
}));
|
||
}}
|
||
/>
|
||
</div>
|
||
);
|
||
case 'Actions':
|
||
return (
|
||
<div className="flex justify-center space-x-2">
|
||
<button
|
||
type="button"
|
||
onClick={handleSaveDocument}
|
||
className="text-green-500 hover:text-green-700"
|
||
>
|
||
<Check className="w-5 h-5" />
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={handleCancelEdit}
|
||
className="text-red-500 hover:text-red-700"
|
||
>
|
||
<X className="w-5 h-5" />
|
||
</button>
|
||
</div>
|
||
);
|
||
default:
|
||
return null;
|
||
}
|
||
} else {
|
||
switch (column) {
|
||
case 'Nom de la pièce':
|
||
return <span>{document.name}</span>;
|
||
case 'Description':
|
||
return <span>{document.description}</span>;
|
||
case "Dossiers d'inscription":
|
||
return (
|
||
<span>
|
||
{document.groups
|
||
.map(
|
||
(groupId) =>
|
||
groups.find((group) => group.id === groupId)?.name ||
|
||
"Dossiers d'inscription inconnu"
|
||
)
|
||
.join(', ')}
|
||
</span>
|
||
);
|
||
case 'Obligatoire':
|
||
return (
|
||
<span
|
||
className={`px-3 py-1 rounded-full text-sm font-semibold ${
|
||
document.is_required
|
||
? 'bg-green-100 text-green-600'
|
||
: 'bg-gray-100 text-gray-600'
|
||
}`}
|
||
>
|
||
{document.is_required ? 'Oui' : 'Non'}
|
||
</span>
|
||
);
|
||
case 'Actions':
|
||
return (
|
||
<div className="flex justify-center space-x-2">
|
||
<button
|
||
type="button"
|
||
onClick={() => handleEditDocument(document)}
|
||
className="text-blue-500 hover:text-blue-700"
|
||
>
|
||
<Edit3 className="w-5 h-5" />
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
setRemovePopupVisible(true);
|
||
setRemovePopupMessage(
|
||
`Attentions ! \nVous êtes sur le point de supprimer le document "${document.name}".\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?`
|
||
);
|
||
setRemovePopupOnConfirm(() => () => {
|
||
handleRemoveDocument(document.id)
|
||
.then(() => {
|
||
showNotification(
|
||
'Le document "${document.name}" a été correctement supprimé.',
|
||
'success',
|
||
'Succès'
|
||
);
|
||
setRemovePopupVisible(false);
|
||
})
|
||
.catch((error) => {
|
||
logger.error(
|
||
'Erreur lors de la suppression du document:',
|
||
error
|
||
);
|
||
showNotification(
|
||
`Erreur lors de la suppression du document "${document.name}".`,
|
||
'error',
|
||
'Erreur'
|
||
);
|
||
setRemovePopupVisible(false);
|
||
});
|
||
});
|
||
}}
|
||
className="text-red-500 hover:text-red-700"
|
||
>
|
||
<Trash2 className="w-5 h-5" />
|
||
</button>
|
||
</div>
|
||
);
|
||
default:
|
||
return null;
|
||
}
|
||
}
|
||
};
|
||
|
||
const columnsRequiredDocuments = [
|
||
{
|
||
name: 'Nom de la pièce',
|
||
transform: (row) => renderRequiredDocumentCell(row, 'Nom de la pièce'),
|
||
},
|
||
{
|
||
name: 'Description',
|
||
transform: (row) => renderRequiredDocumentCell(row, 'Description'),
|
||
},
|
||
{
|
||
name: "Dossiers d'inscription",
|
||
transform: (row) =>
|
||
renderRequiredDocumentCell(row, "Dossiers d'inscription"),
|
||
},
|
||
{
|
||
name: 'Obligatoire',
|
||
transform: (row) => renderRequiredDocumentCell(row, 'Obligatoire'),
|
||
},
|
||
{
|
||
name: 'Actions',
|
||
transform: (row) => renderRequiredDocumentCell(row, 'Actions'),
|
||
},
|
||
];
|
||
|
||
// Ajout : écouteur d'event global pour déclencher la création depuis la popup centrale
|
||
React.useEffect(() => {
|
||
if (!hideCreateButton) return;
|
||
const handler = () => handleAddEmptyRequiredDocument();
|
||
window.addEventListener('parentFilesSection:create', handler);
|
||
return () => window.removeEventListener('parentFilesSection:create', handler);
|
||
}, [hideCreateButton]);
|
||
|
||
const Table = TableComponent || ((props) => <div />); // fallback
|
||
const SectionHeader = SectionHeaderComponent || ((props) => <div />);
|
||
|
||
return (
|
||
<div className={`w-full h-full flex flex-col ${tableContainerClass}`}>
|
||
<SectionHeader
|
||
title="Pièces à fournir"
|
||
description="Configurez la liste des documents que les parents doivent fournir."
|
||
className={headerClassName}
|
||
/>
|
||
<Table
|
||
data={
|
||
editingDocumentId === 'new' ? [formData, ...parentFiles] : parentFiles
|
||
}
|
||
columns={columnsRequiredDocuments}
|
||
emptyMessage="Aucune pièce à fournir enregistrée"
|
||
/>
|
||
<Popup
|
||
isOpen={removePopupVisible}
|
||
message={removePopupMessage}
|
||
onConfirm={removePopupOnConfirm}
|
||
onCancel={() => setRemovePopupVisible(false)}
|
||
/>
|
||
</div>
|
||
);
|
||
}
|