Add course management improvements: tree view, module descriptions, lesson toggles

- SortableModules: add description textarea in edit form, show description in row
- CourseDetailPage: fetch lessons per module, add CourseTree overview section
- ModulePage: fetch sibling modules, pass as otherModules to SortableLessons

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-08 13:31:30 +05:00
parent d0ba4bf909
commit f0024c4243
3 changed files with 80 additions and 30 deletions
@@ -10,13 +10,20 @@ interface Props {
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" } },
},
});
const [module, allModules] = await Promise.all([
prisma.module.findUnique({
where: { id: moduleId },
include: {
course: { select: { title: true } },
lessons: { orderBy: { order: "asc" } },
},
}),
prisma.module.findMany({
where: { courseId, NOT: { id: moduleId } },
select: { id: true, title: true },
orderBy: { order: "asc" },
}),
]);
if (!module || module.courseId !== courseId) notFound();
@@ -41,7 +48,12 @@ export default async function ModulePage({ params }: Props) {
<p className="text-xs font-bold uppercase tracking-widest mb-5" style={{ color: "var(--muted-foreground)" }}>
Уроки модуля
</p>
<SortableLessons courseId={courseId} moduleId={moduleId} lessons={module.lessons} />
<SortableLessons
courseId={courseId}
moduleId={moduleId}
lessons={module.lessons}
otherModules={allModules}
/>
</section>
</div>
);
+18 -1
View File
@@ -4,6 +4,7 @@ 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";
import { CourseTree } from "@/components/admin/course-tree";
interface Props {
params: Promise<{ courseId: string }>;
@@ -18,7 +19,13 @@ export default async function CourseDetailPage({ params }: Props) {
include: {
modules: {
orderBy: { order: "asc" },
include: { _count: { select: { lessons: true } } },
include: {
_count: { select: { lessons: true } },
lessons: {
orderBy: { order: "asc" },
select: { id: true, title: true, published: true, kinescopeId: true },
},
},
},
enrollments: {
select: { userId: true, expiresAt: true },
@@ -73,6 +80,16 @@ export default async function CourseDetailPage({ params }: Props) {
<SortableModules courseId={courseId} modules={course.modules} />
</section>
{/* Course tree overview */}
{course.modules.length > 0 && (
<section className="card-aubade p-6 mb-6">
<p className="text-xs font-bold uppercase tracking-widest mb-5" style={{ color: "var(--muted-foreground)" }}>
Структура курса
</p>
<CourseTree courseId={courseId} modules={course.modules} />
</section>
)}
{/* Access management */}
<section className="card-aubade p-6">
<p className="text-xs font-bold uppercase tracking-widest mb-5" style={{ color: "var(--muted-foreground)" }}>