import { NextResponse } from 'next/server'; import supabase from '@/lib/db'; import bcrypt from 'bcryptjs'; import { SignJWT } from 'jose'; interface User { id_user: number; nim: string; username: string; password: string; role: string; } export async function POST(request: Request) { try { console.log('Login request received'); // Test database connection first try { const { data: testData, error: testError } = await supabase .from('user_app') .select('count') .limit(1); if (testError) { console.error('Database connection error:', testError); return NextResponse.json( { error: 'Tidak dapat terhubung ke database' }, { status: 500 } ); } console.log('Database connection successful'); } catch (dbError) { console.error('Database connection error:', dbError); return NextResponse.json( { error: 'Tidak dapat terhubung ke database' }, { status: 500 } ); } const body = await request.json(); console.log('Request body:', body); const { nim, password } = body; console.log('Extracted credentials:', { nim, password: '***' }); // Validate input if (!nim || !password) { console.log('Missing credentials:', { nim: !!nim, password: !!password }); return NextResponse.json( { error: 'NIM dan password harus diisi' }, { status: 400 } ); } // Get user by NIM console.log('Querying user with NIM:', nim); let users: User[]; try { const { data, error } = await supabase .from('user_app') .select('*') .eq('nim', nim); if (error) { console.error('Database query error:', error); return NextResponse.json( { error: 'Terjadi kesalahan saat memeriksa data pengguna' }, { status: 500 } ); } users = data || []; console.log('Query result:', users.length > 0 ? 'User found' : 'User not found'); } catch (queryError) { console.error('Database query error:', queryError); return NextResponse.json( { error: 'Terjadi kesalahan saat memeriksa data pengguna' }, { status: 500 } ); } if (users.length === 0) { console.log('No user found with NIM:', nim); return NextResponse.json( { error: 'NIM atau password salah' }, { status: 401 } ); } const user = users[0]; console.log('User found:', { id: user.id_user, nim: user.nim, username: user.username, role: user.role }); // Verify password console.log('Verifying password...'); let isPasswordValid; try { isPasswordValid = await bcrypt.compare(password, user.password); console.log('Password verification result:', isPasswordValid ? 'Valid' : 'Invalid'); } catch (bcryptError) { console.error('Password verification error:', bcryptError); return NextResponse.json( { error: 'Terjadi kesalahan saat memverifikasi password' }, { status: 500 } ); } if (!isPasswordValid) { console.log('Invalid password for user:', nim); return NextResponse.json( { error: 'NIM atau password salah' }, { status: 401 } ); } // Create JWT token console.log('Creating JWT token...'); let token; try { token = await new SignJWT({ id: user.id_user, nim: user.nim, role: user.role }) .setProtectedHeader({ alg: 'HS256' }) .setExpirationTime('24h') .sign(new TextEncoder().encode(process.env.JWT_SECRET || 'your-secret-key')); console.log('JWT token created'); } catch (jwtError) { console.error('JWT creation error:', jwtError); return NextResponse.json( { error: 'Terjadi kesalahan saat membuat token' }, { status: 500 } ); } // Set cookie console.log('Setting response...'); const response = NextResponse.json({ user: { id: user.id_user, nim: user.nim, username: user.username, role: user.role } }); response.cookies.set('token', token, { httpOnly: true, secure: false, sameSite: 'lax', maxAge: 60 * 60 * 24 // 24 hours }); console.log('Cookie set'); console.log('Login process completed successfully'); return response; } catch (error) { console.error('Login error details:', error); if (error instanceof Error) { console.error('Error message:', error.message); console.error('Error stack:', error.stack); } return NextResponse.json( { error: 'Terjadi kesalahan saat login' }, { status: 500 } ); } } // Handle OPTIONS request for CORS export async function OPTIONS() { return NextResponse.json({}, { headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization', } }); }