mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 07:53:23 +00:00
241 lines
8.3 KiB
JavaScript
241 lines
8.3 KiB
JavaScript
import { Plus, Trash2, Edit3, Check, X, BookOpen } from 'lucide-react';
|
|
import { useState } from 'react';
|
|
import Table from '@/components/Table';
|
|
import Popup from '@/components/Popup';
|
|
import InputTextWithColorIcon from '@/components/InputTextWithColorIcon';
|
|
import { DndProvider } from 'react-dnd';
|
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
|
import SpecialityItem from '@/components/Structure/Configuration/SpecialityItem';
|
|
|
|
const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, handleEdit, handleDelete }) => {
|
|
|
|
const [newSpeciality, setNewSpeciality] = useState(null);
|
|
const [editingSpeciality, setEditingSpeciality] = useState(null);
|
|
const [formData, setFormData] = useState({});
|
|
const [localErrors, setLocalErrors] = useState({});
|
|
const [popupVisible, setPopupVisible] = useState(false);
|
|
const [popupMessage, setPopupMessage] = useState("");
|
|
|
|
const [removePopupVisible, setRemovePopupVisible] = useState(false);
|
|
const [removePopupMessage, setRemovePopupMessage] = useState("");
|
|
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
|
|
|
|
// Récupération des messages d'erreur
|
|
const getError = (field) => {
|
|
return localErrors?.[field]?.[0];
|
|
};
|
|
|
|
const handleAddSpeciality = () => {
|
|
setNewSpeciality({ id: Date.now(), name: '', color_code: '' });
|
|
};
|
|
|
|
const handleRemoveSpeciality = (id) => {
|
|
return handleDelete(id)
|
|
.then(() => {
|
|
setSpecialities(prevSpecialities => prevSpecialities.filter(speciality => speciality.id !== id));
|
|
})
|
|
.catch(error => {
|
|
console.error(error);
|
|
});
|
|
};
|
|
|
|
const handleSaveNewSpeciality = () => {
|
|
if (
|
|
newSpeciality.name) {
|
|
handleCreate(newSpeciality)
|
|
.then((createdSpeciality) => {
|
|
setSpecialities([createdSpeciality, ...specialities]);
|
|
setNewSpeciality(null);
|
|
setLocalErrors({});
|
|
})
|
|
.catch((error) => {
|
|
console.error('Error:', error.message);
|
|
if (error.details) {
|
|
console.error('Form errors:', error.details);
|
|
setLocalErrors(error.details);
|
|
}
|
|
});
|
|
} else {
|
|
setPopupMessage("Tous les champs doivent être remplis et valides");
|
|
setPopupVisible(true);
|
|
}
|
|
};
|
|
|
|
const handleUpdateSpeciality = (id, updatedSpeciality) => {
|
|
if (
|
|
updatedSpeciality.name) {
|
|
handleEdit(id, updatedSpeciality)
|
|
.then((updatedSpeciality) => {
|
|
setSpecialities(specialities.map(speciality => speciality.id === id ? updatedSpeciality : speciality));
|
|
setEditingSpeciality(null);
|
|
setLocalErrors({});
|
|
})
|
|
.catch((error) => {
|
|
console.error('Error:', error.message);
|
|
if (error.details) {
|
|
console.error('Form errors:', error.details);
|
|
setLocalErrors(error.details);
|
|
}
|
|
});
|
|
} else {
|
|
setPopupMessage("Tous les champs doivent être remplis et valides");
|
|
setPopupVisible(true);
|
|
}
|
|
};
|
|
|
|
const handleChange = (e) => {
|
|
const { name, value } = e.target;
|
|
let parsedValue = value;
|
|
if (name.includes('_color')) {
|
|
parsedValue = value;
|
|
}
|
|
|
|
const fieldName = name.includes('_color') ? 'color_code' : name;
|
|
if (editingSpeciality) {
|
|
setFormData((prevData) => ({
|
|
...prevData,
|
|
[fieldName]: parsedValue,
|
|
}));
|
|
} else if (newSpeciality) {
|
|
setNewSpeciality((prevData) => ({
|
|
...prevData,
|
|
[fieldName]: parsedValue,
|
|
}));
|
|
}
|
|
};
|
|
|
|
const renderSpecialityCell = (speciality, column) => {
|
|
const isEditing = editingSpeciality === speciality.id;
|
|
const isCreating = newSpeciality && newSpeciality.id === speciality.id;
|
|
const currentData = isEditing ? formData : newSpeciality;
|
|
|
|
if (isEditing || isCreating) {
|
|
switch (column) {
|
|
case 'LIBELLE':
|
|
return (
|
|
<InputTextWithColorIcon
|
|
name="name"
|
|
textValue={currentData.name}
|
|
colorValue={currentData.color_code}
|
|
onTextChange={handleChange}
|
|
onColorChange={handleChange}
|
|
placeholder="Nom de la spécialité"
|
|
errorMsg={getError('name')}
|
|
/>
|
|
);
|
|
case 'ACTIONS':
|
|
return (
|
|
<div className="flex justify-center space-x-2">
|
|
<button
|
|
type="button"
|
|
onClick={() => (isEditing ? handleUpdateSpeciality(editingSpeciality, formData) : handleSaveNewSpeciality())}
|
|
className="text-green-500 hover:text-green-700"
|
|
>
|
|
<Check className="w-5 h-5" />
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={() => (isEditing ? setEditingSpeciality(null) : setNewSpeciality(null))}
|
|
className="text-red-500 hover:text-red-700"
|
|
>
|
|
<X className="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
);
|
|
default:
|
|
return null;
|
|
}
|
|
} else {
|
|
switch (column) {
|
|
case 'LIBELLE':
|
|
return (
|
|
<SpecialityItem key={speciality.id} speciality={speciality} />
|
|
);
|
|
case 'MISE A JOUR':
|
|
return speciality.updated_date_formatted;
|
|
case 'ACTIONS':
|
|
return (
|
|
<div className="flex justify-center space-x-2">
|
|
<button
|
|
type="button"
|
|
onClick={() => setEditingSpeciality(speciality.id) || setFormData(speciality)}
|
|
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 la spécialité " + speciality.name + ".\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?");
|
|
setRemovePopupOnConfirm(() => () => {
|
|
handleRemoveSpeciality(speciality.id)
|
|
.then(data => {
|
|
console.log('Success:', data);
|
|
setPopupMessage("La spécialité " + speciality.name + " a été correctement supprimée");
|
|
setPopupVisible(true);
|
|
setRemovePopupVisible(false);
|
|
})
|
|
.catch(error => {
|
|
console.error('Error archiving data:', error);
|
|
setPopupMessage("Erreur lors de la suppression de la spécialité " + speciality.name);
|
|
setPopupVisible(true);
|
|
setRemovePopupVisible(false);
|
|
});
|
|
});
|
|
}}
|
|
className="text-red-500 hover:text-red-700"
|
|
>
|
|
<Trash2 className="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
);
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
};
|
|
|
|
const columns = [
|
|
{ name: 'LIBELLE', label: 'Libellé' },
|
|
{ name: 'MISE A JOUR', label: 'Date mise à jour' },
|
|
{ name: 'ACTIONS', label: 'Actions' }
|
|
];
|
|
|
|
return (
|
|
<DndProvider backend={HTML5Backend}>
|
|
<div className="space-y-4">
|
|
<div className="flex justify-between items-center">
|
|
<div className="flex items-center mb-4">
|
|
<BookOpen className="w-6 h-6 text-emerald-500 mr-2" />
|
|
<h2 className="text-xl font-semibold">Spécialités</h2>
|
|
</div>
|
|
<button type="button" onClick={handleAddSpeciality} className="text-emerald-500 hover:text-emerald-700">
|
|
<Plus className="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
<Table
|
|
data={newSpeciality ? [newSpeciality, ...specialities] : specialities}
|
|
columns={columns}
|
|
renderCell={renderSpecialityCell}
|
|
/>
|
|
<Popup
|
|
visible={popupVisible}
|
|
message={popupMessage}
|
|
onConfirm={() => setPopupVisible(false)}
|
|
onCancel={() => setPopupVisible(false)}
|
|
uniqueConfirmButton={true}
|
|
/>
|
|
<Popup
|
|
visible={removePopupVisible}
|
|
message={removePopupMessage}
|
|
onConfirm={removePopupOnConfirm}
|
|
onCancel={() => setRemovePopupVisible(false)}
|
|
/>
|
|
</div>
|
|
</DndProvider>
|
|
);
|
|
};
|
|
|
|
export default SpecialitiesSection;
|