mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
chore: câblage des absences/retard dans le suivi pédagogique
This commit is contained in:
@ -1,28 +1,103 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { Trash2 } from 'lucide-react';
|
||||
import ToggleSwitch from '@/components/ToggleSwitch';
|
||||
import Button from '@/components/Button';
|
||||
import Popup from '@/components/Popup';
|
||||
import { useNotification } from '@/context/NotificationContext';
|
||||
|
||||
export default function Attendance({ absences, onToggleJustify, onDelete }) {
|
||||
const [popupVisible, setPopupVisible] = useState(false);
|
||||
const [popupMessage, setPopupMessage] = useState('');
|
||||
const [removePopupVisible, setRemovePopupVisible] = useState(false);
|
||||
const [removePopupMessage, setRemovePopupMessage] = useState('');
|
||||
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
|
||||
|
||||
const { showNotification } = useNotification();
|
||||
|
||||
export default function Attendance({ absences }) {
|
||||
return (
|
||||
<div className="w-full bg-stone-50 p-6 rounded-lg shadow-sm border border-gray-200">
|
||||
<h2 className="text-xl font-semibold mb-4">Présence et assiduité</h2>
|
||||
<ol className="relative border-l border-emerald-200">
|
||||
{absences.map((absence, idx) => (
|
||||
<li key={idx} className="mb-6 ml-4">
|
||||
<div className="absolute w-3 h-3 bg-emerald-400 rounded-full mt-1.5 -left-1.5 border border-white" />
|
||||
<time className="mb-1 text-xs font-normal leading-none text-gray-400">
|
||||
{absence.date}
|
||||
</time>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium">{absence.type}</span>
|
||||
<span
|
||||
className={`text-xs px-2 py-1 rounded ${absence.justified ? 'bg-emerald-100 text-emerald-700' : 'bg-red-100 text-red-700'}`}
|
||||
>
|
||||
{absence.justified ? 'Justifiée' : 'Non justifiée'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-sm text-gray-500">{absence.reason}</div>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
{absences.length === 0 ? (
|
||||
<div className="text-center text-emerald-600 font-medium py-8">
|
||||
Aucune absence enregistrée 🎉
|
||||
</div>
|
||||
) : (
|
||||
<ol className="relative border-l border-emerald-200">
|
||||
{absences.map((absence, idx) => (
|
||||
<li key={idx} className="mb-6 ml-4">
|
||||
<div className="absolute w-3 h-3 bg-emerald-400 rounded-full mt-1.5 -left-1.5 border border-white" />
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
{/* Infos principales à gauche */}
|
||||
<div className="flex flex-col">
|
||||
<time className="mb-1 text-xs font-normal leading-none text-gray-400">
|
||||
{absence.date}
|
||||
</time>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium">{absence.type}</span>
|
||||
<span
|
||||
className={`text-xs px-2 py-1 rounded ${absence.justified ? 'bg-emerald-100 text-emerald-700' : 'bg-red-100 text-red-700'}`}
|
||||
>
|
||||
{absence.justified ? 'Justifiée' : 'Non justifiée'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-sm text-gray-500">
|
||||
{absence.commentaire}
|
||||
</div>
|
||||
</div>
|
||||
{/* Actions à droite */}
|
||||
<div className="flex flex-col items-end gap-2 min-w-[110px]">
|
||||
<ToggleSwitch
|
||||
name={`justified-${idx}`}
|
||||
checked={absence.justified}
|
||||
onChange={() => onToggleJustify(absence)}
|
||||
label="Justifiée"
|
||||
/>
|
||||
<Button
|
||||
primary
|
||||
onClick={() => {
|
||||
setRemovePopupVisible(true);
|
||||
setRemovePopupMessage(
|
||||
"Attention ! \nVous êtes sur le point de supprimer l'absence enregistrée.\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?"
|
||||
);
|
||||
setRemovePopupOnConfirm(() => () => {
|
||||
onDelete(absence)
|
||||
.then((data) => {
|
||||
showNotification(
|
||||
'Opération effectuée avec succès.',
|
||||
'success',
|
||||
'Succès'
|
||||
);
|
||||
setPopupVisible(true);
|
||||
setRemovePopupVisible(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
showNotification(
|
||||
'Erreur lors de la suppression de l\absence',
|
||||
'error',
|
||||
'Erreur'
|
||||
);
|
||||
setPopupVisible(true);
|
||||
setRemovePopupVisible(false);
|
||||
});
|
||||
});
|
||||
}}
|
||||
className="mb-1 px-4 py-2 rounded-md shadow bg-emerald-500 text-white hover:bg-emerald-600 w-full"
|
||||
icon={<Trash2 className="w-6 h-6" />}
|
||||
text="Supprimer"
|
||||
title="Evaluez l'élève"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
)}
|
||||
<Popup
|
||||
isOpen={removePopupVisible}
|
||||
message={removePopupMessage}
|
||||
onConfirm={removePopupOnConfirm}
|
||||
onCancel={() => setRemovePopupVisible(false)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user