diff --git a/client/src/pages/FormateurEmargement.tsx b/client/src/pages/FormateurEmargement.tsx index 8a23082..0b76b34 100644 --- a/client/src/pages/FormateurEmargement.tsx +++ b/client/src/pages/FormateurEmargement.tsx @@ -26,6 +26,8 @@ export default function FormateurEmargement() { const { user } = useAuth(); const [selectedSequenceId, setSelectedSequenceId] = useState(null); const [showQRDialog, setShowQRDialog] = useState(false); + const [lastRefreshTime, setLastRefreshTime] = useState(new Date()); + const [secondsSinceRefresh, setSecondsSinceRefresh] = useState(0); // Récupérer toutes les séquences (filtrées côté serveur pour les formateurs) const { data: sequences, isLoading: loadingSequences } = trpc.sequences.list.useQuery(); @@ -61,11 +63,42 @@ export default function FormateurEmargement() { const interval = setInterval(() => { refetchInscrits(); refetchPresences(); + setLastRefreshTime(new Date()); + setSecondsSinceRefresh(0); }, 30000); // 30 secondes return () => clearInterval(interval); }, [selectedSequenceId, refetchInscrits, refetchPresences]); + // Compteur pour "Mis à jour il y a X secondes" + useEffect(() => { + if (!selectedSequenceId) return; + + const interval = setInterval(() => { + setSecondsSinceRefresh(Math.floor((new Date().getTime() - lastRefreshTime.getTime()) / 1000)); + }, 1000); // Mise à jour chaque seconde + + return () => clearInterval(interval); + }, [selectedSequenceId, lastRefreshTime]); + + // Calculer les statistiques de présence par date et période + const getPresenceStats = (dateFormationId: number, periode: "matin" | "apres_midi") => { + if (!inscrits || !presences) return { present: 0, total: 0, percentage: 0 }; + + const total = inscrits.length; + const present = inscrits.filter(inscrit => + presences.some(p => + p.inscriptionId === inscrit.inscriptionId && + p.dateFormationId === dateFormationId && + p.periode === periode + ) + ).length; + + const percentage = total > 0 ? Math.round((present / total) * 100) : 0; + + return { present, total, percentage }; + }; + // Valider une présence manuellement const { mutate: validerPresence, isPending: validating } = trpc.presences.valider.useMutation({ onSuccess: () => { @@ -175,30 +208,45 @@ export default function FormateurEmargement() { {selectedSequenceId && ( -
- - +
+
+ + +
+ + {/* Indicateur de rafraîchissement */} +
+ + + Mis à jour il y a {secondsSinceRefresh} seconde{secondsSinceRefresh > 1 ? 's' : ''} + + + Rafraîchissement auto: 30s + +
)} @@ -268,6 +316,17 @@ export default function FormateurEmargement() {

+ {/* Statistiques Matin */} +
+ 🌅 Matin + + {(() => { + const stats = getPresenceStats(date.id, "matin"); + return `${stats.present}/${stats.total} présents (${stats.percentage}%)`; + })()} + +
+ {/* Matin */}
@@ -328,6 +387,17 @@ export default function FormateurEmargement() { )}
+ {/* Statistiques Après-midi */} +
+ 🌆 Après-midi + + {(() => { + const stats = getPresenceStats(date.id, "apres_midi"); + return `${stats.present}/${stats.total} présents (${stats.percentage}%)`; + })()} + +
+ {/* Après-midi */}
diff --git a/todo.md b/todo.md index 5554a08..8b4f017 100644 --- a/todo.md +++ b/todo.md @@ -1493,3 +1493,6 @@ - [x] Créer l'interface de gestion des attestations pour formateurs et super-formateurs (charger, supprimer, modifier, envoyer) - [x] Ajouter un rafraîchissement automatique toutes les 30 secondes sur la page d'émargement numérique + +- [x] Ajouter un indicateur visuel de rafraîchissement avec badge "Mis à jour il y a X secondes" +- [x] Ajouter des statistiques en temps réel du taux de présence par période