From d1ae996386819409a8410178e55d55598769a013 Mon Sep 17 00:00:00 2001
From: primakov <primakovpro@gmail.com>
Date: Sun, 23 Mar 2025 11:54:39 +0300
Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?=
 =?UTF-8?q?=D0=BD=D1=8B=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B5=20=D0=BF=D0=B5?=
 =?UTF-8?q?=D1=80=D0=B5=D0=B2=D0=BE=D0=B4=D1=8B=20=D0=B4=D0=BB=D1=8F=20?=
 =?UTF-8?q?=D1=81=D1=82=D0=B0=D1=82=D0=B8=D1=81=D1=82=D0=B8=D0=BA=D0=B8=20?=
 =?UTF-8?q?=D0=BA=D1=83=D1=80=D1=81=D0=B0=20=D0=B8=20=D0=BF=D0=BE=D1=81?=
 =?UTF-8?q?=D0=B5=D1=89=D0=B0=D0=B5=D0=BC=D0=BE=D1=81=D1=82=D0=B8=20=D0=B2?=
 =?UTF-8?q?=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20=D0=BB=D0=BE=D0=BA=D0=B0?=
 =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20(en.json=20=D0=B8?=
 =?UTF-8?q?=20ru.json).=20=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD?=
 =?UTF-8?q?=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=20Cou?=
 =?UTF-8?q?rseCard:=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE=D0=B2?=
 =?UTF-8?q?=D0=B0=D0=BD=D0=B0=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D0=B0=20?=
 =?UTF-8?q?=D1=80=D0=B0=D1=81=D1=87=D0=B5=D1=82=D0=B0=20=D1=81=D1=82=D0=B0?=
 =?UTF-8?q?=D1=82=D0=B8=D1=81=D1=82=D0=B8=D0=BA=D0=B8=20=D0=BA=D1=83=D1=80?=
 =?UTF-8?q?=D1=81=D0=B0=20=D0=B8=20=D0=BF=D0=BE=D1=81=D0=B5=D1=89=D0=B0?=
 =?UTF-8?q?=D0=B5=D0=BC=D0=BE=D1=81=D1=82=D0=B8=20=D1=81=D1=82=D1=83=D0=B4?=
 =?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=BE=D0=B2,=20=D0=B4=D0=BE=D0=B1=D0=B0?=
 =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=B2=D0=B8=D0=B7=D1=83=D0=B0?=
 =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D1=8D=D0=BB=D0=B5=D0=BC=D0=B5?=
 =?UTF-8?q?=D0=BD=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D1=82=D0=BE?=
 =?UTF-8?q?=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D1=80?=
 =?UTF-8?q?=D0=BE=D0=B3=D1=80=D0=B5=D1=81=D1=81=D0=B0=20=D0=B8=20=D1=81?=
 =?UTF-8?q?=D1=82=D0=B0=D1=82=D0=B8=D1=81=D1=82=D0=B8=D0=BA=D0=B8.=20?=
 =?UTF-8?q?=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=D0=BE=20=D0=B2=D0=B7?=
 =?UTF-8?q?=D0=B0=D0=B8=D0=BC=D0=BE=D0=B4=D0=B5=D0=B9=D1=81=D1=82=D0=B2?=
 =?UTF-8?q?=D0=B8=D0=B5=20=D1=81=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE?=
 =?UTF-8?q?=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D0=B5=D0=BC=20=D1=87=D0=B5=D1=80?=
 =?UTF-8?q?=D0=B5=D0=B7=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD?=
 =?UTF-8?q?=D0=BD=D1=8B=D0=B9=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5?=
 =?UTF-8?q?=D0=B9=D1=81.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 locales/en.json                       |   4 +
 locales/ru.json                       |   4 +
 src/pages/course-list/course-card.tsx | 484 ++++++++++++++++++++++----
 3 files changed, 417 insertions(+), 75 deletions(-)

diff --git a/locales/en.json b/locales/en.json
index 5b758a7..e0ffdc3 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -52,6 +52,9 @@
     "journal.pl.course.attendance": "Attendance",
     "journal.pl.course.details": "Details",
     "journal.pl.course.viewDetails": "View details",
