diff --git a/src/pages/course-list/course-card.tsx b/src/pages/course-list/course-card.tsx
index f43ab40..1d7da75 100644
--- a/src/pages/course-list/course-card.tsx
+++ b/src/pages/course-list/course-card.tsx
@@ -34,13 +34,16 @@ import {
TagLeftIcon,
Wrap,
WrapItem,
+ useBreakpointValue,
+ useMediaQuery,
+ Icon
} from '@chakra-ui/react'
import { useTranslation } from 'react-i18next'
+import { FaExpand, FaCompress } from 'react-icons/fa'
import { api } from '../../__data__/api/api'
import { ArrowUpIcon, LinkIcon, CalendarIcon, ViewIcon, WarningIcon, StarIcon, TimeIcon } from '@chakra-ui/icons'
import { Course } from '../../__data__/model'
-import { CourseDetails } from './course-details'
export const CourseCard = ({ course }: { course: Course }) => {
const [getLessonList, populatedCourse] = api.useLazyGetCourseByIdQuery()
@@ -51,9 +54,25 @@ export const CourseCard = ({ course }: { course: Course }) => {
}),
})
const [isOpened, setIsOpened] = useState(false)
+ const [isLessonsExpanded, setIsLessonsExpanded] = useState(false)
const { t } = useTranslation()
const { colorMode } = useColorMode()
+ // Адаптивные размеры и компоновка для различных размеров экрана
+ const headingSize = useBreakpointValue({ base: 'sm', md: 'md' })
+ const buttonSize = useBreakpointValue({ base: 'xs', md: 'md' })
+ const tagSize = useBreakpointValue({ base: 'sm', md: 'md' })
+ const avatarSize = useBreakpointValue({ base: 'xs', md: 'sm' })
+ const cardPadding = useBreakpointValue({ base: 2, md: 4 })
+
+ // Используем медиа-запросы для определения направления бейджей
+ const [isLargerThanSm] = useMediaQuery("(min-width: 480px)")
+ const [badgeDirection, setBadgeDirection] = useState<'column' | 'row'>('row')
+
+ useEffect(() => {
+ setBadgeDirection(isLargerThanSm ? 'row' : 'column')
+ }, [isLargerThanSm])
+
useEffect(() => {
if (isOpened) {
getLessonList(course.id, true)
@@ -64,6 +83,10 @@ export const CourseCard = ({ course }: { course: Course }) => {
setIsOpened((opened) => !opened)
}, [setIsOpened])
+ const handleToggleExpand = useCallback(() => {
+ setIsLessonsExpanded((expanded) => !expanded)
+ }, [setIsLessonsExpanded])
+
// Рассчитываем статистику курса и посещаемости
const stats = useMemo(() => {
if (!populatedCourse.data) {
@@ -173,9 +196,9 @@ export const CourseCard = ({ course }: { course: Course }) => {
bg={colorMode === 'dark' ? 'gray.700' : 'white'}
borderColor={colorMode === 'dark' ? 'gray.600' : 'gray.200'}
>
-
-
-
+
+
+
{course.name}
@@ -190,21 +213,37 @@ export const CourseCard = ({ course }: { course: Course }) => {
/>
-
-
-
-
- {dayjs(course.startDt).format('DD.MM.YYYY')}
+
+ {badgeDirection === 'column' ? (
+
+
+
+
+ {dayjs(course.startDt).format('DD.MM.YYYY')}
+
+
+
+ {stats.totalLessons} {t('journal.pl.common.lesson').toLowerCase()}
+
+
+ ) : (
+
+
+
+
+ {dayjs(course.startDt).format('DD.MM.YYYY')}
+
+
+
+ {stats.totalLessons} {t('journal.pl.common.lesson').toLowerCase()}
+
-
-
- {stats.totalLessons} {t('journal.pl.common.lesson').toLowerCase()}
-
-
+ )}
+
{!isOpened && (
-
+
{lessonListLoading ? (
@@ -214,7 +253,7 @@ export const CourseCard = ({ course }: { course: Course }) => {
{t('journal.pl.attendance.stats.topStudents')}:
-
+
{attendanceStats.topStudents.map(student => (
{
)}
{isOpened && (
-
-
+
+
{t('journal.pl.course.completedLessons')}
@@ -253,9 +292,9 @@ export const CourseCard = ({ course }: { course: Course }) => {
{t('journal.pl.course.upcomingLessons')}
-
+
{stats.upcomingLessons}
-
+
{populatedCourse.data?.lessons
.filter(lesson => dayjs(lesson.date).isAfter(dayjs()))
@@ -290,9 +329,9 @@ export const CourseCard = ({ course }: { course: Course }) => {
{attendanceStats.topStudents.map((student, index) => (
-
+
- {student.name}
+ {student.name}
)}
-
-
+
+
}
as={ConnectedLink}
colorScheme="blue"
- size="md"
+ size={buttonSize}
flexGrow={1}
to={`${getNavigationValue('journal.main')}/lessons-list/${course._id}`}
+ mb={{ base: 2, sm: 0 }}
>
{t('journal.pl.lesson.list')}
@@ -440,7 +501,7 @@ export const CourseCard = ({ course }: { course: Course }) => {
as={ConnectedLink}
variant="outline"
colorScheme="blue"
- size="md"
+ size={buttonSize}
flexGrow={1}
to={generatePath(
`${getNavigationValue('journal.main')}${getNavigationValue('link.journal.attendance')}`,
diff --git a/src/pages/course-list/course-details.tsx b/src/pages/course-list/course-details.tsx
deleted file mode 100644
index 229d860..0000000
--- a/src/pages/course-list/course-details.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-import React from 'react'
-import dayjs from 'dayjs'
-import { Link as ConnectedLink } from 'react-router-dom'
-import { getNavigationValue, getHistory } from '@brojs/cli'
-import { Stack, Heading, Link, Button, Tooltip, Box } from '@chakra-ui/react'
-import { useTranslation } from 'react-i18next'
-import { LinkIcon } from '@chakra-ui/icons'
-
-import { useAppSelector } from '../../__data__/store'
-import { isTeacher } from '../../utils/user'
-import { PopulatedCourse } from '../../__data__/model'
-import { api } from '../../__data__/api/api'
-
-type CourseDetailsProps = {
- populatedCourse: PopulatedCourse
-}
-
-const history = getHistory()
-
-export const CourseDetails = ({ populatedCourse }: CourseDetailsProps) => {
- const user = useAppSelector((s) => s.user)
- const exam = populatedCourse.examWithJury
- const [toggleExamWithJury, examWithJuryRequest] =
- api.useToggleExamWithJuryMutation()
- const { t } = useTranslation()
-
- return (
- <>
- {isTeacher(user) && (
-
- {t('journal.pl.exam.title')}: {exam?.name}{' '}
- {exam && getNavigationValue('exam.main') && getNavigationValue('link.exam.details') && (
-
- }
- as={'a'}
- colorScheme="blue"
- href={
- getNavigationValue('exam.main') +
- getNavigationValue('link.exam.details')
- .replace(':courseId', populatedCourse.id)
- .replace(':examId', exam.id)
- }
- onClick={(event) => {
- event.preventDefault()
- history.push(
- getNavigationValue('exam.main') +
- getNavigationValue('link.exam.details')
- .replace(':courseId', populatedCourse.id)
- .replace(':examId', exam.id),
- )
- }}
- >
- {t('journal.pl.exam.open')}
-
-
- )}
-
- )}
- {!Boolean(exam) && (
- <>
-
- {t('journal.pl.exam.notSpecified')}
-
-
-
-
-
-
- >
- )}
- {Boolean(exam) && (
- <>
-
- {t('journal.pl.exam.juryCount')}:
-
-
- {populatedCourse.examWithJury.jury.length}
-
- >
- )}
-
- {t('journal.pl.lesson.list')}:
-
-
- {populatedCourse?.lessons?.map((lesson) => (
-
- {lesson.name}
-
- ))}
-
- >
- )
-}
diff --git a/src/pages/course-list/course-list.tsx b/src/pages/course-list/course-list.tsx
index f2c6155..b32afd0 100644
--- a/src/pages/course-list/course-list.tsx
+++ b/src/pages/course-list/course-list.tsx
@@ -17,6 +17,9 @@ import {
FormErrorMessage,
useToast,
useColorMode,
+ useBreakpointValue,
+ Flex,
+ Stack
} from '@chakra-ui/react'
import { useForm, Controller } from 'react-hook-form'
import { AddIcon } from '@chakra-ui/icons'
@@ -44,6 +47,12 @@ export const CoursesList = () => {
const { t } = useTranslation()
const { colorMode } = useColorMode();
+
+ // Определяем размеры для адаптивного дизайна
+ const buttonSize = useBreakpointValue({ base: 'md', md: 'lg' })
+ const headingSize = useBreakpointValue({ base: 'md', md: 'lg' })
+ const formSpacing = useBreakpointValue({ base: 5, md: 10 })
+ const containerPadding = useBreakpointValue({ base: '2', md: '4' })
const {
control,
@@ -80,6 +89,7 @@ export const CoursesList = () => {
})
}
reset()
+ setShowForm(false) // Закрываем форму после успешного создания
}
}, [crucQuery.isSuccess, t])
@@ -90,20 +100,20 @@ export const CoursesList = () => {
}
return (
-
+
{isTeacher(user) && (
-
+
{showForm ? (
-
-
+
+
{t('journal.pl.course.createTitle')}
- setShowForm(false)} />
+ setShowForm(false)} />
{crucQuery?.error && (
- {(crucQuery?.error as any).error}
+
+ {(crucQuery?.error as any).error}
+
)}
) : (
-
+
}
colorScheme="green"
onClick={() => setShowForm(true)}
- >
+ size={buttonSize}
+ width={{ base: '100%', sm: 'auto' }}
+ >
{t('journal.pl.common.add')}
)}
)}
-
+
{data?.body?.map((c) => (
{
-
+
{t('journal.pl.common.journal')}