Enhance localization support by integrating i18next for translations across various components and pages. Update UI elements to utilize translated strings for improved user experience in both English and Russian. Additionally, refactor the Toaster component to support a context-based approach for toast notifications.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Box, Heading, Grid, Text, VStack, HStack, Badge, Progress } from '@chakra-ui/react'
|
||||
import { useGetSystemStatsQuery } from '../../__data__/api/api'
|
||||
import { StatCard } from '../../components/StatCard'
|
||||
@@ -6,16 +7,17 @@ import { LoadingSpinner } from '../../components/LoadingSpinner'
|
||||
import { ErrorAlert } from '../../components/ErrorAlert'
|
||||
|
||||
export const DashboardPage: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const { data: stats, isLoading, error, refetch } = useGetSystemStatsQuery(undefined, {
|
||||
pollingInterval: 10000, // Обновление каждые 10 секунд
|
||||
})
|
||||
|
||||
if (isLoading) {
|
||||
return <LoadingSpinner message="Загрузка статистики..." />
|
||||
return <LoadingSpinner message={t('challenge.admin.dashboard.loading')} />
|
||||
}
|
||||
|
||||
if (error || !stats) {
|
||||
return <ErrorAlert message="Не удалось загрузить статистику системы" onRetry={refetch} />
|
||||
return <ErrorAlert message={t('challenge.admin.dashboard.load.error')} onRetry={refetch} />
|
||||
}
|
||||
|
||||
const acceptanceRate = stats.submissions.total > 0
|
||||
@@ -32,25 +34,25 @@ export const DashboardPage: React.FC = () => {
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Heading mb={6}>Dashboard</Heading>
|
||||
<Heading mb={6}>{t('challenge.admin.dashboard.title')}</Heading>
|
||||
|
||||
{/* Main Stats */}
|
||||
<Grid templateColumns="repeat(auto-fit, minmax(250px, 1fr))" gap={6} mb={8}>
|
||||
<StatCard label="Всего пользователей" value={stats.users} colorScheme="blue" />
|
||||
<StatCard label="Всего заданий" value={stats.tasks} colorScheme="teal" />
|
||||
<StatCard label="Всего цепочек" value={stats.chains} colorScheme="purple" />
|
||||
<StatCard label="Всего проверок" value={stats.submissions.total} colorScheme="orange" />
|
||||
<StatCard label={t('challenge.admin.dashboard.stats.users')} value={stats.users} colorScheme="blue" />
|
||||
<StatCard label={t('challenge.admin.dashboard.stats.tasks')} value={stats.tasks} colorScheme="teal" />
|
||||
<StatCard label={t('challenge.admin.dashboard.stats.chains')} value={stats.chains} colorScheme="purple" />
|
||||
<StatCard label={t('challenge.admin.dashboard.stats.submissions')} value={stats.submissions.total} colorScheme="orange" />
|
||||
</Grid>
|
||||
|
||||
{/* Submissions Stats */}
|
||||
<Box bg="white" p={6} borderRadius="lg" boxShadow="sm" borderWidth="1px" borderColor="gray.200" mb={8}>
|
||||
<Heading size="md" mb={4}>
|
||||
Статистика проверок
|
||||
{t('challenge.admin.dashboard.submissions.title')}
|
||||
</Heading>
|
||||
<Grid templateColumns="repeat(auto-fit, minmax(200px, 1fr))" gap={6}>
|
||||
<VStack align="start" gap={2}>
|
||||
<Text fontSize="sm" color="gray.600">
|
||||
Принято
|
||||
{t('challenge.admin.dashboard.submissions.accepted')}
|
||||
</Text>
|
||||
<HStack>
|
||||
<Text fontSize="2xl" fontWeight="bold" color="green.600">
|
||||
@@ -62,7 +64,7 @@ export const DashboardPage: React.FC = () => {
|
||||
|
||||
<VStack align="start" gap={2}>
|
||||
<Text fontSize="sm" color="gray.600">
|
||||
Отклонено
|
||||
{t('challenge.admin.dashboard.submissions.rejected')}
|
||||
</Text>
|
||||
<HStack>
|
||||
<Text fontSize="2xl" fontWeight="bold" color="red.600">
|
||||
@@ -74,7 +76,7 @@ export const DashboardPage: React.FC = () => {
|
||||
|
||||
<VStack align="start" gap={2}>
|
||||
<Text fontSize="sm" color="gray.600">
|
||||
Ожидают
|
||||
{t('challenge.admin.dashboard.submissions.pending')}
|
||||
</Text>
|
||||
<Text fontSize="2xl" fontWeight="bold" color="yellow.600">
|
||||
{stats.submissions.pending}
|
||||
@@ -83,7 +85,7 @@ export const DashboardPage: React.FC = () => {
|
||||
|
||||
<VStack align="start" gap={2}>
|
||||
<Text fontSize="sm" color="gray.600">
|
||||
В процессе
|
||||
{t('challenge.admin.dashboard.submissions.in.progress')}
|
||||
</Text>
|
||||
<Text fontSize="2xl" fontWeight="bold" color="blue.600">
|
||||
{stats.submissions.inProgress}
|
||||
@@ -95,13 +97,13 @@ export const DashboardPage: React.FC = () => {
|
||||
{/* Queue Stats */}
|
||||
<Box bg="white" p={6} borderRadius="lg" boxShadow="sm" borderWidth="1px" borderColor="gray.200" mb={8}>
|
||||
<Heading size="md" mb={4}>
|
||||
Статус очереди
|
||||
{t('challenge.admin.dashboard.queue.title')}
|
||||
</Heading>
|
||||
|
||||
<Grid templateColumns="repeat(auto-fit, minmax(250px, 1fr))" gap={6} mb={4}>
|
||||
<VStack align="start" gap={2}>
|
||||
<Text fontSize="sm" color="gray.600">
|
||||
В обработке
|
||||
{t('challenge.admin.dashboard.queue.processing')}
|
||||
</Text>
|
||||
<HStack align="baseline">
|
||||
<Text fontSize="2xl" fontWeight="bold" color="teal.600">
|
||||
@@ -115,7 +117,7 @@ export const DashboardPage: React.FC = () => {
|
||||
|
||||
<VStack align="start" gap={2}>
|
||||
<Text fontSize="sm" color="gray.600">
|
||||
Ожидают в очереди
|
||||
{t('challenge.admin.dashboard.queue.waiting')}
|
||||
</Text>
|
||||
<Text fontSize="2xl" fontWeight="bold" color="orange.600">
|
||||
{stats.queue.waiting}
|
||||
@@ -124,7 +126,7 @@ export const DashboardPage: React.FC = () => {
|
||||
|
||||
<VStack align="start" gap={2}>
|
||||
<Text fontSize="sm" color="gray.600">
|
||||
Всего в очереди
|
||||
{t('challenge.admin.dashboard.queue.total')}
|
||||
</Text>
|
||||
<Text fontSize="2xl" fontWeight="bold" color="blue.600">
|
||||
{stats.queue.queueLength}
|
||||
@@ -134,7 +136,7 @@ export const DashboardPage: React.FC = () => {
|
||||
|
||||
<Box>
|
||||
<Text fontSize="sm" color="gray.600" mb={2}>
|
||||
Загруженность очереди: {queueUtilization}%
|
||||
{t('challenge.admin.dashboard.queue.utilization')} {queueUtilization}%
|
||||
</Text>
|
||||
<Progress.Root value={Number(queueUtilization)} colorPalette="teal" size="sm" borderRadius="full">
|
||||
<Progress.Track>
|
||||
@@ -147,13 +149,13 @@ export const DashboardPage: React.FC = () => {
|
||||
{/* Average Check Time */}
|
||||
<Box bg="white" p={6} borderRadius="lg" boxShadow="sm" borderWidth="1px" borderColor="gray.200">
|
||||
<Heading size="md" mb={2}>
|
||||
Среднее время проверки
|
||||
{t('challenge.admin.dashboard.check.time.title')}
|
||||
</Heading>
|
||||
<Text fontSize="3xl" fontWeight="bold" color="purple.600">
|
||||
{(stats.averageCheckTimeMs / 1000).toFixed(2)} сек
|
||||
{t('challenge.admin.dashboard.check.time.value', { time: (stats.averageCheckTimeMs / 1000).toFixed(2) })}
|
||||
</Text>
|
||||
<Text fontSize="sm" color="gray.600" mt={2}>
|
||||
Время от отправки решения до получения результата
|
||||
{t('challenge.admin.dashboard.check.time.description')}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user