mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-04-05 20:51:26 +00:00
feat: Ajout d'un système de notation par classe et par matière et par élève [N3WTS-6]
This commit is contained in:
153
Front-End/src/components/Evaluation/EvaluationList.js
Normal file
153
Front-End/src/components/Evaluation/EvaluationList.js
Normal file
@ -0,0 +1,153 @@
|
||||
'use client';
|
||||
import React, { useState } from 'react';
|
||||
import { Trash2, Edit2, ClipboardList, ChevronDown, ChevronUp } from 'lucide-react';
|
||||
import Button from '@/components/Form/Button';
|
||||
import Popup from '@/components/Popup';
|
||||
import { useNotification } from '@/context/NotificationContext';
|
||||
|
||||
export default function EvaluationList({
|
||||
evaluations,
|
||||
onDelete,
|
||||
onEdit,
|
||||
onGradeStudents,
|
||||
}) {
|
||||
const [expandedId, setExpandedId] = useState(null);
|
||||
const [deletePopupVisible, setDeletePopupVisible] = useState(false);
|
||||
const [evaluationToDelete, setEvaluationToDelete] = useState(null);
|
||||
const { showNotification } = useNotification();
|
||||
|
||||
const handleDeleteClick = (evaluation) => {
|
||||
setEvaluationToDelete(evaluation);
|
||||
setDeletePopupVisible(true);
|
||||
};
|
||||
|
||||
const handleConfirmDelete = () => {
|
||||
if (evaluationToDelete && onDelete) {
|
||||
onDelete(evaluationToDelete.id)
|
||||
.then(() => {
|
||||
showNotification('Évaluation supprimée avec succès', 'success', 'Succès');
|
||||
setDeletePopupVisible(false);
|
||||
setEvaluationToDelete(null);
|
||||
})
|
||||
.catch((error) => {
|
||||
showNotification('Erreur lors de la suppression', 'error', 'Erreur');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Grouper les évaluations par matière
|
||||
const groupedBySpeciality = evaluations.reduce((acc, ev) => {
|
||||
const key = ev.speciality_name || 'Sans matière';
|
||||
if (!acc[key]) {
|
||||
acc[key] = {
|
||||
name: key,
|
||||
color: ev.speciality_color || '#6B7280',
|
||||
evaluations: [],
|
||||
};
|
||||
}
|
||||
acc[key].evaluations.push(ev);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
if (evaluations.length === 0) {
|
||||
return (
|
||||
<div className="text-center text-gray-500 py-8">
|
||||
Aucune évaluation créée pour cette période
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{Object.values(groupedBySpeciality).map((group) => (
|
||||
<div
|
||||
key={group.name}
|
||||
className="border border-gray-200 rounded-lg overflow-hidden"
|
||||
>
|
||||
<div
|
||||
className="flex items-center justify-between p-3 bg-gray-50 cursor-pointer"
|
||||
onClick={() =>
|
||||
setExpandedId(expandedId === group.name ? null : group.name)
|
||||
}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<span
|
||||
className="w-3 h-3 rounded-full"
|
||||
style={{ backgroundColor: group.color }}
|
||||
/>
|
||||
<span className="font-medium text-gray-800">{group.name}</span>
|
||||
<span className="text-sm text-gray-500">
|
||||
({group.evaluations.length} évaluation
|
||||
{group.evaluations.length > 1 ? 's' : ''})
|
||||
</span>
|
||||
</div>
|
||||
{expandedId === group.name ? (
|
||||
<ChevronUp size={20} className="text-gray-500" />
|
||||
) : (
|
||||
<ChevronDown size={20} className="text-gray-500" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{expandedId === group.name && (
|
||||
<div className="divide-y divide-gray-100">
|
||||
{group.evaluations.map((evaluation) => (
|
||||
<div
|
||||
key={evaluation.id}
|
||||
className="p-3 flex items-center justify-between hover:bg-gray-50"
|
||||
>
|
||||
<div className="flex-1">
|
||||
<div className="font-medium text-gray-700">
|
||||
{evaluation.name}
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 flex gap-3">
|
||||
{evaluation.date && (
|
||||
<span>
|
||||
{new Date(evaluation.date).toLocaleDateString('fr-FR')}
|
||||
</span>
|
||||
)}
|
||||
<span>Note max: {evaluation.max_score}</span>
|
||||
<span>Coef: {evaluation.coefficient}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
primary
|
||||
onClick={() => onGradeStudents(evaluation)}
|
||||
icon={<ClipboardList size={16} />}
|
||||
text="Noter"
|
||||
title="Noter les élèves"
|
||||
/>
|
||||
<button
|
||||
onClick={() => onEdit && onEdit(evaluation)}
|
||||
className="p-2 text-gray-500 hover:text-blue-600 hover:bg-blue-50 rounded"
|
||||
title="Modifier"
|
||||
>
|
||||
<Edit2 size={16} />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleDeleteClick(evaluation)}
|
||||
className="p-2 text-gray-500 hover:text-red-600 hover:bg-red-50 rounded"
|
||||
title="Supprimer"
|
||||
>
|
||||
<Trash2 size={16} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
||||
<Popup
|
||||
isOpen={deletePopupVisible}
|
||||
message={`Êtes-vous sûr de vouloir supprimer l'évaluation "${evaluationToDelete?.name}" ?`}
|
||||
onConfirm={handleConfirmDelete}
|
||||
onCancel={() => {
|
||||
setDeletePopupVisible(false);
|
||||
setEvaluationToDelete(null);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user