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
+72
View File
@@ -0,0 +1,72 @@
import { prisma } from "@/lib/prisma";
import { notFound } from "next/navigation";
import Link from "next/link";
import { CourseEditForm } from "@/components/admin/course-edit-form";
import { SortableModules } from "@/components/admin/sortable-modules";
import { EnrollmentManager } from "@/components/admin/enrollment-manager";
interface Props {
params: Promise<{ courseId: string }>;
}
export default async function CourseDetailPage({ params }: Props) {
const { courseId } = await params;
const [course, allStudents] = await Promise.all([
prisma.course.findUnique({
where: { id: courseId },
include: {
modules: {
orderBy: { order: "asc" },
include: { _count: { select: { lessons: true } } },
},
enrollments: { include: { user: { select: { id: true, name: true, email: true } } } },
},
}),
prisma.user.findMany({
where: { role: "student" },
select: { id: true, name: true, email: true },
orderBy: { name: "asc" },
}),
]);
if (!course) notFound();
const enrolledIds = new Set(course.enrollments.map((e) => e.userId));
return (
<div className="p-8 max-w-4xl">
{/* Breadcrumb */}
<nav className="text-sm text-slate-400 mb-6">
<Link href="/admin/courses" className="hover:text-slate-600">Курсы</Link>
<span className="mx-2">/</span>
<span className="text-slate-700">{course.title}</span>
</nav>
{/* Course metadata */}
<section className="bg-white border border-slate-200 rounded-2xl p-6 mb-6">
<h2 className="text-base font-semibold text-slate-700 mb-4">Основная информация</h2>
<CourseEditForm course={course} />
</section>
{/* Modules */}
<section className="bg-white border border-slate-200 rounded-2xl p-6 mb-6">
<div className="flex items-center justify-between mb-4">
<h2 className="text-base font-semibold text-slate-700">Модули</h2>
<span className="text-sm text-slate-400">{course.modules.length} модулей</span>
</div>
<SortableModules courseId={courseId} modules={course.modules} />
</section>
{/* Access management */}
<section className="bg-white border border-slate-200 rounded-2xl p-6">
<h2 className="text-base font-semibold text-slate-700 mb-4">Доступ к курсу</h2>
<EnrollmentManager
courseId={courseId}
allStudents={allStudents}
enrolledIds={[...enrolledIds]}
/>
</section>
</div>
);
}