+    "journal.pl.course.progress": "Course progress",
+    "journal.pl.course.completedLessons": "Completed lessons",
+    "journal.pl.course.upcomingLessons": "Upcoming lessons",
     
     "journal.pl.lesson.created": "Lesson created",
     "journal.pl.lesson.successMessage": "Lesson {{name}} successfully created",
@@ -84,6 +87,7 @@
     "journal.pl.attendance.stats.totalLessons": "Total Lessons",
     "journal.pl.attendance.stats.averageAttendance": "Average Attendance",
     "journal.pl.attendance.stats.topStudents": "Top 3 Students by Attendance",
+    "journal.pl.attendance.stats.lowAttendance": "Students with Low Attendance",
     "journal.pl.attendance.stats.noData": "No data",
     
     "journal.pl.attendance.emojis.excellent": "Excellent attendance",
diff --git a/locales/ru.json b/locales/ru.json
index 65cd08a..99a0662 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -48,6 +48,9 @@
   "journal.pl.course.attendance": "Посещаемость",
   "journal.pl.course.details": "Детали",
   "journal.pl.course.viewDetails": "Просмотреть детали",
+  "journal.pl.course.progress": "Прогресс курса",
+  "journal.pl.course.completedLessons": "Завершено занятий",
+  "journal.pl.course.upcomingLessons": "Предстоящие занятия",
   
   "journal.pl.lesson.created": "Лекция создана",
   "journal.pl.lesson.successMessage": "Лекция {{name}} успешно создана",
@@ -80,6 +83,7 @@
   "journal.pl.attendance.stats.totalLessons": "Всего занятий",
   "journal.pl.attendance.stats.averageAttendance": "Средняя посещаемость",
   "journal.pl.attendance.stats.topStudents": "Топ-3 студента по посещаемости",
+  "journal.pl.attendance.stats.lowAttendance": "Студенты с низкой посещаемостью",
   "journal.pl.attendance.stats.noData": "Нет данных",
   
   "journal.pl.attendance.emojis.excellent": "Отличная посещаемость",
diff --git a/src/pages/course-list/course-card.tsx b/src/pages/course-list/course-card.tsx
index cd07001..f43ab40 100644
--- a/src/pages/course-list/course-card.tsx
+++ b/src/pages/course-list/course-card.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useState } from 'react'
+import React, { useCallback, useEffect, useState, useMemo } from 'react'
 import dayjs from 'dayjs'
 import { Link as ConnectedLink, generatePath } from 'react-router-dom'
 import { getNavigationValue } from '@brojs/cli'
@@ -9,24 +9,50 @@ import {
   CardFooter,
   ButtonGroup,
   Stack,
-  StackDivider,
   Button,
   Card,
   Heading,
   Tooltip,
   Spinner,
+  Flex,
+  IconButton,
+  Badge,
+  Progress,
+  SimpleGrid,
+  Stat,
+  StatLabel,
+  StatNumber,
+  HStack,
+  Text,
+  VStack,
+  Divider,
+  useColorMode,
+  Avatar,
+  AvatarGroup,
+  Tag,
+  TagLabel,
+  TagLeftIcon,
+  Wrap,
+  WrapItem,
 } from '@chakra-ui/react'
 import { useTranslation } from 'react-i18next'
 
 import { api } from '../../__data__/api/api'
-import { ArrowUpIcon, LinkIcon } from '@chakra-ui/icons'
+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()
+  const { data: lessonList, isLoading: lessonListLoading } = api.useLessonListQuery(course.id, {
+    selectFromResult: ({ data, isLoading }) => ({
+      data: data?.body,
+      isLoading,
+    }),
+  })
   const [isOpened, setIsOpened] = useState(false)
   const { t } = useTranslation()
