import { Prisma } from '@/prisma/generated/client'; import { NextResponse } from 'next/server'; import db from '@/lib/db'; import bcrypt from 'bcryptjs'; import { Role } from '@/config/enum'; import { SignUpSchema } from '@/lib/schemas'; import { UserQueryString } from '@/config/types'; import { getUserByEmail, parseSearchParams, genUsername } from '@/helpers/user'; export async function GET(req: Request) { const { searchParams } = new URL(req.url); const query: UserQueryString = parseSearchParams(searchParams); const isKoas = Role.Koas; const isPasien = Role.Pasien; const isFasilitator = Role.Fasilitator; try { const user = await db.user.findMany({ where: { ...query, } as Prisma.UserWhereInput, orderBy: { name: 'asc', }, include: { KoasProfile: { include: { Review: { include: { user: true, }, }, }, }, PasienProfile: true, FasilitatorProfile: true, }, }); const users = await Promise.all( user.map(async (user) => { if (user.role === Role.Koas) { const totalReviews = await db.review.count({ where: { koasId: user.KoasProfile!.userId, }, }); const averageRating = await db.review.aggregate({ _avg: { rating: true, }, where: { koasId: user.KoasProfile!.userId, }, }); const patientCount = await db.appointment.count({ where: { koasId: user.KoasProfile!.id, status: 'Completed', }, }); const { createdAt, updateAt, ...koasProfileWithoutDates } = user.KoasProfile!; return { ...user, KoasProfile: { ...koasProfileWithoutDates, stats: { totalReviews, averageRating: parseFloat( (averageRating._avg.rating || 0.0).toFixed(1) ), patientCount, }, createdAt, updateAt, }, PasienProfile: undefined, // sembunyikan pasien profile FasilitatorProfile: undefined, // sembunyikan fasilitator profile }; } else if (user.role === Role.Pasien) { return { ...user, KoasProfile: undefined, // sembunyikan koas profile FasilitatorProfile: undefined, // sembunyikan fasilitator profile }; } else if (user.role === Role.Fasilitator) { return { ...user, KoasProfile: undefined, // sembunyikan koas profile PasienProfile: undefined, // sembunyikan pasien profile }; } else { return { ...user, KoasProfile: undefined, // sembunyikan koas profile PasienProfile: undefined, // sembunyikan pasien profile FasilitatorProfile: undefined, // sembunyikan fasilitator profile }; } }) ); return NextResponse.json( { users, }, { status: 200 } ); } catch (error) { if (error instanceof Error) { console.error('Error fetching user', error.stack); } else { console.error('Error fetching user', error); } return NextResponse.json( { error: 'Internal Server Error' }, { status: 500 } ); } } export async function POST(req: Request) { try { const body = await req.json(); // Accept both camelCase and snake_case for names const { id, givenName, familyName, firstName, lastName, email, password, phone, role, profile, image, name: nameFromBody, } = body; console.log('Received Body:', body); // Use givenName/familyName if present, else fallback to firstName/lastName const userGivenName = givenName ?? firstName ?? ''; const userFamilyName = familyName ?? lastName ?? ''; // Check if this is an OAuth signup (no password) const isOauth = !password || password === null || password === undefined; // Validate required fields if (!email || !role) { return NextResponse.json( { error: 'Email and role are required.' }, { status: 400 } ); } // Check for existing user const existingUser = await getUserByEmail(email); if (existingUser) { console.log(`Attempted signup with existing email: ${email}`); return NextResponse.json( { error: 'Email already in use.' }, { status: 400 } ); } const university = await db.university.findFirst({ where: { alias: 'UNEJ', }, }); if (!university) { return NextResponse.json( { error: 'University not found.' }, { status: 400 } ); } // Only hash password if not OAuth and password is provided let hash: string | null = null; if (!isOauth) { if (typeof password !== 'string' || password.length === 0) { return NextResponse.json( { error: 'Password is required for non-OAuth signup.' }, { status: 400 } ); } try { hash = await bcrypt.hash(password, 10); } catch (err) { console.error('Error hashing password:', err); return NextResponse.json( { error: 'Failed to process password.' }, { status: 500 } ); } } // Generate username if not provided let name = nameFromBody; if (!name) { name = await genUsername(userGivenName, userFamilyName); } // Create the user const newUser = await db.user.create({ data: { id, givenName: userGivenName, familyName: userFamilyName, name, email, password: hash, phone, image: image ?? null, role: role ?? null, } as Prisma.UserCreateInput, }); // Create profile based on role if (newUser.role === Role.Koas) { await db.koasProfile.create({ data: { ...profile, university: university.name, universityId: university.id, userId: newUser.id, }, }); } else if (newUser.role === Role.Pasien) { await db.pasienProfile.create({ data: { ...profile, userId: newUser.id, }, }); } else if (newUser.role === Role.Fasilitator) { await db.fasilitatorProfile.create({ data: { ...profile, university: university.name, userId: newUser.id, }, }); } else if (newUser.role === Role.Admin) { // For admin, just update emailVerified await db.user.update({ where: { id: newUser.id }, data: { emailVerified: new Date(), }, }); } else { return NextResponse.json({ error: 'Invalid role' }, { status: 400 }); } // If OAuth, mark email as verified if (isOauth) { await db.user.update({ where: { id: newUser.id }, data: { emailVerified: new Date() }, }); } return NextResponse.json( { status: 'Success', message: 'User created successfully', data: { user: newUser }, }, { status: 201 } ); } catch (error) { if (error instanceof Error) { console.error('Error in POST /api/users:', error.stack); return NextResponse.json({ error: error.message }, { status: 500 }); } else { console.error('Unknown error in POST /api/users:', error); return NextResponse.json( { error: 'Internal Server Error' }, { status: 500 } ); } } } export async function DELETE(req: Request) { try { await db.user.deleteMany({}); return NextResponse.json( { status: 'Success', message: 'All users deleted successfully', }, { status: 200 } ); } catch (error) { console.error('Error deleting all users', error); return NextResponse.json( { error: 'Internal Server Error' }, { status: 500 } ); } }