import { notFound, redirect } from "next/navigation"; import { db } from "@/lib/prisma"; import { requireUser } from "@/lib/auth/requireUser"; import StudentClassroomClient from "@/components/courses/StudentClassroomClient"; import { parseLessonDescriptionMeta } from "@/lib/courses/lessonContent"; type LessonSelect = { id: string; title: unknown; description: unknown; videoUrl: string | null; youtubeUrl: string | null; estimatedDuration: number; isFreePreview: boolean; }; type ModuleSelect = { id: string; title: unknown; lessons: LessonSelect[] }; type CourseWithModules = { id: string; slug: string; title: unknown; price: unknown; modules: ModuleSelect[] }; function getText(value: unknown): string { if (!value) return ""; if (typeof value === "string") return value; if (typeof value === "object") { const record = value as Record; if (typeof record.es === "string") return record.es; if (typeof record.en === "string") return record.en; } return ""; } type PageProps = { params: Promise<{ slug: string }>; searchParams: Promise<{ lesson?: string }>; }; export default async function CourseLearnPage({ params, searchParams }: PageProps) { const { slug } = await params; const { lesson: requestedLessonId } = await searchParams; const user = await requireUser(); const courseSelect = { id: true, slug: true, title: true, price: true, modules: { orderBy: { orderIndex: "asc" as const }, select: { id: true, title: true, lessons: { orderBy: { orderIndex: "asc" as const }, select: { id: true, title: true, description: true, videoUrl: true, youtubeUrl: true, estimatedDuration: true, isFreePreview: true, }, }, }, }, }; const course = (await db.course.findUnique({ where: { slug }, select: courseSelect, })) as CourseWithModules | null; if (!course) { notFound(); } let enrollment: { id: string } | null = null; let isEnrolled: boolean; if (!user?.id) { // Anonymous: no enrollment, preview-only access const allLessons = course.modules.flatMap((m) => m.lessons.map((l) => ({ id: l.id, isFreePreview: l.isFreePreview })) ); const firstPreviewLesson = allLessons.find((l) => l.isFreePreview); if (!firstPreviewLesson) { redirect(`/courses/${slug}`); } isEnrolled = false; } else { enrollment = await db.enrollment.findUnique({ where: { userId_courseId: { userId: user.id, courseId: course.id, }, }, select: { id: true }, }); const isFree = Number(course.price) === 0; if (!enrollment) { if (isFree) { enrollment = await db.enrollment.create({ data: { userId: user.id, courseId: course.id, amountPaid: 0, }, select: { id: true }, }); isEnrolled = true; } else { // Paid course, no enrollment: allow only if there are preview lessons const allLessons = course.modules.flatMap((m) => m.lessons.map((l) => ({ id: l.id, isFreePreview: l.isFreePreview })) ); const firstPreviewLesson = allLessons.find((l) => l.isFreePreview); if (!firstPreviewLesson) { redirect(`/courses/${slug}`); } isEnrolled = false; } } else { isEnrolled = true; } } const completedProgress = isEnrolled && user ? await db.userProgress.findMany({ where: { userId: user.id, isCompleted: true, lesson: { module: { courseId: course.id }, }, }, select: { lessonId: true }, }) : []; const modules = course.modules.map((module) => ({ id: module.id, title: getText(module.title) || "Untitled module", lessons: module.lessons.map((lesson) => { const lessonMeta = parseLessonDescriptionMeta(lesson.description); return { id: lesson.id, title: getText(lesson.title) || "Untitled lesson", description: lessonMeta.text, contentType: lessonMeta.contentType, materialUrl: lessonMeta.materialUrl, videoUrl: lesson.videoUrl, youtubeUrl: lesson.youtubeUrl, estimatedDuration: lesson.estimatedDuration, isFreePreview: lesson.isFreePreview, }; }), })); const flattenedLessons = modules.flatMap((module) => module.lessons); const flattenedLessonIds = flattenedLessons.map((l) => l.id); let initialSelectedLessonId: string; if (isEnrolled) { initialSelectedLessonId = requestedLessonId && flattenedLessonIds.includes(requestedLessonId) ? requestedLessonId : flattenedLessonIds[0] ?? ""; } else { const firstPreview = flattenedLessons.find((l) => l.isFreePreview); const requestedLesson = requestedLessonId ? flattenedLessons.find((l) => l.id === requestedLessonId) : null; if (requestedLesson?.isFreePreview) { initialSelectedLessonId = requestedLessonId!; } else { initialSelectedLessonId = firstPreview?.id ?? ""; } } return ( p.lessonId)} isEnrolled={isEnrolled} /> ); }