Добавлены новые переводы для полноэкранного режима таблицы посещаемости в файлы локализации (en.json и ru.json). Обновлен компонент AttendanceTable: реализована возможность отображения таблицы в полноэкранном режиме с соответствующими кнопками и модальным окном.
This commit is contained in:
parent
5997723166
commit
2a5d7efcbb
@ -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",
|
||||
|
@ -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": "Ошибка копирования",
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user