Stage 1: Course/Module/Lesson CRUD admin UI with TipTap editor
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user