diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 26ae41e..6287836 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -130,6 +130,7 @@ model Lesson {
title String
content Json?
kinescopeId String?
+ coverImage String?
order Int @default(0)
published Boolean @default(false)
createdAt DateTime @default(now())
diff --git a/src/app/(student)/courses/[slug]/lessons/[lessonId]/page.tsx b/src/app/(student)/courses/[slug]/lessons/[lessonId]/page.tsx
index f836f7a..9bb4a0c 100644
--- a/src/app/(student)/courses/[slug]/lessons/[lessonId]/page.tsx
+++ b/src/app/(student)/courses/[slug]/lessons/[lessonId]/page.tsx
@@ -113,7 +113,7 @@ export default async function LessonPage({ params }: Props) {
{/* Video */}
{lesson.kinescopeId && (
-
+
)}
@@ -180,17 +180,30 @@ export default async function LessonPage({ params }: Props) {
)}
{/* Quiz */}
- {lesson.quiz && !isAdmin && (
+ {lesson.quiz && (
- Тест
+ Тест{isAdmin && (предпросмотр)}
-
} : null}
- slug={slug}
- lessonId={lessonId}
- />
+ {isAdmin ? (
+
+ {lesson.quiz.questions.map((q, idx) => (
+
+
{idx + 1}. {q.text}
+
+ Поле для ответа студента
+
+
+ ))}
+
+ ) : (
+ } : null}
+ slug={slug}
+ lessonId={lessonId}
+ />
+ )}
)}
diff --git a/src/app/api/admin/lessons/[lessonId]/route.ts b/src/app/api/admin/lessons/[lessonId]/route.ts
new file mode 100644
index 0000000..8723e9b
--- /dev/null
+++ b/src/app/api/admin/lessons/[lessonId]/route.ts
@@ -0,0 +1,34 @@
+import { NextRequest, NextResponse } from "next/server";
+import { headers } from "next/headers";
+import { auth } from "@/lib/auth";
+import { prisma } from "@/lib/prisma";
+
+export async function PATCH(
+ req: NextRequest,
+ { params }: { params: Promise<{ lessonId: string }> }
+) {
+ const session = await auth.api.getSession({ headers: await headers() });
+ if (!session || session.user.role !== "admin") {
+ return NextResponse.json({ error: "Forbidden" }, { status: 403 });
+ }
+
+ const { lessonId } = await params;
+ const body = await req.json() as {
+ title: string;
+ kinescopeId: string;
+ content: object;
+ published: boolean;
+ };
+
+ await prisma.lesson.update({
+ where: { id: lessonId },
+ data: {
+ title: body.title,
+ kinescopeId: body.kinescopeId || null,
+ content: body.content,
+ published: body.published,
+ },
+ });
+
+ return NextResponse.json({ ok: true });
+}
diff --git a/src/components/admin/lesson-editor.tsx b/src/components/admin/lesson-editor.tsx
index b1c501f..e328a20 100644
--- a/src/components/admin/lesson-editor.tsx
+++ b/src/components/admin/lesson-editor.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useState, useCallback, useTransition } from "react";
+import { useState, useCallback } from "react";
import { useEditor, EditorContent } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import Image from "@tiptap/extension-image";
@@ -9,7 +9,6 @@ import Underline from "@tiptap/extension-underline";
import Placeholder from "@tiptap/extension-placeholder";
import { Save, Eye, FileUp, ChevronLeft, ChevronRight } from "lucide-react";
import { useRouter } from "next/navigation";
-import { saveLesson } from "@/lib/actions/lesson-actions";
interface LessonData {
id: string;
@@ -47,7 +46,8 @@ export function LessonEditor({
const [importing, setImporting] = useState(false);
const [importError, setImportError] = useState(null);
const [saved, setSaved] = useState(false);
- const [pending, startTransition] = useTransition();
+ const [saveError, setSaveError] = useState(null);
+ const [pending, setPending] = useState(false);
const inputStyle = {
border: "2px solid var(--border)",
@@ -73,7 +73,7 @@ export function LessonEditor({
class: "prose prose-slate max-w-none min-h-[300px] focus:outline-none p-4",
},
},
- });
+ }, [lesson.id]);
const uploadImage = useCallback(async () => {
const input = document.createElement("input");
@@ -133,18 +133,27 @@ export function LessonEditor({
}
}, [editor]);
- function handleSave() {
+ async function handleSave() {
if (!editor) return;
- startTransition(async () => {
- await saveLesson(lesson.id, courseId, moduleId, {
- title,
- kinescopeId,
- content: editor.getJSON(),
- published,
+ setPending(true);
+ setSaveError(null);
+ try {
+ const res = await fetch(`/api/admin/lessons/${lesson.id}`, {
+ method: "PATCH",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ title, kinescopeId, content: editor.getJSON(), published }),
});
+ if (!res.ok) {
+ const data = await res.json().catch(() => ({}));
+ throw new Error((data as { error?: string }).error ?? `HTTP ${res.status}`);
+ }
setSaved(true);
setTimeout(() => setSaved(false), 2000);
- });
+ } catch (err) {
+ setSaveError(err instanceof Error ? err.message : "Ошибка сохранения");
+ } finally {
+ setPending(false);
+ }
}
function navigateTo(lessonId: string) {
@@ -266,6 +275,12 @@ export function LessonEditor({
)}
+ {saveError && (
+
+ Ошибка сохранения: {saveError}
+
+ )}
+
{/* Title */}