import { NextRequest } from "next/server"; import { z } from "zod"; import { NextResponse } from "next/server"; import { getPrisma } from "../../../../lib/db"; import { getSession } from "../../../../lib/auth/session"; import { ok, fail } from "../../../../lib/http"; export const runtime = "nodejs"; const QuerySchema = z.object({ page: z.string().default("1").transform(Number), search: z.string().optional(), }); const UpdateUserSchema = z.object({ role: z.enum(["USER", "ADMIN"]).optional(), isActive: z.boolean().optional(), }); export async function GET(req: NextRequest) { const session = await getSession(); if (!session || session.role !== "ADMIN") { return fail(new Error("Unauthorized"), { status: 401 }); } const prisma = await getPrisma(); if (!prisma) return fail(new Error("Database not configured"), { status: 503 }); const parsed = QuerySchema.safeParse( Object.fromEntries(new URL(req.url).searchParams) ); if (!parsed.success) return fail(new Error("Invalid query parameters")); const appSetup = await prisma.appSetup.findUnique({ where: { id: 1 } }); const pageSize = appSetup?.paginationItemsPerPage || 10; const page = Math.max(1, parsed.data.page); const skip = (page - 1) * pageSize; const searchFilter = parsed.data.search ? { OR: [ { email: { contains: parsed.data.search, mode: "insensitive" as const } }, { firstName: { contains: parsed.data.search, mode: "insensitive" as const } }, { lastName: { contains: parsed.data.search, mode: "insensitive" as const } }, ], } : undefined; const [users, total] = await Promise.all([ prisma.user.findMany({ where: searchFilter, select: { id: true, email: true, firstName: true, lastName: true, role: true, isActive: true, emailVerified: true, createdAt: true, gender: true, dob: true, address: true, image: true, }, orderBy: { createdAt: "desc" }, skip, take: pageSize, }), prisma.user.count({ where: searchFilter }), ]); // Fetch webinars for each user const usersWithWebinars = await Promise.all( users.map(async (user) => { const registrations = await prisma.webinarRegistration.findMany({ where: { userId: user.id, status: { not: "CANCELLED" } }, }); return { ...user, _count: { webinarRegistrations: registrations.length, }, registeredWebinars: await prisma.webinarRegistration.findMany({ where: { userId: user.id, status: { not: "CANCELLED" } }, select: { id: true, status: true, webinar: { select: { id: true, title: true, startAt: true, }, }, }, orderBy: { createdAt: "desc" }, take: 5, }), }; }) ); return ok({ users: usersWithWebinars, pagination: { page, pageSize, total, pages: Math.ceil(total / pageSize), hasMore: page < Math.ceil(total / pageSize), }, }); } export async function PATCH(req: NextRequest) { const session = await getSession(); if (!session || session.role !== "ADMIN") { return fail(new Error("Unauthorized"), { status: 401 }); } const prisma = await getPrisma(); if (!prisma) return fail(new Error("Database not configured"), { status: 503 }); const body = await req.json().catch(() => ({})); const { userId, ...updateData } = body; if (!userId) return fail(new Error("userId is required")); const parsed = UpdateUserSchema.safeParse(updateData); if (!parsed.success) return fail(new Error("Invalid update data")); // Prevent disabling the current admin if (session.sub === userId && parsed.data.isActive === false) { return fail(new Error("Cannot disable your own account"), { status: 400 }); } // Prevent removing admin role from self if (session.sub === userId && parsed.data.role && parsed.data.role !== "ADMIN") { return fail(new Error("Cannot change your own role"), { status: 400 }); } const user = await prisma.user.update({ where: { id: userId }, data: { ...(parsed.data.role && { role: parsed.data.role }), ...(parsed.data.isActive !== undefined && { isActive: parsed.data.isActive }), }, select: { id: true, email: true, firstName: true, lastName: true, role: true, isActive: true, }, }); return ok({ message: parsed.data.isActive === false ? "User blocked successfully" : "User updated successfully", user, }); }