Добавлены новые переводы для полноэкранного режима таблицы посещаемости в файлы локализации (en.json и ru.json). Обновлен компонент AttendanceTable: реализована возможность отображения таблицы в полноэкранном режиме с соответствующими кнопками и модальным окном.

This commit is contained in:
Primakov Alexandr Alexandrovich 2025-03-23 12:09:56 +03:00
parent 5997723166
commit 2a5d7efcbb
3 changed files with 126 additions and 77 deletions

View File

@ -100,6 +100,9 @@
"journal.pl.attendance.table.copy": "Copy Table",
"journal.pl.attendance.table.show": "Show Table",
"journal.pl.attendance.table.hide": "Hide Table",
"journal.pl.attendance.table.fullscreen": "Fullscreen",
"journal.pl.attendance.table.exitFullscreen": "Exit Fullscreen",
"journal.pl.attendance.table.attendanceData": "Attendance Data",
"journal.pl.attendance.table.copySuccess": "Table copied",
"journal.pl.attendance.table.copySuccessDescription": "Table data successfully copied to clipboard",
"journal.pl.attendance.table.copyError": "Copy error",

View File

@ -95,6 +95,9 @@
"journal.pl.attendance.table.copy": "Копировать таблицу",
"journal.pl.attendance.table.show": "Показать таблицу",
"journal.pl.attendance.table.hide": "Скрыть таблицу",
"journal.pl.attendance.table.fullscreen": "На весь экран",
"journal.pl.attendance.table.exitFullscreen": "Выйти из полноэкранного режима",
"journal.pl.attendance.table.attendanceData": "Данные о посещаемости",
"journal.pl.attendance.table.copySuccess": "Таблица скопирована",
"journal.pl.attendance.table.copySuccessDescription": "Данные таблицы успешно скопированы в буфер обмена",
"journal.pl.attendance.table.copyError": "Ошибка копирования",

View File

