Add homework system (admin, student, curator)

Admin:
- HomeworkEditor in lesson page: create/update/delete assignment description

Student:
- HomeworkSection in lesson page: view assignment, submit text + files
- Resubmission allowed until curator gives feedback
- Shows feedback from curator with date and name

Curator:
- New layout with Second Brain dark sidebar (replaces green theme)
- /curator/dashboard: stats cards (pending, total, reviewed this week)
- /curator/homework: list of all submissions, pending highlighted
- /curator/homework/[id]: review submission, write feedback, redirect after send

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-07 14:13:24 +05:00
parent d0c8c6dd53
commit 543d5b2d5e
13 changed files with 836 additions and 31 deletions
@@ -0,0 +1,27 @@
"use server";
import { prisma } from "@/lib/prisma";
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { revalidatePath } from "next/cache";
async function requireAdmin() {
const session = await auth.api.getSession({ headers: await headers() });
if (!session || session.user.role !== "admin") throw new Error("Forbidden");
}
export async function saveHomework(lessonId: string, description: string) {
await requireAdmin();
await prisma.homework.upsert({
where: { lessonId },
update: { description },
create: { lessonId, description },
});
revalidatePath(`/admin/courses`);
}
export async function deleteHomework(lessonId: string) {
await requireAdmin();
await prisma.homework.delete({ where: { lessonId } });
revalidatePath(`/admin/courses`);
}
@@ -3,6 +3,7 @@ import { notFound } from "next/navigation";
import Link from "next/link";
import { LessonEditor } from "@/components/admin/lesson-editor";
import { LessonFilesManager } from "@/components/admin/lesson-files-manager";
import { HomeworkEditor } from "@/components/admin/homework-editor";
interface Props {
params: Promise<{ courseId: string; moduleId: string; lessonId: string }>;
@@ -15,6 +16,7 @@ export default async function LessonEditorPage({ params }: Props) {
where: { id: lessonId },
include: {
files: { orderBy: { createdAt: "asc" } },
homework: true,
module: {
include: { course: { select: { title: true, slug: true } } },
},
@@ -52,12 +54,20 @@ export default async function LessonEditorPage({ params }: Props) {
</div>
{/* Files section */}
<div className="card-aubade p-6">
<div className="card-aubade p-6 mb-6">
<p className="text-xs font-bold uppercase tracking-widest mb-4" style={{ color: "var(--muted-foreground)" }}>
Файлы и материалы
</p>
<LessonFilesManager lessonId={lessonId} initialFiles={lesson.files} />
</div>
{/* Homework section */}
<div className="card-aubade p-6">
<p className="text-xs font-bold uppercase tracking-widest mb-4" style={{ color: "var(--muted-foreground)" }}>
Домашнее задание
</p>
<HomeworkEditor lessonId={lessonId} initial={lesson.homework} />
</div>
</div>
);
}