/** * Секция «Последние сданные ДЗ» для дашборда ментора (iOS 26). */ 'use client'; import React, { useMemo, useState } from 'react'; import { MentorDashboardResponse } from '@/api/dashboard'; import { Panel, SectionHeader, FlipCard } from '../ui'; import { LoadingSpinner } from '@/components/common/LoadingSpinner'; import { getHomeworkSubmission, type HomeworkSubmission } from '@/api/homework'; export interface RecentSubmissionsSectionProps { data: MentorDashboardResponse | null; loading: boolean; } const formatDateTime = (dateTimeStr: string | null): string => { if (!dateTimeStr) return '—'; try { const date = new Date(dateTimeStr); if (isNaN(date.getTime())) return '—'; const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); const diffDays = Math.floor(diffHours / 24); if (diffHours < 1) { const diffMins = Math.floor(diffMs / (1000 * 60)); return diffMins <= 1 ? 'только что' : `${diffMins} мин назад`; } else if (diffHours < 24) { return `${diffHours} ч назад`; } else if (diffDays === 1) { return 'Вчера'; } else if (diffDays < 7) { return `${diffDays} дн назад`; } else { return date.toLocaleDateString('ru-RU', { day: 'numeric', month: 'short', }); } } catch { return '—'; } }; const getStatusColor = (status: string): string => { switch (status) { case 'graded': return 'var(--md-sys-color-tertiary)'; case 'returned': return 'var(--md-sys-color-error)'; case 'submitted': return 'var(--md-sys-color-on-surface-variant)'; default: return 'var(--md-sys-color-on-surface-variant)'; } }; const getStatusLabel = (status: string): string => { switch (status) { case 'graded': return 'Проверено'; case 'returned': return 'На доработке'; case 'submitted': return 'Сдано'; default: return status; } }; export const RecentSubmissionsSection: React.FC = ({ data, loading, }) => { const submissions = data?.recent_submissions?.slice(0, 4) || []; const [flipped, setFlipped] = useState(false); const [selectedSubmissionId, setSelectedSubmissionId] = useState(null); const [details, setDetails] = useState(null); const [loadingDetails, setLoadingDetails] = useState(false); const selectedPreview = useMemo( () => submissions.find((s) => s.id === selectedSubmissionId) || null, [submissions, selectedSubmissionId], ); const formatFullDateTime = (dateTimeStr: string | null): string => { if (!dateTimeStr) return '—'; try { const date = new Date(dateTimeStr); if (isNaN(date.getTime())) return '—'; return date.toLocaleString('ru-RU', { day: 'numeric', month: 'long', year: 'numeric', hour: '2-digit', minute: '2-digit', }); } catch { return '—'; } }; const openSubmissionDetails = async (submissionId: string) => { setSelectedSubmissionId(submissionId); setFlipped(true); setLoadingDetails(true); setDetails(null); try { const full = await getHomeworkSubmission(submissionId); setDetails(full); } catch (error) { console.error('Ошибка загрузки решения ДЗ:', error); } finally { setLoadingDetails(false); } }; return ( {loading && !data ? ( ) : submissions.length === 0 ? (
Нет сданных ДЗ
) : (
e.stopPropagation()} > {submissions.map((submission) => { const studentName = submission.student?.first_name && submission.student?.last_name ? `${submission.student.first_name} ${submission.student.last_name}`.trim() : submission.student?.name || 'Студент'; return ( ); })}
)} } back={ { e.stopPropagation(); setFlipped(false); }} className="ios26-back-button" > Назад } />
e.stopPropagation()}> {loadingDetails ? (
Загрузка...
) : details ? (

{details.homework?.title || selectedPreview?.homework?.title || 'ДЗ'}

{details.homework?.description && (

{details.homework.description}

)}

Студент: {details.student?.first_name} {details.student?.last_name}

Сдано: {formatFullDateTime(details.submitted_at)}

{details.score != null && (

Оценка: {details.score}/5

)} {details.feedback && (

Отзыв: {details.feedback}

)}
) : (
Не удалось загрузить детали
)}
} /> ); };