Добавлено состояние для отслеживания пульсации в компоненте LessonDetail при изменении количества студентов. Реализована функция для определения цвета на основе посещаемости. Обновлен компонент LessonList для отображения статистики посещаемости с использованием новых стилей и анимаций.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useRef, useMemo } from 'react'
|
||||
import React, { useEffect, useRef, useMemo, useState } from 'react'
|
||||
import { useParams, Link } from 'react-router-dom'
|
||||
import QRCode from 'qrcode'
|
||||
import { sha256 } from 'js-sha256'
|
||||
@@ -49,6 +49,11 @@ const LessonDetail = () => {
|
||||
// Создаем ref для отслеживания ранее присутствовавших студентов
|
||||
const prevPresentStudentsRef = useRef(new Set<string>())
|
||||
|
||||
// Добавляем состояние для отслеживания пульсации
|
||||
const [isPulsing, setIsPulsing] = useState(false)
|
||||
// Отслеживаем предыдущее количество студентов
|
||||
const prevStudentCountRef = useRef(0)
|
||||
|
||||
const {
|
||||
isFetching,
|
||||
data: accessCode,
|
||||
@@ -75,6 +80,20 @@ const LessonDetail = () => {
|
||||
if (accessCode?.body) {
|
||||
const currentPresent = new Set(accessCode.body.lesson.students.map(s => s.sub))
|
||||
|
||||
// Проверяем, изменилось ли количество студентов
|
||||
const currentCount = accessCode.body.lesson.students.length;
|
||||
if (prevStudentCountRef.current !== currentCount && prevStudentCountRef.current > 0) {
|
||||
// Запускаем эффект пульсации
|
||||
setIsPulsing(true);
|
||||
// Сбрасываем эффект через 1.5 секунды
|
||||
setTimeout(() => {
|
||||
setIsPulsing(false);
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
// Обновляем предыдущее количество
|
||||
prevStudentCountRef.current = currentCount;
|
||||
|
||||
// Очищаем флаги предыдущего состояния после задержки
|
||||
const timeoutId = setTimeout(() => {
|
||||
prevPresentStudentsRef.current = currentPresent
|
||||
@@ -169,6 +188,17 @@ const LessonDetail = () => {
|
||||
return allStudents.sort((a, b) => (a.present ? -1 : 1))
|
||||
}, [accessCode?.body, AllStudents.data, prevPresentStudentsRef.current])
|
||||
|
||||
// Функция для определения цвета на основе посещаемости
|
||||
const getAttendanceColor = (attendance: number, total: number) => {
|
||||
const percentage = total > 0 ? (attendance / total) * 100 : 0
|
||||
|
||||
if (percentage > 80) return { bg: 'green.100', color: 'green.800', dark: { bg: 'green.800', color: 'green.100' } }
|
||||
if (percentage > 60) return { bg: 'teal.100', color: 'teal.800', dark: { bg: 'teal.800', color: 'teal.100' } }
|
||||
if (percentage > 40) return { bg: 'yellow.100', color: 'yellow.800', dark: { bg: 'yellow.800', color: 'yellow.100' } }
|
||||
if (percentage > 20) return { bg: 'orange.100', color: 'orange.800', dark: { bg: 'orange.800', color: 'orange.100' } }
|
||||
return { bg: 'red.100', color: 'red.800', dark: { bg: 'red.800', color: 'red.100' } }
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<BreadcrumbsWrapper>
|
||||
@@ -211,10 +241,49 @@ const LessonDetail = () => {
|
||||
boxShadow="md"
|
||||
><Box pb={3}>
|
||||
{formatDate(accessCode?.body?.lesson?.date, t('journal.pl.lesson.dateFormat'))}{' '}
|
||||
{t('journal.pl.common.marked')} - {accessCode?.body?.lesson?.students?.length}{' '}
|
||||
{AllStudents.isSuccess
|
||||
? `/ ${AllStudents?.data?.body?.length}`
|
||||
: ''}{' '}
|
||||
{t('journal.pl.common.marked')} -
|
||||
{AllStudents.isSuccess && (
|
||||
<Box
|
||||
as="span"
|
||||
px={2}
|
||||
py={1}
|
||||
ml={2}
|
||||
borderRadius="md"
|
||||
fontWeight="bold"
|
||||
bg={getAttendanceColor(
|
||||
accessCode?.body?.lesson?.students?.length || 0,
|
||||
AllStudents?.data?.body?.length || 1
|
||||
).bg}
|
||||
color={getAttendanceColor(
|
||||
accessCode?.body?.lesson?.students?.length || 0,
|
||||
AllStudents?.data?.body?.length || 1
|
||||
).color}
|
||||
_dark={{
|
||||
bg: getAttendanceColor(
|
||||
accessCode?.body?.lesson?.students?.length || 0,
|
||||
AllStudents?.data?.body?.length || 1
|
||||
).dark.bg,
|
||||
color: getAttendanceColor(
|
||||
accessCode?.body?.lesson?.students?.length || 0,
|
||||
AllStudents?.data?.body?.length || 1
|
||||
).dark.color
|
||||
}}
|
||||
position="relative"
|
||||
animation={isPulsing ? "pulse 1.5s ease-in-out" : "none"}
|
||||
sx={{
|
||||
'@keyframes pulse': {
|
||||
'0%': { transform: 'scale(1)' },
|
||||
'50%': { transform: 'scale(1.15)', boxShadow: '0 0 10px rgba(66, 153, 225, 0.7)' },
|
||||
'100%': { transform: 'scale(1)' }
|
||||
}
|
||||
}}
|
||||
>
|
||||
{accessCode?.body?.lesson?.students?.length} / {AllStudents?.data?.body?.length}
|
||||
</Box>
|
||||
)}
|
||||
{!AllStudents.isSuccess && (
|
||||
<span> {accessCode?.body?.lesson?.students?.length}</span>
|
||||
)}{' '}
|
||||
{t('journal.pl.common.people')}
|
||||
</Box>
|
||||
<a href={userUrl}>
|
||||
|
||||
Reference in New Issue
Block a user