Stage 1: Course/Module/Lesson CRUD admin UI with TipTap editor

This commit is contained in:
2026-04-07 11:36:27 +05:00
parent 9d82b73e58
commit d356dddc96
30 changed files with 2090 additions and 41 deletions
@@ -0,0 +1,64 @@
"use server";
import { prisma } from "@/lib/prisma";
import { headers } from "next/headers";
import { auth } from "@/lib/auth";
import { revalidatePath } from "next/cache";
async function requireAdmin() {
const session = await auth.api.getSession({ headers: await headers() });
if (!session || session.user.role !== "admin") throw new Error("Forbidden");
}
// ── Modules ──────────────────────────────────────────────────────────────────
export async function createModule(courseId: string, formData: FormData) {
await requireAdmin();
const title = formData.get("title") as string;
const count = await prisma.module.count({ where: { courseId } });
await prisma.module.create({ data: { courseId, title, order: count } });
revalidatePath(`/admin/courses/${courseId}`);
}
export async function updateModule(moduleId: string, courseId: string, formData: FormData) {
await requireAdmin();
const title = formData.get("title") as string;
await prisma.module.update({ where: { id: moduleId }, data: { title } });
revalidatePath(`/admin/courses/${courseId}`);
}
export async function deleteModule(moduleId: string, courseId: string) {
await requireAdmin();
await prisma.module.delete({ where: { id: moduleId } });
revalidatePath(`/admin/courses/${courseId}`);
}
export async function reorderModules(courseId: string, orderedIds: string[]) {
await requireAdmin();
await Promise.all(
orderedIds.map((id, index) =>
prisma.module.update({ where: { id }, data: { order: index } })
)
);
revalidatePath(`/admin/courses/${courseId}`);
}
// ── Enrollment ───────────────────────────────────────────────────────────────
export async function grantAccess(courseId: string, userId: string) {
await requireAdmin();
await prisma.courseEnrollment.upsert({
where: { userId_courseId: { userId, courseId } },
update: {},
create: { userId, courseId },
});
revalidatePath(`/admin/courses/${courseId}`);
}
export async function revokeAccess(courseId: string, userId: string) {
await requireAdmin();
await prisma.courseEnrollment.delete({
where: { userId_courseId: { userId, courseId } },
});
revalidatePath(`/admin/courses/${courseId}`);
}