Stage 1: Course/Module/Lesson CRUD admin UI with TipTap editor

This commit is contained in:
2026-04-07 11:36:27 +05:00
parent 9d82b73e58
commit d356dddc96
30 changed files with 2090 additions and 41 deletions
@@ -0,0 +1,46 @@
import { prisma } from "@/lib/prisma";
import { notFound } from "next/navigation";
import Link from "next/link";
import { Badge } from "@/components/ui/badge";
import { SortableLessons } from "@/components/admin/sortable-lessons";
interface Props {
params: Promise<{ courseId: string; moduleId: string }>;
}
export default async function ModulePage({ params }: Props) {
const { courseId, moduleId } = await params;
const module = await prisma.module.findUnique({
where: { id: moduleId },
include: {
course: { select: { title: true } },
lessons: { orderBy: { order: "asc" } },
},
});
if (!module || module.courseId !== courseId) notFound();
return (
<div className="p-8 max-w-3xl">
<nav className="text-sm text-slate-400 mb-6">
<Link href="/admin/courses" className="hover:text-slate-600">Курсы</Link>
<span className="mx-2">/</span>
<Link href={`/admin/courses/${courseId}`} className="hover:text-slate-600">{module.course.title}</Link>
<span className="mx-2">/</span>
<span className="text-slate-700">{module.title}</span>
</nav>
<div className="flex items-center justify-between mb-6">
<div>
<h1 className="text-2xl font-semibold text-slate-800">{module.title}</h1>
<p className="text-slate-500 text-sm mt-0.5">{module.lessons.length} уроков</p>
</div>
</div>
<section className="bg-white border border-slate-200 rounded-2xl p-6">
<SortableLessons courseId={courseId} moduleId={moduleId} lessons={module.lessons} />
</section>
</div>
);
}