'use client'; import { useState, useEffect, useCallback } from 'react'; import Box from '@mui/material/Box'; import Card from '@mui/material/Card'; import Stack from '@mui/material/Stack'; import Divider from '@mui/material/Divider'; import Avatar from '@mui/material/Avatar'; import Button from '@mui/material/Button'; import Typography from '@mui/material/Typography'; import CircularProgress from '@mui/material/CircularProgress'; import LinearProgress from '@mui/material/LinearProgress'; import { useTheme } from '@mui/material/styles'; import { paths } from 'src/routes/paths'; import { useRouter } from 'src/routes/hooks'; import { fDateTime } from 'src/utils/format-time'; import { getClientDashboard, getChildDashboard } from 'src/utils/dashboard-api'; import { createLiveKitRoom } from 'src/utils/livekit-api'; import { DashboardContent } from 'src/layouts/dashboard'; import { useAuthContext } from 'src/auth/hooks'; import { CONFIG } from 'src/config-global'; import { varAlpha } from 'src/theme/styles'; import { Iconify } from 'src/components/iconify'; import { CourseWidgetSummary } from '../../course/course-widget-summary'; import { CourseProgress } from '../../course/course-progress'; import { CourseMyAccount } from '../../course/course-my-account'; // ---------------------------------------------------------------------- const formatDateTime = (str) => { if (!str) return '—'; try { const date = new Date(str); if (isNaN(date.getTime())) return '—'; const today = new Date(); const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1); const time = date.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' }); if (date.toDateString() === today.toDateString()) return `Сегодня, ${time}`; if (date.toDateString() === tomorrow.toDateString()) return `Завтра, ${time}`; return date.toLocaleDateString('ru-RU', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }); } catch { return '—'; } }; // ---------------------------------------------------------------------- function LessonItem({ lesson }) { const router = useRouter(); const [joining, setJoining] = useState(false); const mentorName = lesson.mentor ? `${lesson.mentor.first_name || ''} ${lesson.mentor.last_name || ''}`.trim() || 'Ментор' : 'Ментор'; const now = new Date(); const startTime = new Date(lesson.start_time); const diffMin = (startTime - now) / 60000; const canJoin = diffMin < 11 && diffMin > -90; const handleJoin = async () => { try { setJoining(true); const res = await createLiveKitRoom(lesson.id); const token = res?.access_token || res?.token; router.push(`${paths.dashboard.prejoin}?token=${encodeURIComponent(token)}&lesson_id=${lesson.id}`); } catch (err) { console.error('Join error:', err); setJoining(false); } }; return ( {mentorName[0]?.toUpperCase()} {lesson.title || lesson.subject || 'Занятие'} {mentorName} {canJoin ? ( ) : ( {formatDateTime(lesson.start_time)} )} ); } // ---------------------------------------------------------------------- function HomeworkItem({ homework }) { const statusColor = { pending: 'warning', submitted: 'info', reviewed: 'success', completed: 'success', }[homework.status] || 'default'; return ( {homework.title} {homework.subject || 'Предмет не указан'} {homework.grade != null && ( {homework.grade}/5 )} ); } // ---------------------------------------------------------------------- export function OverviewClientView({ childId, childName }) { const theme = useTheme(); const { user } = useAuthContext(); const [stats, setStats] = useState(null); const [loading, setLoading] = useState(true); const fetchData = useCallback( async (signal) => { try { setLoading(true); const data = childId ? await getChildDashboard(childId, { signal }) : await getClientDashboard({ signal }); if (!signal?.aborted) setStats(data); } catch (err) { if (err?.name === 'AbortError' || err?.name === 'CanceledError') return; console.error('Client dashboard error:', err); } finally { if (!signal?.aborted) setLoading(false); } }, [childId] ); useEffect(() => { const controller = new AbortController(); fetchData(controller.signal); return () => controller.abort(); }, [fetchData]); // Периодическое обновление каждые 60 сек — кнопка «Подключиться» появляется автоматически useEffect(() => { const id = setInterval(() => { const controller = new AbortController(); fetchData(controller.signal); return () => controller.abort(); }, 60_000); return () => clearInterval(id); }, [fetchData]); const displayName = childName || user?.first_name || 'Студент'; const completionPct = stats?.total_lessons > 0 ? Math.round((stats.completed_lessons / stats.total_lessons) * 100) : 0; if (loading && !stats) { return ( ); } return ( {/* LEFT */} {/* Stat widgets */} {/* Progress bar */} Прогресс занятий {completionPct}% Пройдено: {stats?.completed_lessons || 0} Всего: {stats?.total_lessons || 0} {/* Upcoming lessons + homework */} {/* Upcoming lessons */} Ближайшие занятия {loading ? ( ) : stats?.upcoming_lessons?.length > 0 ? ( {stats.upcoming_lessons.slice(0, 4).map((lesson) => ( ))} ) : ( Нет запланированных занятий )} {/* Homework */} Домашние задания {loading ? ( ) : stats?.recent_homework?.length > 0 ? ( {stats.recent_homework.slice(0, 4).map((hw) => ( ))} ) : ( Нет домашних заданий )} {/* RIGHT sidebar */} {/* Next lesson highlight */} {stats?.next_lesson && ( Следующее занятие {stats.next_lesson.title || 'Занятие'} {formatDateTime(stats.next_lesson.start_time)} {stats.next_lesson.mentor && ( {(stats.next_lesson.mentor.first_name || 'М')[0]} {`${stats.next_lesson.mentor.first_name || ''} ${stats.next_lesson.mentor.last_name || ''}`.trim()} )} )} ); }