Files
journal.pl/src/pages/course-list/course-list.tsx

144 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState, useMemo, useEffect } from 'react'
import {
Box,
Button,
Container,
Text,
useColorMode,
useBreakpointValue
} from '@chakra-ui/react'
import { AddIcon } from '@chakra-ui/icons'
import { useTranslation } from 'react-i18next'
import { getFeatures } from '@brojs/cli'
import { useAppSelector } from '../../__data__/store'
import { api } from '../../__data__/api/api'
import { isTeacher } from '../../utils/user'
import { PageLoader } from '../../components/page-loader/page-loader'
import { useSetBreadcrumbs } from '../../components'
import { useGroupedCourses } from './hooks'
import { CreateCourseForm, YearGroup, CoursesOverview } from './components'
import { Lesson } from '../../__data__/model'
/**
* Основной компонент списка курсов
*/
export const CoursesList = () => {
const user = useAppSelector((s) => s.user)
const { data, isLoading } = api.useCoursesListQuery()
const [showForm, setShowForm] = useState(false)
const { t } = useTranslation()
const { colorMode } = useColorMode()
// Устанавливаем хлебные крошки для главной страницы
useSetBreadcrumbs([
{
title: t('journal.pl.breadcrumbs.home'),
path: '/',
isCurrentPage: true
}
])
// Получаем значения фичей
const features = getFeatures('journal')
const coursesStatistics = features?.['courses.statistics']
// Создаем API запросы для получения уроков
const [getLessons] = api.useLazyLessonListQuery()
const buttonSize = useBreakpointValue({ base: 'md', md: 'lg' })
const containerPadding = useBreakpointValue({ base: '2', md: '4' })
// Используем хук для группировки курсов по годам
const groupedCourses = useGroupedCourses(data?.body)
// Создаем объект с детализированными данными для всех курсов
const [lessonsByCourse, setLessonsByCourse] = useState<Record<string, Lesson[]>>({})
// Используем useMemo для проверки наличия данных
const courses = useMemo(() => data?.body || [], [data])
// Загружаем данные для каждого курса параллельно
useEffect(() => {
if (courses.length > 0 && !showForm) {
// Создаем запросы для получения данных о занятиях каждого курса
const fetchLessonsForCourses = async () => {
const lessonsData: Record<string, Lesson[]> = {}
// Получаем данные курсов параллельно (по 3 курса за раз, чтобы не перегружать сервер)
for (let i = 0; i < courses.length; i += 3) {
const batch = courses.slice(i, i + 3)
const batchPromises = batch.map(async course => {
// Используем существующий API метод с Lazy Query
const response = await getLessons(course.id)
if (response.data?.body) {
lessonsData[course._id] = response.data.body
}
})
await Promise.all(batchPromises)
}
setLessonsByCourse(lessonsData)
}
fetchLessonsForCourses()
}
}, [courses, showForm, getLessons])
if (isLoading) {
return <PageLoader />
}
const handleCloseForm = () => setShowForm(false)
return (
<Container maxW="container.xl" px={containerPadding}>
{isTeacher(user) && (
<Box mt={{ base: 3, md: 5 }} mb={{ base: 3, md: 5 }}>
{showForm ? (
<CreateCourseForm onClose={handleCloseForm} />
) : (
<Box p={{ base: 1, md: 2 }} m={{ base: 1, md: 2 }}>
<Button
leftIcon={<AddIcon />}
colorScheme="green"
onClick={() => setShowForm(true)}
size={buttonSize}
width={{ base: '100%', sm: 'auto' }}
>
{t('journal.pl.common.add')}
</Button>
</Box>
)}
</Box>
)}
{!showForm && coursesStatistics && (
<CoursesOverview
courses={courses}
isLoading={isLoading}
lessonsByCourse={lessonsByCourse}
/>
)}
{Object.keys(groupedCourses).length > 0 ? (
Object.entries(groupedCourses)
.sort(([yearA], [yearB]) => Number(yearB) - Number(yearA)) // Сортируем годы по убыванию
.map(([year, courses]) => (
<YearGroup
key={year}
year={year}
courses={courses}
colorMode={colorMode}
/>
))
) : (
<Box textAlign="center" py={10}>
<Text color="gray.500">{t('journal.pl.course.noCourses')}</Text>
</Box>
)}
</Container>
)
}