Files
lms-sb/src/app/admin/courses/[courseId]/modules/[moduleId]/actions.ts
T
admins 768a38b9d3 Add course tree, lesson actions, and module description schema
- CourseTree: expandable module/lesson overview with Eye/Video icons
- SortableLessons: Kinescope ID in create form, published toggle, move-to-module dropdown
- Actions: toggleLessonPublished, moveLessonToModule, updateModule with description
- Schema: add description field to Module model + migration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 13:32:30 +05:00

91 lines
3.0 KiB
TypeScript

"use server";
import { prisma } from "@/lib/prisma";
import { headers } from "next/headers";
import { auth } from "@/lib/auth";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
async function requireAdmin() {
const session = await auth.api.getSession({ headers: await headers() });
if (!session || session.user.role !== "admin") throw new Error("Forbidden");
}
export async function createLesson(moduleId: string, courseId: string, formData: FormData) {
await requireAdmin();
const title = formData.get("title") as string;
const kinescopeId = (formData.get("kinescopeId") as string | null)?.trim() || null;
const count = await prisma.lesson.count({ where: { moduleId } });
const lesson = await prisma.lesson.create({
data: { moduleId, title, kinescopeId, order: count },
});
revalidatePath(`/admin/courses/${courseId}/modules/${moduleId}`);
redirect(`/admin/courses/${courseId}/modules/${moduleId}/lessons/${lesson.id}`);
}
export async function updateLesson(lessonId: string, courseId: string, moduleId: string, formData: FormData) {
await requireAdmin();
const title = formData.get("title") as string;
await prisma.lesson.update({ where: { id: lessonId }, data: { title } });
revalidatePath(`/admin/courses/${courseId}/modules/${moduleId}`);
}
export async function deleteLesson(lessonId: string, courseId: string, moduleId: string) {
await requireAdmin();
await prisma.lesson.delete({ where: { id: lessonId } });
revalidatePath(`/admin/courses/${courseId}/modules/${moduleId}`);
}
export async function reorderLessons(moduleId: string, courseId: string, orderedIds: string[]) {
await requireAdmin();
await Promise.all(
orderedIds.map((id, index) =>
prisma.lesson.update({ where: { id }, data: { order: index } })
)
);
revalidatePath(`/admin/courses/${courseId}/modules/${moduleId}`);
}
export async function toggleLessonPublished(
lessonId: string,
courseId: string,
moduleId: string,
currentValue: boolean
) {
await requireAdmin();
await prisma.lesson.update({
where: { id: lessonId },
data: { published: !currentValue },
});
revalidatePath(`/admin/courses/${courseId}/modules/${moduleId}`);
revalidatePath(`/admin/courses/${courseId}`);
}
export async function moveLessonToModule(
lessonId: string,
targetModuleId: string,
courseId: string,
sourceModuleId: string
) {
await requireAdmin();
// verify target module belongs to same course
const target = await prisma.module.findFirst({
where: { id: targetModuleId, courseId },
});
if (!target) throw new Error("Module not found");
const maxOrder = await prisma.lesson.aggregate({
where: { moduleId: targetModuleId },
_max: { order: true },
});
await prisma.lesson.update({
where: { id: lessonId },
data: { moduleId: targetModuleId, order: (maxOrder._max.order ?? -1) + 1 },
});
revalidatePath(`/admin/courses/${courseId}/modules/${sourceModuleId}`);
revalidatePath(`/admin/courses/${courseId}/modules/${targetModuleId}`);
revalidatePath(`/admin/courses/${courseId}`);
}