@ -17,10 +17,17 @@ import {
Icon,
Tooltip,
Avatar,
AvatarBadge
AvatarBadge,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody,
ModalCloseButton,
useDisclosure
} from '@chakra-ui/react'
import { CopyIcon, ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons'
import { FaSmile, FaMeh, FaFrown, FaSadTear } from 'react-icons/fa'
import { FaSmile, FaMeh, FaFrown, FaSadTear, FaExpand, FaCompress } from 'react-icons/fa'
import dayjs from 'dayjs'
import { useTranslation } from 'react-i18next'
import { getGravatarURL } from '../../../utils/gravatar'
@ -36,6 +43,7 @@ export const AttendanceTable: React.FC<AttendanceTableProps> = ({ data }) => {
const toast = useToast()
const { t } = useTranslation()
const [showTable, setShowTable] = useState(false)
const { isOpen, onOpen, onClose } = useDisclosure()
const getPresentColor = () => {
return colorMode === 'dark' ? 'green.600' : 'green.100'
@ -178,84 +186,8 @@ export const AttendanceTable: React.FC<AttendanceTableProps> = ({ data }) => {
return <Box>{t('journal.pl.common.noData')}</Box>
}
return (
<Box
boxShadow="md"
borderRadius="lg"
bg={colorMode === 'dark' ? 'gray.700' : 'white'}
>
<Flex justifyContent="space-between" p={3} alignItems="center">
<Button
leftIcon={<CopyIcon />}
size="sm"
colorScheme="blue"
onClick={copyTableData}
mr={2}
>
{t('journal.pl.attendance.table.copy')}
</Button>
<Button
rightIcon={showTable ? <ChevronUpIcon /> : <ChevronDownIcon />}
size="sm"
variant="outline"
onClick={() => setShowTable(!showTable)}
>
{showTable ? t('journal.pl.attendance.table.hide') : t('journal.pl.attendance.table.show')}
</Button>
</Flex>
{/* Краткая статистика по каждому студенту с эмоджи */}
<Box p={4} borderTop="1px" borderColor={colorMode === 'dark' ? 'gray.600' : 'gray.200'}>
<Flex flexWrap="wrap" gap={3}>
{getStudentAttendance().map(({ student, name, attendedCount, totalLessons, attendance, picture }) => {
const emoji = getAttendanceEmoji(attendedCount, totalLessons)
return (
<Tooltip
key={student.sub}
label={`${emoji.label}: ${attendedCount} ${t('journal.pl.common.of')} ${totalLessons} ${t('journal.pl.common.students')} (${attendance.toFixed(0)}%)`}
hasArrow
>
<Box
p={3}
borderRadius="md"
bg={colorMode === 'dark' ? 'gray.800' : 'gray.50'}
boxShadow="sm"
minWidth="180px"
>
<HStack spacing={3}>
<Avatar
size="md"
src={picture}
name={name}
>
<AvatarBadge boxSize='2em' bg={emoji.color}>
<Icon as={emoji.icon} color="white" boxSize={7} />
</AvatarBadge>
</Avatar>
<Box>
<Text fontSize="sm" fontWeight="medium" isTruncated maxW="110px">{name}</Text>
<Text fontSize="xs" mt={1} color={colorMode === 'dark' ? 'gray.400' : 'gray.600'}>
{attendedCount} {t('journal.pl.common.of')} {totalLessons} ({attendance.toFixed(0)}%)
</Text>
</Box>
</HStack>
</Box>
</Tooltip>
)
})}
</Flex>
</Box>
{/* Полная таблица с возможностью скрытия/показа */}
<Collapse in={showTable} animateOpacity>
<Box
overflowX="auto"
p={3}
borderTop="1px"
borderColor={colorMode === 'dark' ? 'gray.600' : 'gray.200'}
>
// Создаем компонент таблицы для переиспользования
const AttendanceTableContent = () => (
<Table variant="simple" size="sm">
<Thead>
<Tr>
@ -322,8 +254,119 @@ export const AttendanceTable: React.FC<AttendanceTableProps> = ({ data }) => {
))}
</Tbody>
</Table>
)
return (
<Box
boxShadow="md"
borderRadius="lg"
bg={colorMode === 'dark' ? 'gray.700' : 'white'}
>
<Flex justifyContent="space-between" p={3} alignItems="center">
<Flex>
<Button
leftIcon={<CopyIcon />}
size="sm"
colorScheme="blue"
onClick={copyTableData}
mr={2}
>
{t('journal.pl.attendance.table.copy')}
</Button>
<Button
leftIcon={<Icon as={FaExpand} />}
size="sm"
colorScheme="teal"
onClick={onOpen}
mr={2}
>
{t('journal.pl.attendance.table.fullscreen')}
</Button>
</Flex>
<Button
rightIcon={showTable ? <ChevronUpIcon /> : <ChevronDownIcon />}
size="sm"
variant="outline"
onClick={() => setShowTable(!showTable)}
>
{showTable ? t('journal.pl.attendance.table.hide') : t('journal.pl.attendance.table.show')}
</Button>
</Flex>
{/* Краткая статистика по каждому студенту с эмоджи */}
<Box p={4} borderTop="1px" borderColor={colorMode === 'dark' ? 'gray.600' : 'gray.200'}>
<Flex flexWrap="wrap" gap={3}>
{getStudentAttendance().map(({ student, name, attendedCount, totalLessons, attendance, picture }) => {
const emoji = getAttendanceEmoji(attendedCount, totalLessons)
return (
<Tooltip
key={student.sub}
label={`${emoji.label}: ${attendedCount} ${t('journal.pl.common.of')} ${totalLessons} ${t('journal.pl.common.students')} (${attendance.toFixed(0)}%)`}
hasArrow
>
<Box
p={3}
borderRadius="md"
bg={colorMode === 'dark' ? 'gray.800' : 'gray.50'}
boxShadow="sm"
minWidth="180px"
>
<HStack spacing={3}>
<Avatar
size="md"
src={picture}
name={name}
>
<AvatarBadge boxSize='2em' bg={emoji.color}>
<Icon as={emoji.icon} color="white" boxSize={7} />
</AvatarBadge>
</Avatar>
<Box>
<Text fontSize="sm" fontWeight="medium" isTruncated maxW="110px">{name}</Text>
<Text fontSize="xs" mt={1} color={colorMode === 'dark' ? 'gray.400' : 'gray.600'}>
{attendedCount} {t('journal.pl.common.of')} {totalLessons} ({attendance.toFixed(0)}%)
</Text>
</Box>
</HStack>
</Box>
</Tooltip>
)
})}
</Flex>
</Box>
{/* Полная таблица с возможностью скрытия/показа */}
<Collapse in={showTable} animateOpacity>
<Box
overflowX="auto"
p={3}
borderTop="1px"
borderColor={colorMode === 'dark' ? 'gray.600' : 'gray.200'}
>
<AttendanceTableContent />
</Box>
</Collapse>
{/* Модальное окно для отображения таблицы на весь экран */}
<Modal isOpen={isOpen} onClose={onClose} size="full">
<ModalOverlay />
<ModalContent>
<ModalHeader>
<Flex justifyContent="space-between" alignItems="center">
{t('journal.pl.attendance.table.attendanceData')}
</Flex>
</ModalHeader>
<ModalCloseButton size="lg" top="16px" />
<ModalBody pb={6}>
<Box overflowX="auto">
<AttendanceTableContent />
</Box>
</ModalBody>
</ModalContent>
</Modal>
</Box>
)
}