/** * Карточка урока для Dashboard */ 'use client'; import React, { useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { LessonPreview } from '@/api/dashboard'; import { createLiveKitRoom } from '@/api/livekit'; interface LessonCardProps { lesson: LessonPreview; showMentor?: boolean; showClient?: boolean; onClick?: () => void; } /** Подключение доступно за 10 минут до начала и до 15 минут после окончания */ function canJoinLesson(lesson: LessonPreview): boolean { if (!lesson.start_time || !lesson.end_time) return false; if (lesson.status === 'cancelled') return false; const now = new Date(); const startTime = new Date(lesson.start_time); const endTime = new Date(lesson.end_time); const allowedStart = new Date(startTime.getTime() - 10 * 60 * 1000); // за 10 минут до начала const allowedEnd = new Date(endTime.getTime() + 15 * 60 * 1000); // до 15 минут после окончания return now >= allowedStart && now <= allowedEnd; } export const LessonCard: React.FC = ({ lesson, showMentor = false, showClient = false, onClick, }) => { const router = useRouter(); const [connectLoading, setConnectLoading] = useState(false); const [canJoin, setCanJoin] = useState(false); useEffect(() => { const check = () => setCanJoin(canJoinLesson(lesson)); check(); const interval = setInterval(check, 60000); return () => clearInterval(interval); }, [lesson.start_time, lesson.end_time, lesson.status]); const handleConnect = useCallback( async (e: React.MouseEvent) => { e.stopPropagation(); if (!canJoin || connectLoading) return; setConnectLoading(true); try { const lessonId = typeof lesson.id === 'string' ? parseInt(lesson.id, 10) : lesson.id; const res = await createLiveKitRoom(lessonId); router.push( `/livekit/${res.room_name}?lesson_id=${lesson.id}&token=${encodeURIComponent(res.access_token)}` ); } catch (err) { console.error('LiveKit connect error:', err); setConnectLoading(false); } }, [canJoin, connectLoading, lesson.id, router] ); const startTime = new Date(lesson.start_time); const endTime = new Date(lesson.end_time); const getStatusColor = (status: string) => { switch (status) { case 'completed': // более серый фон для завершённых занятий return 'color-mix(in srgb, var(--md-sys-color-surface-variant) 70%, #000 10%)'; case 'in_progress': return 'var(--md-sys-color-tertiary)'; case 'cancelled': return 'var(--md-sys-color-error)'; case 'scheduled': default: return 'var(--md-sys-color-primary)'; } }; const getStatusTextColor = (status: string) => { switch (status) { case 'completed': return 'var(--md-sys-color-on-surface-variant)'; case 'in_progress': return 'var(--md-sys-color-on-tertiary)'; case 'cancelled': return 'var(--md-sys-color-on-error)'; case 'scheduled': default: return 'var(--md-sys-color-on-primary)'; } }; const getStatusText = (status: string) => { switch (status) { case 'completed': return 'Завершено'; case 'in_progress': return 'В процессе'; case 'cancelled': return 'Отменено'; default: return 'Запланировано'; } }; const statusColor = getStatusColor(lesson.status); const textColor = getStatusTextColor(lesson.status); return (
{ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onClick(); } } : undefined} style={{ background: statusColor, borderRadius: '16px', padding: '16px', marginBottom: '12px', transition: 'all 0.2s ease', cursor: 'pointer', position: 'relative', }} onMouseEnter={(e) => { e.currentTarget.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.15)'; e.currentTarget.style.transform = 'translateY(-2px)'; }} onMouseLeave={(e) => { e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.transform = 'translateY(0)'; }} >

{lesson.title}

{lesson.subject && (

{lesson.subject}

)}
{getStatusText(lesson.status)}
{startTime.toLocaleDateString('ru-RU', { day: 'numeric', month: 'short' })} {' в '} {startTime.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' })} {' - '} {endTime.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' })}
{(showMentor && lesson.mentor) && (
Ментор: {lesson.mentor.first_name} {lesson.mentor.last_name}
)} {(showClient && lesson.client) && (
Ученик: {lesson.client.first_name} {lesson.client.last_name}
)} {canJoin && (lesson.status === 'scheduled' || lesson.status === 'in_progress') && ( )}
); };