import { NextRequest, NextResponse } from 'next/server'; import supabase from '@/lib/db'; // Define the NilaiMahasiswa type interface NilaiMahasiswa { id_nilai: number; id_mahasiswa: number; id_mk: number; nim: string; nama: string; kode_mk: string; nama_mk: string; nilai_huruf: 'A' | 'B+' | 'B' | 'C+' | 'C' | 'D+' | 'D' | 'E'; nilai_angka: number; semester: number; created_at: string; updated_at: string; } // GET - Ambil semua data nilai mahasiswa atau satu nilai spesifik berdasarkan ID export async function GET(request: NextRequest) { try { const { searchParams } = new URL(request.url); const id = searchParams.get('id'); const search = searchParams.get('search'); const semester = searchParams.get('semester'); const nilai_huruf = searchParams.get('nilai_huruf'); if (id) { // Ambil nilai spesifik berdasarkan ID dengan join ke mahasiswa dan mata_kuliah const { data, error } = await supabase .from('nilai_mahasiswa') .select(` id_nilai, id_mahasiswa, id_mk, nilai_huruf, nilai_angka, semester, created_at, updated_at, mahasiswa!inner(nim, nama), mata_kuliah!inner(kode_mk, nama_mk) `) .eq('id_nilai', id) .single(); if (error || !data) { return NextResponse.json({ message: 'Nilai mahasiswa not found' }, { status: 404 }); } // Transformasi data untuk meratakan field yang di-join const transformedData: any = { ...data, nim: (data.mahasiswa as any)?.nim || '', nama: (data.mahasiswa as any)?.nama || '', kode_mk: (data.mata_kuliah as any)?.kode_mk || '', nama_mk: (data.mata_kuliah as any)?.nama_mk || '' }; delete transformedData.mahasiswa; delete transformedData.mata_kuliah; return NextResponse.json(transformedData); } else { // Ambil semua nilai mahasiswa dengan join let query = supabase .from('nilai_mahasiswa') .select(` id_nilai, id_mahasiswa, id_mk, nilai_huruf, nilai_angka, semester, created_at, updated_at, mahasiswa!inner(nim, nama), mata_kuliah!inner(kode_mk, nama_mk) `); // Add semester filter if provided if (semester && semester !== 'all') { query = query.eq('semester', parseInt(semester)); } // Add nilai_huruf filter if provided if (nilai_huruf && nilai_huruf !== 'all') { query = query.eq('nilai_huruf', nilai_huruf); } // Add order by query = query.order('semester', { ascending: true }); const { data, error } = await query; if (error) { console.error('Error fetching data:', error); return NextResponse.json({ message: 'Internal Server Error' }, { status: 500 }); } // Transformasi data untuk meratakan field yang di-join let transformedData = data.map((item: any) => ({ ...item, nim: item.mahasiswa?.nim || '', nama: item.mahasiswa?.nama || '', kode_mk: item.mata_kuliah?.kode_mk || '', nama_mk: item.mata_kuliah?.nama_mk || '' })).map((item: any) => { const { mahasiswa, mata_kuliah, ...rest } = item; return rest; }); // Client-side search filtering (untuk joined tables) if (search) { const searchLower = search.toLowerCase(); transformedData = transformedData.filter((item: any) => { return ( item.nim?.toLowerCase().includes(searchLower) || item.nama?.toLowerCase().includes(searchLower) || item.kode_mk?.toLowerCase().includes(searchLower) || item.nama_mk?.toLowerCase().includes(searchLower) ); }); } // Sort by nim after filtering transformedData.sort((a: any, b: any) => { if (a.semester !== b.semester) { return a.semester - b.semester; } return a.nim.localeCompare(b.nim); }); return NextResponse.json(transformedData); } } catch (error) { console.error('Error fetching data:', error); return NextResponse.json({ message: 'Internal Server Error' }, { status: 500 }); } } // POST - Buat data nilai mahasiswa baru export async function POST(request: NextRequest) { try { const body = await request.json(); const { nim, id_mk, nilai_huruf, nilai_angka, semester } = body; // Validasi field yang wajib diisi if (!nim || !id_mk || !nilai_huruf || nilai_angka === undefined || !semester) { return NextResponse.json( { message: 'Missing required fields: nim, id_mk, nilai_huruf, nilai_angka, semester' }, { status: 400 } ); } // Validasi nilai huruf const validNilaiHuruf = ['A', 'B+', 'B', 'C+', 'C', 'D+', 'D', 'E']; if (!validNilaiHuruf.includes(nilai_huruf)) { return NextResponse.json( { message: 'Invalid nilai_huruf. Must be one of: A, B+, B, C+, C, D+, D, E' }, { status: 400 } ); } // Validasi nilai angka if (nilai_angka < 0 || nilai_angka > 4) { return NextResponse.json( { message: 'nilai_angka must be between 0 and 4' }, { status: 400 } ); } // Validasi semester if (semester <= 0) { return NextResponse.json( { message: 'semester must be greater than 0' }, { status: 400 } ); } // Cek apakah mahasiswa dengan NIM tersebut ada const { data: mahasiswa, error: mahasiswaError } = await supabase .from('mahasiswa') .select('id_mahasiswa, nim, nama') .eq('nim', nim) .single(); if (mahasiswaError || !mahasiswa) { return NextResponse.json( { message: `Mahasiswa dengan NIM ${nim} tidak terdaftar` }, { status: 404 } ); } // Cek apakah mata kuliah ada const { data: mataKuliah, error: mkError } = await supabase .from('mata_kuliah') .select('id_mk, kode_mk, nama_mk') .eq('id_mk', id_mk) .single(); if (mkError || !mataKuliah) { return NextResponse.json( { message: 'Mata kuliah not found' }, { status: 404 } ); } // Cek apakah nilai untuk mahasiswa dan mata kuliah ini sudah ada const { data: existingNilai, error: checkError } = await supabase .from('nilai_mahasiswa') .select('id_nilai') .eq('id_mahasiswa', mahasiswa.id_mahasiswa) .eq('id_mk', id_mk) .single(); if (existingNilai) { return NextResponse.json( { message: `Nilai untuk mahasiswa ${nim} pada mata kuliah ${mataKuliah.kode_mk} sudah ada` }, { status: 409 } ); } // Insert nilai baru const { data, error } = await supabase .from('nilai_mahasiswa') .insert({ id_mahasiswa: mahasiswa.id_mahasiswa, id_mk: parseInt(id_mk), nilai_huruf, nilai_angka: parseFloat(nilai_angka), semester: parseInt(semester) }) .select() .single(); if (error) { console.error('Error creating nilai mahasiswa:', error); return NextResponse.json({ message: 'Internal Server Error' }, { status: 500 }); } return NextResponse.json( { message: 'Nilai mahasiswa berhasil ditambahkan', id: data.id_nilai, mahasiswa: mahasiswa.nama, mata_kuliah: mataKuliah.nama_mk }, { status: 201 } ); } catch (error) { console.error('Error creating nilai mahasiswa:', error); return NextResponse.json({ message: 'Internal Server Error' }, { status: 500 }); } } // PUT - Update data nilai mahasiswa yang sudah ada export async function PUT(request: NextRequest) { try { const { searchParams } = new URL(request.url); const id = searchParams.get('id'); if (!id) { return NextResponse.json({ message: 'ID is required' }, { status: 400 }); } const body = await request.json(); const { nim, id_mk, nilai_huruf, nilai_angka, semester } = body; // Validasi field yang wajib diisi if (!nim || !id_mk || !nilai_huruf || nilai_angka === undefined || !semester) { return NextResponse.json( { message: 'Missing required fields: nim, id_mk, nilai_huruf, nilai_angka, semester' }, { status: 400 } ); } // Validasi nilai huruf const validNilaiHuruf = ['A', 'B+', 'B', 'C+', 'C', 'D+', 'D', 'E']; if (!validNilaiHuruf.includes(nilai_huruf)) { return NextResponse.json( { message: 'Invalid nilai_huruf. Must be one of: A, B+, B, C+, C, D+, D, E' }, { status: 400 } ); } // Validasi nilai angka if (nilai_angka < 0 || nilai_angka > 4) { return NextResponse.json( { message: 'nilai_angka must be between 0 and 4' }, { status: 400 } ); } // Validasi semester if (semester <= 0) { return NextResponse.json( { message: 'semester must be greater than 0' }, { status: 400 } ); } // Cek apakah nilai ada const { data: existing, error: checkError } = await supabase .from('nilai_mahasiswa') .select('*') .eq('id_nilai', id) .single(); if (checkError || !existing) { return NextResponse.json({ message: 'Nilai mahasiswa not found' }, { status: 404 }); } // Cek apakah mahasiswa dengan NIM tersebut ada const { data: mahasiswa, error: mahasiswaError } = await supabase .from('mahasiswa') .select('id_mahasiswa, nim, nama') .eq('nim', nim) .single(); if (mahasiswaError || !mahasiswa) { return NextResponse.json( { message: `Mahasiswa dengan NIM ${nim} tidak terdaftar` }, { status: 404 } ); } // Cek apakah mata kuliah ada const { data: mataKuliah, error: mkError } = await supabase .from('mata_kuliah') .select('id_mk, kode_mk, nama_mk') .eq('id_mk', id_mk) .single(); if (mkError || !mataKuliah) { return NextResponse.json( { message: 'Mata kuliah not found' }, { status: 404 } ); } // Cek apakah kombinasi mahasiswa-mata kuliah sudah digunakan oleh nilai lain const { data: duplicateNilai, error: duplicateError } = await supabase .from('nilai_mahasiswa') .select('id_nilai') .eq('id_mahasiswa', mahasiswa.id_mahasiswa) .eq('id_mk', id_mk) .neq('id_nilai', id) .single(); if (duplicateNilai) { return NextResponse.json( { message: `Nilai untuk mahasiswa ${nim} pada mata kuliah ${mataKuliah.kode_mk} sudah ada` }, { status: 409 } ); } // Update nilai const { error } = await supabase .from('nilai_mahasiswa') .update({ id_mahasiswa: mahasiswa.id_mahasiswa, id_mk: parseInt(id_mk), nilai_huruf, nilai_angka: parseFloat(nilai_angka), semester: parseInt(semester), updated_at: new Date().toISOString() }) .eq('id_nilai', id); if (error) { console.error('Error updating nilai mahasiswa:', error); return NextResponse.json({ message: 'Internal Server Error' }, { status: 500 }); } return NextResponse.json({ message: 'Nilai mahasiswa berhasil diperbarui' }); } catch (error) { console.error('Error updating nilai mahasiswa:', error); return NextResponse.json({ message: 'Internal Server Error' }, { status: 500 }); } } // DELETE - Hapus data nilai mahasiswa export async function DELETE(request: NextRequest) { try { const { searchParams } = new URL(request.url); const id = searchParams.get('id'); if (!id) { return NextResponse.json({ message: 'ID is required' }, { status: 400 }); } // Check if nilai exists const { data: existing, error: checkError } = await supabase .from('nilai_mahasiswa') .select(` id_nilai, mahasiswa!inner(nim, nama), mata_kuliah!inner(kode_mk, nama_mk) `) .eq('id_nilai', id) .single(); if (checkError || !existing) { return NextResponse.json({ message: 'Nilai mahasiswa not found' }, { status: 404 }); } // Hapus nilai const { error } = await supabase .from('nilai_mahasiswa') .delete() .eq('id_nilai', id); if (error) { console.error('Error deleting nilai mahasiswa:', error); return NextResponse.json({ message: 'Internal Server Error' }, { status: 500 }); } return NextResponse.json({ message: 'Nilai mahasiswa berhasil dihapus' }); } catch (error) { console.error('Error deleting nilai mahasiswa:', error); return NextResponse.json({ message: 'Internal Server Error' }, { status: 500 }); } }