+  const { colorMode } = useColorMode()
   
   useEffect(() => {
     if (isOpened) {
@@ -38,85 +64,393 @@ export const CourseCard = ({ course }: { course: Course }) => {
     setIsOpened((opened) => !opened)
   }, [setIsOpened])
 
+  // Рассчитываем статистику курса и посещаемости
+  const stats = useMemo(() => {
+    if (!populatedCourse.data) {
+      return {
+        totalLessons: course.lessons.length,
+        upcomingLessons: 0,
+        completedLessons: 0,
+        progress: 0,
+        topStudents: [],
+        lowAttendanceStudents: []
+      }
+    }
+    
+    const now = dayjs()
+    const total = populatedCourse.data.lessons.length
+    const completed = populatedCourse.data.lessons.filter(lesson => 
+      dayjs(lesson.date).isBefore(now)
+    ).length
+    
+    return {
+      totalLessons: total,
+      upcomingLessons: total - completed,
+      completedLessons: completed,
+      progress: total > 0 ? (completed / total) * 100 : 0,
+      topStudents: [],
+      lowAttendanceStudents: []
+    }
+  }, [populatedCourse.data, course.lessons.length])
+
+  // Рассчитываем статистику посещаемости студентов
+  const attendanceStats = useMemo(() => {
+    if (!lessonList || lessonList.length === 0) {
+      return {
+        topStudents: [],
+        lowAttendanceStudents: []
+      }
+    }
+
+    const studentsMap = new Map()
+    
+    // Собираем данные о всех студентах
+    lessonList.forEach(lesson => {
+      lesson.students?.forEach(student => {
+        const studentId = student.sub
+        const current = studentsMap.get(studentId) || {
+          id: studentId,
+          name: (student.family_name && student.given_name
+            ? `${student.family_name} ${student.given_name}`
+            : student.name || student.email || student.preferred_username || student.family_name || student.given_name),
+          attended: 0,
+          total: 0,
+          avatarUrl: student.picture,
+          email: student.email
+        }
+        
+        current.attended += 1
+        studentsMap.set(studentId, current)
+      })
+    })
+    
+    // Для каждого студента установить общее количество лекций
+    studentsMap.forEach(student => {
+      student.total = lessonList.length
+      student.percent = (student.attended / student.total) * 100
+    })
+    
+    // Преобразуем Map в массив и сортируем
+    const students = Array.from(studentsMap.values())
+    
+    // Топ-3 студента по посещаемости
+    const topStudents = [...students]
+      .sort((a, b) => b.percent - a.percent)
+      .slice(0, 3)
+    
+    // Студенты с низкой посещаемостью (менее 50%)
+    const lowAttendanceStudents = students
+      .filter(student => student.percent < 50 && student.total > 0)
+      .sort((a, b) => a.percent - b.percent)
+      .slice(0, 3)
+    
+    return {
+      topStudents,
+      lowAttendanceStudents
+    }
+  }, [lessonList])
+
+  const getProgressColor = (value: number) => {
+    if (value > 80) return 'green'
+    if (value > 50) return 'yellow'
+    return 'blue'
+  }
+
+  const getAttendanceColor = (value: number) => {
+    if (value > 80) return 'green'
+    if (value > 50) return 'yellow'
+    if (value > 30) return 'orange'
+    return 'red'
+  }
+
   return (
-    <Card key={course._id} align="left">
-      <CardHeader>
-        <Heading as="h2" mt="0">
-          {course.name}
-        </Heading>
-      </CardHeader>
-      {isOpened && (
-        <CardBody mt="16px">
-          <Stack divider={<StackDivider />} spacing="8px">
-            <Box as="span" textAlign="left">
-              {`${t('journal.pl.course.startDate')} - ${dayjs(course.startDt).format(t('journal.pl.lesson.dateFormat'))}`}
-            </Box>
-            <Box as="span" textAlign="left">
-              {t('journal.pl.course.lessonCount')} - {course.lessons.length}
-            </Box>
-
-            {populatedCourse.isFetching && <Spinner />}
-            {!populatedCourse.isFetching && populatedCourse.isSuccess && (
-              <CourseDetails populatedCourse={populatedCourse.data} />
-            )}
-
-            {getNavigationValue('link.journal.attendance') && (
-              <Tooltip
-                label={t('journal.pl.course.attendancePage')}
-                fontSize="12px"
-                top="16px"
-              >
-                <Button
-                  leftIcon={<LinkIcon />}
-                  as={ConnectedLink}
-                  variant="outline"
-                  colorScheme="blue"
-                  to={generatePath(
-                    `${getNavigationValue('journal.main')}${getNavigationValue('link.journal.attendance')}`,
-                    { courseId: course.id },
-                  )}
-                >
-                  <Box mt={3}></Box>
-                  {t('journal.pl.course.attendance')}
-                </Button>
-              </Tooltip>
-            )}
-          </Stack>
-        </CardBody>
-      )}
-      <CardFooter>
-        <ButtonGroup
-          spacing={[0, 4]}
-          mt="16px"
-          flexDirection={['column', 'row']}
-        >
-          <Tooltip label={t('journal.pl.course.attendancePage')} fontSize="12px" top="16px">
-            <Button
-              leftIcon={<LinkIcon />}
-              as={ConnectedLink}
+    <Card 
+      key={course._id} 
+      overflow="hidden"
+      variant="outline"
+      borderRadius="lg"
+      boxShadow="md"
+      bg={colorMode === 'dark' ? 'gray.700' : 'white'}
+      borderColor={colorMode === 'dark' ? 'gray.600' : 'gray.200'}
+    >
+      <CardHeader pb={2}>
+        <Flex justify="space-between" align="center">
+          <Heading as="h2" size="md">
+            {course.name}
+          </Heading>
+          <Tooltip label={isOpened ? t('journal.pl.close') : t('journal.pl.course.viewDetails')}>
+            <IconButton
+              aria-label={isOpened ? t('journal.pl.close') : t('journal.pl.course.viewDetails')}
+              icon={<ArrowUpIcon transform={isOpened ? 'rotate(0)' : 'rotate(180deg)'} />}
+              size="sm"
               colorScheme="blue"
-              to={`${getNavigationValue('journal.main')}/lessons-list/${course._id}`}
-            >
-              {t('journal.pl.common.open')}
-            </Button>
-          </Tooltip>
-          <Tooltip label={t('journal.pl.course.details')} fontSize="12px" top="16px">
-            <Button
-              colorScheme="blue"
-              mt={['16px', 0]}
-              variant="outline"
-              leftIcon={
-                <ArrowUpIcon
-                  transform={isOpened ? 'rotate(0)' : 'rotate(180deg)'}
-                />
-              }
-              loadingText={t('journal.pl.common.loading')}
+              variant="ghost"
               isLoading={populatedCourse.isFetching}
               onClick={handleToggleOpene}
+            />
+          </Tooltip>
+        </Flex>
+        <HStack spacing={2} mt={2}>
+          <Badge colorScheme="blue">
+            <HStack spacing={1}>
+              <CalendarIcon boxSize="3" />
+              <Text>{dayjs(course.startDt).format('DD.MM.YYYY')}</Text>
+            </HStack>
+          </Badge>
+          <Badge colorScheme="purple">
+            {stats.totalLessons} {t('journal.pl.common.lesson').toLowerCase()}
+          </Badge>
+        </HStack>
+      </CardHeader>
+
+      {!isOpened && (
+        <CardBody pt={2} pb={3}>
+          {lessonListLoading ? (
+            <Flex justify="center" py={3}>
+              <Spinner size="sm" />
+            </Flex>
+          ) : attendanceStats.topStudents.length > 0 ? (
+            <Box>
+              <Text fontSize="sm" fontWeight="medium" mb={2}>
+                {t('journal.pl.attendance.stats.topStudents')}:
+              </Text>
+              <AvatarGroup size="sm" max={3} mb={1}>
+                {attendanceStats.topStudents.map(student => (
+                  <Avatar 
+                    key={student.id}
+                    name={student.name} 
+                    src={student.avatarUrl}
+                  />
+                ))}
+              </AvatarGroup>
+            </Box>
+          ) : (
+            <Text fontSize="sm" color="gray.500" textAlign="center">
+              {t('journal.pl.attendance.stats.noData')}
+            </Text>
+          )}
+        </CardBody>
+      )}
+      
+      {isOpened && (
+        <CardBody pt={2}>
+          <SimpleGrid columns={{ base: 1, md: 2 }} spacing={4} mb={4}>
+            <Stat>
+              <StatLabel>{t('journal.pl.course.completedLessons')}</StatLabel>
+              <HStack align="baseline">
+                <StatNumber>{stats.completedLessons}</StatNumber>
+                <Text color="gray.500">/ {stats.totalLessons}</Text>
+              </HStack>
+              <Progress 
+                value={stats.progress} 
+                colorScheme={getProgressColor(stats.progress)}
+                size="sm" 
+                mt={2}
+                borderRadius="full"
+                hasStripe
+              />
+            </Stat>
+            
+            <Stat>
+              <StatLabel>{t('journal.pl.course.upcomingLessons')}</StatLabel>
+              <HStack align="baseline">
+                <StatNumber>{stats.upcomingLessons}</StatNumber>
+                <Text color="gray.500">
+                  <TimeIcon ml={1} mr={1} />
+                  {populatedCourse.data?.lessons
+                    .filter(lesson => dayjs(lesson.date).isAfter(dayjs()))
+                    .sort((a, b) => dayjs(a.date).valueOf() - dayjs(b.date).valueOf())[0]?.date
+                    ? dayjs(populatedCourse.data?.lessons
+                      .filter(lesson => dayjs(lesson.date).isAfter(dayjs()))
+                      .sort((a, b) => dayjs(a.date).valueOf() - dayjs(b.date).valueOf())[0]?.date)
+                      .format('DD.MM.YYYY')
+                    : t('journal.pl.common.noData')
+                  }
+                </Text>
+              </HStack>
+            </Stat>
+          </SimpleGrid>
+          
+          <Divider my={3} />
+          
+          {lessonListLoading ? (
+            <Flex justify="center" py={4}>
+              <Spinner />
+            </Flex>
+          ) : (
+            <Box>
+              <Heading size="sm" mb={3}>{t('journal.pl.attendance.stats.title')}</Heading>
+              
+              {attendanceStats.topStudents.length > 0 && (
+                <Box mb={4}>
+                  <Text fontSize="sm" fontWeight="medium" mb={2}>
+                    <StarIcon color="yellow.400" mr={1} />
+                    {t('journal.pl.attendance.stats.topStudents')}:
+                  </Text>
+                  <VStack align="stretch" spacing={2}>
+                    {attendanceStats.topStudents.map((student, index) => (
+                      <HStack key={student.id} spacing={2}>
+                        <Avatar size="sm" name={student.name} src={student.avatarUrl} />
+                        <Box flex="1">
+                          <Text fontSize="sm" fontWeight="medium">{student.name}</Text>
+                          <Progress 
+                            value={student.percent} 
+                            size="xs" 
+                            colorScheme={getAttendanceColor(student.percent)}
+                            borderRadius="full"
+                          />
+                        </Box>
+                        <Badge colorScheme={getAttendanceColor(student.percent)}>
+                          {student.attended} / {student.total}
+                        </Badge>
+                      </HStack>
+                    ))}
+                  </VStack>
+                </Box>
+              )}
+              
+              {attendanceStats.lowAttendanceStudents.length > 0 && (
+                <Box>
+                  <Text fontSize="sm" fontWeight="medium" mb={2}>
+                    <WarningIcon color="red.400" mr={1} />
+                    {t('journal.pl.attendance.stats.lowAttendance')}:
+                  </Text>
+                  <VStack align="stretch" spacing={2}>
+                    {attendanceStats.lowAttendanceStudents.map((student) => (
+                      <HStack key={student.id} spacing={2}>
+                        <Avatar size="sm" name={student.name} src={student.avatarUrl} />
+                        <Box flex="1">
+                          <Text fontSize="sm" fontWeight="medium">{student.name}</Text>
+                          <Progress 
+                            value={student.percent} 
+                            size="xs" 
+                            colorScheme={getAttendanceColor(student.percent)}
+                            borderRadius="full"
+                          />
+                        </Box>
+                        <Badge colorScheme={getAttendanceColor(student.percent)}>
+                          {student.attended} / {student.total}
+                        </Badge>
+                      </HStack>
+                    ))}
+                  </VStack>
+                </Box>
+              )}
+            </Box>
+          )}
+          
+          <Divider my={3} />
+          
+          {populatedCourse.isFetching && (
+            <Flex justify="center" py={4}>
+              <Spinner />
+            </Flex>
+          )}
+          
+          {!populatedCourse.isFetching && populatedCourse.isSuccess && populatedCourse.data && (
+            <>
+              <Heading size="sm" mb={3}>{t('journal.pl.lesson.list')}</Heading>
+              <VStack align="stretch" spacing={2} maxH="300px" overflowY="auto" pr={2}>
+                {[...populatedCourse.data.lessons]
+                  .sort((a, b) => dayjs(b.date).valueOf() - dayjs(a.date).valueOf())
+                  .map(lesson => {
+                    const isPast = dayjs(lesson.date).isBefore(dayjs())
+                    const lessonAttendance = lessonList?.find(l => l._id === lesson._id)
+                    const attendanceCount = lessonAttendance?.students?.length || 0
+                    
+                    // Безопасный расчёт общего количества студентов
+                    const totalStudentsCount = lessonList && lessonList.length > 0 
+                      ? new Set(lessonList.flatMap(l => (l.students || []).map(s => s.sub))).size
+                      : 1 // Избегаем деления на ноль
+                    
+                    const attendancePercent = totalStudentsCount > 0 
+                      ? (attendanceCount / totalStudentsCount) * 100 
+                      : 0
+                      
+                    return (
+                      <Box 
+                        key={lesson._id} 
+                        p={2} 
+                        borderRadius="md" 
+                        bg={colorMode === 'dark' ? 'gray.600' : 'gray.50'}
+                        borderLeft="4px solid"
+                        borderLeftColor={isPast ? 
+                          (colorMode === 'dark' ? 'green.500' : 'green.400') : 
+                          (colorMode === 'dark' ? 'blue.400' : 'blue.500')
+                        }
+                      >
+                        <Flex justify="space-between" align="center">
+                          <Box>
+                            <Text fontWeight="medium">{lesson.name}</Text>
+                            <HStack spacing={2} mt={1}>
+                              <Tag size="sm" colorScheme={isPast ? "green" : "blue"} borderRadius="full">
+                                <TagLeftIcon as={CalendarIcon} boxSize='10px' />
+                                <TagLabel>{dayjs(lesson.date).format('DD.MM.YYYY')}</TagLabel>
+                              </Tag>
+                              {isPast && lessonAttendance && (
+                                <Tag 
+                                  size="sm" 
+                                  colorScheme={getAttendanceColor(attendancePercent)} 
+                                  borderRadius="full"
+                                >
+                                  {attendanceCount} {t('journal.pl.common.students')}
+                                </Tag>
+                              )}
+                            </HStack>
+                          </Box>
+                          <Button
+                            as={ConnectedLink}
+                            to={`${getNavigationValue('journal.main')}/lessons-list/${course._id}/lessons/${lesson._id}`}
+                            size="xs"
+                            variant="ghost"
+                            colorScheme="blue"
+                            leftIcon={<ViewIcon />}
+                          >
+                            {t('journal.pl.common.open')}
+                          </Button>
+                        </Flex>
+                      </Box>
+                    )
+                  })}
+              </VStack>
+            </>
+          )}
+        </CardBody>
+      )}
+      
+      <CardFooter pt={2}>
+        <ButtonGroup spacing={2} width="100%">
+          <Tooltip label={t('journal.pl.lesson.list')}>
+            <Button
+              leftIcon={<ViewIcon />}
+              as={ConnectedLink}
+              colorScheme="blue"
+              size="md"
+              flexGrow={1}
+              to={`${getNavigationValue('journal.main')}/lessons-list/${course._id}`}
             >
-              {isOpened ? t('journal.pl.close') : t('journal.pl.course.viewDetails')}
+              {t('journal.pl.lesson.list')}
             </Button>
           </Tooltip>
+          
+          {getNavigationValue('link.journal.attendance') && (
+            <Tooltip label={t('journal.pl.course.attendance')}>
+              <Button
+                leftIcon={<LinkIcon />}
+                as={ConnectedLink}
+                variant="outline"
+                colorScheme="blue"
+                size="md"
+                flexGrow={1}
+                to={generatePath(
+                  `${getNavigationValue('journal.main')}${getNavigationValue('link.journal.attendance')}`,
+                  { courseId: course.id },
+                )}
+              >
+                {t('journal.pl.course.attendance')}
+              </Button>
+            </Tooltip>
+          )}
         </ButtonGroup>
       </CardFooter>
     </Card>