"use client"; import { useState, useTransition } from "react"; import { submitHomework } from "@/lib/actions/student-actions"; import { AudioRecorder } from "@/components/curator/audio-recorder"; import { linkify } from "@/lib/linkify"; interface HWFile { name: string; url: string; size: number } interface Feedback { id: string; text: string; files?: HWFile[]; audioUrl?: string | null; createdAt: Date; curator: { name: string }; } interface Submission { id: string; text: string | null; files: HWFile[]; audioUrl?: string | null; submittedAt: Date; status: string; feedbacks: Feedback[]; } interface Props { homework: { id: string; description: string }; submission: Submission | null; slug: string; lessonId: string; allowAudio?: boolean; } function formatSize(bytes: number) { if (bytes < 1024) return `${bytes} Б`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)} КБ`; return `${(bytes / 1024 / 1024).toFixed(1)} МБ`; } export function HomeworkSection({ homework, submission, slug, lessonId, allowAudio = false }: Props) { const [text, setText] = useState(submission?.text ?? ""); const [files, setFiles] = useState(submission?.files ?? []); const [audioUrl, setAudioUrl] = useState(submission?.audioUrl ?? null); const [uploading, setUploading] = useState(false); const [pending, startTransition] = useTransition(); const [editing, setEditing] = useState(!submission); const isReviewed = submission && submission.feedbacks.length > 0; const isApproved = submission?.status === "APPROVED"; // Финализировано: есть фидбек ИЛИ ДЗ принято кнопкой без ответа. Нельзя пересдавать. const isLocked = Boolean(isReviewed || isApproved); const inputStyle = { border: "2px solid var(--border)", background: "var(--background)", outline: "none", width: "100%", padding: "0.5rem 0.75rem", fontSize: "16px", fontFamily: "inherit", resize: "vertical" as const, minHeight: "140px", }; async function handleFileUpload(e: React.ChangeEvent) { const file = e.target.files?.[0]; if (!file) return; setUploading(true); const fd = new FormData(); fd.append("file", file); const res = await fetch("/api/student/homework-upload", { method: "POST", body: fd }); const data = await res.json(); if (data.url) setFiles((prev) => [...prev, data]); setUploading(false); e.target.value = ""; } function removeFile(url: string) { setFiles((prev) => prev.filter((f) => f.url !== url)); } function handleSubmit() { startTransition(() => submitHomework(homework.id, slug, lessonId, text, files, audioUrl)); setEditing(false); } return (
{/* Assignment description */}
{homework.description}
{/* Submitted & reviewed */} {isReviewed && (

Ваш ответ

{submission!.text ? linkify(submission!.text) : "—"}
{submission!.audioUrl && (

Аудио-ответ:

)}
{submission!.feedbacks.map((fb) => { const fbFiles = fb.files ?? []; return (

Обратная связь

{fb.curator.name} · {new Date(fb.createdAt).toLocaleDateString("ru-RU")}

{linkify(fb.text)}

{fbFiles.length > 0 && (
{fbFiles.map((f) => ( 📎{f.name} {formatSize(f.size)} ))}
)} {fb.audioUrl && (

Аудио от куратора:

)}
); })}
)} {/* Принято без письменного ответа */} {isApproved && !isReviewed && submission && (
ДЗ принято ✓ Сдано {new Date(submission.submittedAt).toLocaleDateString("ru-RU")}
{submission.text && (
{linkify(submission.text)}
)} {submission.audioUrl && (

Аудио-ответ:

)} {submission.files.length > 0 && (
{submission.files.map((f) => ( 📎 {f.name} {formatSize(f.size)} ))}
)}
)} {/* Submitted, pending review */} {submission && !isLocked && !editing && (
На проверке Сдано {new Date(submission.submittedAt).toLocaleDateString("ru-RU")}
{submission.text && (
{linkify(submission.text)}
)} {submission.audioUrl && (

Аудио-ответ:

)} {submission.files.length > 0 && (
{submission.files.map((f) => ( 📎 {f.name} {formatSize(f.size)} ))}
)}
)} {/* Form */} {editing && !isLocked && (