47840901c5
Hamburger button (top-left, lg:hidden), dark overlay, slide-in animation. Sidebar closes on lesson link click. Spacer added to prevent content overlap. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
71 lines
2.0 KiB
TypeScript
71 lines
2.0 KiB
TypeScript
import { headers } from "next/headers";
|
|
import { auth } from "@/lib/auth";
|
|
import { redirect } from "next/navigation";
|
|
import { prisma } from "@/lib/prisma";
|
|
import { notFound } from "next/navigation";
|
|
import { CourseSidebar } from "@/components/student/course-sidebar";
|
|
|
|
interface Props {
|
|
children: React.ReactNode;
|
|
params: Promise<{ slug: string }>;
|
|
}
|
|
|
|
export default async function CourseLayout({ children, params }: Props) {
|
|
const { slug } = await params;
|
|
const session = await auth.api.getSession({ headers: await headers() });
|
|
if (!session) redirect("/login");
|
|
|
|
const isAdmin = session.user.role === "admin";
|
|
|
|
const course = await prisma.course.findUnique({
|
|
where: { slug, ...(isAdmin ? {} : { published: true }) },
|
|
include: {
|
|
modules: {
|
|
orderBy: { order: "asc" },
|
|
include: {
|
|
lessons: {
|
|
where: { published: true },
|
|
orderBy: { order: "asc" },
|
|
select: { id: true, title: true },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!course) notFound();
|
|
|
|
if (!isAdmin) {
|
|
const enrollment = await prisma.courseEnrollment.findUnique({
|
|
where: { userId_courseId: { userId: session.user.id, courseId: course.id } },
|
|
});
|
|
|
|
if (!enrollment) redirect("/dashboard");
|
|
|
|
if (enrollment.expiresAt && enrollment.expiresAt < new Date()) {
|
|
redirect("/dashboard?expired=1");
|
|
}
|
|
}
|
|
|
|
// Fetch completed lesson IDs for this user
|
|
const allLessonIds = course.modules.flatMap((m) => m.lessons.map((l) => l.id));
|
|
const progressRecords = isAdmin
|
|
? []
|
|
: await prisma.lessonProgress.findMany({
|
|
where: { userId: session.user.id, lessonId: { in: allLessonIds } },
|
|
select: { lessonId: true },
|
|
});
|
|
|
|
const completedLessonIds = new Set(progressRecords.map((p) => p.lessonId));
|
|
|
|
return (
|
|
<div className="flex flex-1">
|
|
<CourseSidebar course={course} completedLessonIds={completedLessonIds} />
|
|
<main className="flex-1 min-w-0 overflow-y-auto">
|
|
<div className="h-12 lg:hidden" />
|
|
{children}
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|