Change Database
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { cookies } from 'next/headers';
|
||||
import { jwtVerify } from 'jose';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
export async function GET() {
|
||||
let connection;
|
||||
try {
|
||||
const token = (await (await cookies()).get('token'))?.value;
|
||||
|
||||
@@ -21,39 +20,29 @@ export async function GET() {
|
||||
new TextEncoder().encode(process.env.JWT_SECRET || 'your-secret-key')
|
||||
);
|
||||
|
||||
// Get connection from pool
|
||||
connection = await pool.getConnection();
|
||||
// Get user data from user_app table
|
||||
const { data: users, error } = await supabase
|
||||
.from('user_app')
|
||||
.select('id_user, nim, username, role')
|
||||
.eq('id_user', payload.id)
|
||||
.single();
|
||||
|
||||
// Get user data
|
||||
const [users]: any = await connection.execute(
|
||||
'SELECT id_user, nim, username, role FROM user WHERE id_user = ?',
|
||||
[payload.id]
|
||||
);
|
||||
|
||||
if (users.length === 0) {
|
||||
connection.release();
|
||||
if (error || !users) {
|
||||
return NextResponse.json(
|
||||
{ error: 'User not found' },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
const user = users[0];
|
||||
connection.release();
|
||||
|
||||
return NextResponse.json({
|
||||
user: {
|
||||
id: user.id_user,
|
||||
nim: user.nim,
|
||||
username: user.username,
|
||||
role: user.role
|
||||
id: users.id_user,
|
||||
nim: users.nim,
|
||||
username: users.username,
|
||||
role: users.role
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
if (connection) {
|
||||
connection.release();
|
||||
}
|
||||
|
||||
console.error('Auth check error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Unauthorized' },
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import { SignJWT } from 'jose';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
|
||||
interface User extends RowDataPacket {
|
||||
interface User {
|
||||
id_user: number;
|
||||
nim: string;
|
||||
username: string;
|
||||
@@ -13,13 +12,23 @@ interface User extends RowDataPacket {
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
let connection;
|
||||
try {
|
||||
console.log('Login request received');
|
||||
|
||||
// Test database connection first
|
||||
try {
|
||||
connection = await pool.getConnection();
|
||||
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);
|
||||
@@ -48,11 +57,20 @@ export async function POST(request: Request) {
|
||||
console.log('Querying user with NIM:', nim);
|
||||
let users: User[];
|
||||
try {
|
||||
const [rows] = await connection.execute<User[]>(
|
||||
'SELECT * FROM user WHERE nim = ?',
|
||||
[nim]
|
||||
);
|
||||
users = rows;
|
||||
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);
|
||||
@@ -64,7 +82,6 @@ export async function POST(request: Request) {
|
||||
|
||||
if (users.length === 0) {
|
||||
console.log('No user found with NIM:', nim);
|
||||
connection.release();
|
||||
return NextResponse.json(
|
||||
{ error: 'NIM atau password salah' },
|
||||
{ status: 401 }
|
||||
@@ -95,7 +112,6 @@ export async function POST(request: Request) {
|
||||
|
||||
if (!isPasswordValid) {
|
||||
console.log('Invalid password for user:', nim);
|
||||
connection.release();
|
||||
return NextResponse.json(
|
||||
{ error: 'NIM atau password salah' },
|
||||
{ status: 401 }
|
||||
@@ -142,14 +158,9 @@ export async function POST(request: Request) {
|
||||
});
|
||||
console.log('Cookie set');
|
||||
|
||||
connection.release();
|
||||
console.log('Login process completed successfully');
|
||||
return response;
|
||||
} catch (error) {
|
||||
if (connection) {
|
||||
connection.release();
|
||||
}
|
||||
|
||||
console.error('Login error details:', error);
|
||||
if (error instanceof Error) {
|
||||
console.error('Error message:', error.message);
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
import bcrypt from 'bcryptjs';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
let connection;
|
||||
try {
|
||||
const { username, nim, password } = await request.json();
|
||||
|
||||
@@ -23,31 +22,28 @@ export async function POST(request: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
// Get connection from pool
|
||||
connection = await pool.getConnection();
|
||||
|
||||
// Check if NIM exists in mahasiswa table
|
||||
const [mahasiswa]: any = await connection.execute(
|
||||
'SELECT * FROM mahasiswa WHERE nim = ?',
|
||||
[nim]
|
||||
);
|
||||
const { data: mahasiswa, error: mahasiswaError } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select('nim')
|
||||
.eq('nim', nim)
|
||||
.single();
|
||||
|
||||
if (mahasiswa.length === 0) {
|
||||
connection.release();
|
||||
if (mahasiswaError || !mahasiswa) {
|
||||
return NextResponse.json(
|
||||
{ error: 'NIM tidak terdaftar sebagai mahasiswa' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Check if NIM already exists in user table
|
||||
const [existingUsers]: any = await connection.execute(
|
||||
'SELECT * FROM user WHERE nim = ?',
|
||||
[nim]
|
||||
);
|
||||
// Check if NIM already exists in user_app table
|
||||
const { data: existingUsers, error: userError } = await supabase
|
||||
.from('user_app')
|
||||
.select('nim')
|
||||
.eq('nim', nim)
|
||||
.single();
|
||||
|
||||
if (existingUsers.length > 0) {
|
||||
connection.release();
|
||||
if (!userError && existingUsers) {
|
||||
return NextResponse.json(
|
||||
{ error: 'NIM sudah terdaftar sebagai pengguna' },
|
||||
{ status: 400 }
|
||||
@@ -58,22 +54,30 @@ export async function POST(request: Request) {
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
|
||||
// Insert new user
|
||||
await connection.execute(
|
||||
'INSERT INTO user (nim, username, password, role, created_at, updated_at) VALUES (?, ?, ?, ?, NOW(), NOW())',
|
||||
[nim, username, hashedPassword, 'mahasiswa']
|
||||
);
|
||||
const { data: newUser, error: insertError } = await supabase
|
||||
.from('user_app')
|
||||
.insert({
|
||||
nim: nim,
|
||||
username: username,
|
||||
password: hashedPassword,
|
||||
role: 'mahasiswa'
|
||||
})
|
||||
.select()
|
||||
.single();
|
||||
|
||||
connection.release();
|
||||
if (insertError) {
|
||||
console.error('Insert error:', insertError);
|
||||
return NextResponse.json(
|
||||
{ error: 'Terjadi kesalahan saat registrasi' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{ message: 'Registrasi berhasil' },
|
||||
{ status: 201 }
|
||||
);
|
||||
} catch (error) {
|
||||
if (connection) {
|
||||
connection.release();
|
||||
}
|
||||
|
||||
console.error('Registration error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Terjadi kesalahan saat registrasi' },
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface AsalDaerah extends RowDataPacket {
|
||||
interface AsalDaerah {
|
||||
kabupaten: string;
|
||||
jumlah: number;
|
||||
}
|
||||
@@ -18,18 +17,46 @@ export async function GET(request: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
const connection = await pool.getConnection();
|
||||
|
||||
try {
|
||||
const query = `
|
||||
SELECT kabupaten, COUNT(*) AS jumlah
|
||||
FROM mahasiswa
|
||||
WHERE tahun_angkatan = ?
|
||||
GROUP BY kabupaten
|
||||
ORDER BY jumlah DESC, kabupaten ASC
|
||||
`;
|
||||
const { data, error } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select('kabupaten')
|
||||
.eq('tahun_angkatan', parseInt(tahunAngkatan));
|
||||
|
||||
const [results] = await connection.query<AsalDaerah[]>(query, [tahunAngkatan]);
|
||||
if (error) {
|
||||
console.error('Error fetching asal daerah per angkatan:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch asal daerah data' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Group by kabupaten and count
|
||||
const groupedData = data.reduce((acc, item) => {
|
||||
acc[item.kabupaten] = (acc[item.kabupaten] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
// Convert to final format and sort
|
||||
const results: AsalDaerah[] = Object.entries(groupedData)
|
||||
.map(([kabupaten, jumlah]) => ({
|
||||
kabupaten,
|
||||
jumlah
|
||||
}))
|
||||
.sort((a, b) => {
|
||||
// Sort by jumlah DESC, then by kabupaten ASC
|
||||
if (a.jumlah !== b.jumlah) {
|
||||
return b.jumlah - a.jumlah;
|
||||
}
|
||||
return a.kabupaten.localeCompare(b.kabupaten);
|
||||
});
|
||||
|
||||
return NextResponse.json(results, {
|
||||
headers: {
|
||||
@@ -52,7 +79,5 @@ export async function GET(request: Request) {
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
@@ -7,37 +7,66 @@ export async function GET(request: Request) {
|
||||
const tahunAngkatan = searchParams.get('tahunAngkatan');
|
||||
const jenisBeasiswa = searchParams.get('jenisBeasiswa');
|
||||
|
||||
let query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
m.kabupaten,
|
||||
COUNT(m.nim) AS jumlah_mahasiswa
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
beasiswa_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.jenis_beasiswa = ?
|
||||
`;
|
||||
let query = supabase
|
||||
.from('mahasiswa')
|
||||
.select(`
|
||||
tahun_angkatan,
|
||||
kabupaten,
|
||||
beasiswa_mahasiswa!inner(
|
||||
jenis_beasiswa
|
||||
)
|
||||
`)
|
||||
.eq('beasiswa_mahasiswa.jenis_beasiswa', jenisBeasiswa);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ` AND m.tahun_angkatan = ?`;
|
||||
query = query.eq('tahun_angkatan', tahunAngkatan);
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY
|
||||
m.kabupaten, m.tahun_angkatan
|
||||
ORDER BY
|
||||
m.tahun_angkatan ASC, m.kabupaten
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const params = [jenisBeasiswa];
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
params.push(tahunAngkatan);
|
||||
if (error) {
|
||||
console.error('Supabase error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Database error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
const [rows] = await pool.query(query, params);
|
||||
return NextResponse.json(rows);
|
||||
// Group and count the data in JavaScript
|
||||
const groupedData = data.reduce((acc: any[], row: any) => {
|
||||
const tahunAngkatanValue = row.tahun_angkatan;
|
||||
const kabupaten = row.kabupaten;
|
||||
|
||||
if (!kabupaten) return acc;
|
||||
|
||||
const existingGroup = acc.find(
|
||||
(item: any) =>
|
||||
item.tahun_angkatan === tahunAngkatanValue &&
|
||||
item.kabupaten === kabupaten
|
||||
);
|
||||
|
||||
if (existingGroup) {
|
||||
existingGroup.jumlah_mahasiswa++;
|
||||
} else {
|
||||
acc.push({
|
||||
tahun_angkatan: tahunAngkatanValue,
|
||||
kabupaten: kabupaten,
|
||||
jumlah_mahasiswa: 1
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Sort the results
|
||||
const sortedData = groupedData.sort((a: any, b: any) => {
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return a.tahun_angkatan - b.tahun_angkatan;
|
||||
}
|
||||
return a.kabupaten.localeCompare(b.kabupaten);
|
||||
});
|
||||
|
||||
return NextResponse.json(sortedData);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,38 +1,65 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface AsalDaerahLulus {
|
||||
tahun_angkatan: number;
|
||||
kabupaten: string;
|
||||
jumlah_lulus_tepat_waktu: number;
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const tahunAngkatan = searchParams.get('tahunAngkatan');
|
||||
|
||||
let query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
m.kabupaten,
|
||||
COUNT(m.nim) AS jumlah_lulus_tepat_waktu
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.status_kuliah = 'Lulus'
|
||||
AND s.semester <= 8
|
||||
`;
|
||||
let query = supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('semester, mahasiswa!inner(tahun_angkatan, kabupaten, nim)')
|
||||
.eq('status_kuliah', 'Lulus')
|
||||
.lte('semester', 8);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ` AND m.tahun_angkatan = '${tahunAngkatan}'`;
|
||||
query = query.eq('mahasiswa.tahun_angkatan', parseInt(tahunAngkatan));
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY
|
||||
m.tahun_angkatan, m.kabupaten
|
||||
ORDER BY
|
||||
m.tahun_angkatan DESC, jumlah_lulus_tepat_waktu DESC
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const [rows] = await pool.query(query);
|
||||
return NextResponse.json(rows);
|
||||
if (error) {
|
||||
console.error('Error fetching asal daerah lulus data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch asal daerah lulus data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// Group by tahun_angkatan and kabupaten
|
||||
const groupedData = data.reduce((acc, item: any) => {
|
||||
const tahun_angkatan = item.mahasiswa.tahun_angkatan;
|
||||
const kabupaten = item.mahasiswa.kabupaten;
|
||||
const key = `${tahun_angkatan}-${kabupaten}`;
|
||||
acc[key] = (acc[key] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
// Convert to final format and sort
|
||||
const results: AsalDaerahLulus[] = Object.entries(groupedData)
|
||||
.map(([key, jumlah_lulus_tepat_waktu]) => {
|
||||
const [tahun_angkatan, kabupaten] = key.split('-');
|
||||
return {
|
||||
tahun_angkatan: parseInt(tahun_angkatan),
|
||||
kabupaten,
|
||||
jumlah_lulus_tepat_waktu
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// Sort by tahun_angkatan DESC, jumlah_lulus_tepat_waktu DESC
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return b.tahun_angkatan - a.tahun_angkatan;
|
||||
}
|
||||
return b.jumlah_lulus_tepat_waktu - a.jumlah_lulus_tepat_waktu;
|
||||
});
|
||||
|
||||
return NextResponse.json(results);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
@@ -7,37 +7,66 @@ export async function GET(request: Request) {
|
||||
const tahunAngkatan = searchParams.get('tahunAngkatan');
|
||||
const jenisPrestasi = searchParams.get('jenisPrestasi');
|
||||
|
||||
let query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
m.kabupaten,
|
||||
COUNT(m.nim) AS asal_daerah_mahasiswa_prestasi
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
prestasi_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.jenis_prestasi = ?
|
||||
`;
|
||||
let query = supabase
|
||||
.from('mahasiswa')
|
||||
.select(`
|
||||
tahun_angkatan,
|
||||
kabupaten,
|
||||
prestasi_mahasiswa!inner(
|
||||
jenis_prestasi
|
||||
)
|
||||
`)
|
||||
.eq('prestasi_mahasiswa.jenis_prestasi', jenisPrestasi);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ` AND m.tahun_angkatan = ?`;
|
||||
query = query.eq('tahun_angkatan', tahunAngkatan);
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY
|
||||
m.tahun_angkatan, m.kabupaten
|
||||
ORDER BY
|
||||
m.tahun_angkatan DESC, m.kabupaten
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const params = [jenisPrestasi];
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
params.push(tahunAngkatan);
|
||||
if (error) {
|
||||
console.error('Supabase error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Database error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
const [rows] = await pool.query(query, params);
|
||||
return NextResponse.json(rows);
|
||||
// Group and count the data in JavaScript
|
||||
const groupedData = data.reduce((acc: any[], row: any) => {
|
||||
const tahunAngkatanValue = row.tahun_angkatan;
|
||||
const kabupaten = row.kabupaten;
|
||||
|
||||
if (!tahunAngkatanValue || !kabupaten) return acc;
|
||||
|
||||
const existingGroup = acc.find(
|
||||
(item: any) =>
|
||||
item.tahun_angkatan === tahunAngkatanValue &&
|
||||
item.kabupaten === kabupaten
|
||||
);
|
||||
|
||||
if (existingGroup) {
|
||||
existingGroup.asal_daerah_mahasiswa_prestasi++;
|
||||
} else {
|
||||
acc.push({
|
||||
tahun_angkatan: tahunAngkatanValue,
|
||||
kabupaten: kabupaten,
|
||||
asal_daerah_mahasiswa_prestasi: 1
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Sort the results
|
||||
const sortedData = groupedData.sort((a: any, b: any) => {
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return b.tahun_angkatan - a.tahun_angkatan;
|
||||
}
|
||||
return a.kabupaten.localeCompare(b.kabupaten);
|
||||
});
|
||||
|
||||
return NextResponse.json(sortedData);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface AsalDaerahStatus extends RowDataPacket {
|
||||
interface AsalDaerahStatus {
|
||||
kabupaten: string;
|
||||
tahun_angkatan?: number;
|
||||
status_kuliah: string;
|
||||
@@ -13,39 +12,78 @@ export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const tahunAngkatan = searchParams.get('tahun_angkatan');
|
||||
const statusKuliah = searchParams.get('status_kuliah');
|
||||
|
||||
const connection = await pool.getConnection();
|
||||
|
||||
try {
|
||||
let query = `
|
||||
SELECT
|
||||
m.kabupaten,
|
||||
${tahunAngkatan && tahunAngkatan !== 'all' ? 'm.tahun_angkatan,' : ''}
|
||||
s.status_kuliah,
|
||||
COUNT(m.nim) AS total_mahasiswa
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.status_kuliah = ?
|
||||
`;
|
||||
|
||||
const params: any[] = [statusKuliah];
|
||||
try {
|
||||
let query = supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('status_kuliah, mahasiswa!inner(kabupaten, tahun_angkatan, nim)')
|
||||
.eq('status_kuliah', statusKuliah);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ` AND m.tahun_angkatan = ?`;
|
||||
params.push(tahunAngkatan);
|
||||
query = query.eq('mahasiswa.tahun_angkatan', parseInt(tahunAngkatan));
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY
|
||||
m.kabupaten${tahunAngkatan && tahunAngkatan !== 'all' ? ', m.tahun_angkatan' : ''}, s.status_kuliah
|
||||
ORDER BY
|
||||
${tahunAngkatan && tahunAngkatan !== 'all' ? 'm.tahun_angkatan ASC,' : ''} m.kabupaten, s.status_kuliah
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const [results] = await connection.query<AsalDaerahStatus[]>(query, params);
|
||||
if (error) {
|
||||
console.error('Error fetching asal daerah status:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch asal daerah status data' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Cache-Control': 'public, max-age=60, stale-while-revalidate=30',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Group by kabupaten, tahun_angkatan (optional), status_kuliah
|
||||
const groupedData = data.reduce((acc, item: any) => {
|
||||
const kabupaten = item.mahasiswa.kabupaten;
|
||||
const tahun_angkatan = tahunAngkatan && tahunAngkatan !== 'all' ? item.mahasiswa.tahun_angkatan : undefined;
|
||||
const status_kuliah = item.status_kuliah;
|
||||
const key = tahun_angkatan !== undefined
|
||||
? `${kabupaten}-${tahun_angkatan}-${status_kuliah}`
|
||||
: `${kabupaten}-${status_kuliah}`;
|
||||
acc[key] = (acc[key] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
// Convert to final format and sort
|
||||
const results: AsalDaerahStatus[] = Object.entries(groupedData)
|
||||
.map(([key, total_mahasiswa]) => {
|
||||
const parts = key.split('-');
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
const [kabupaten, tahun_angkatan, status_kuliah] = parts;
|
||||
return {
|
||||
kabupaten,
|
||||
tahun_angkatan: parseInt(tahun_angkatan),
|
||||
status_kuliah,
|
||||
total_mahasiswa
|
||||
};
|
||||
} else {
|
||||
const [kabupaten, status_kuliah] = parts;
|
||||
return {
|
||||
kabupaten,
|
||||
status_kuliah,
|
||||
total_mahasiswa
|
||||
};
|
||||
}
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// Sort by tahun_angkatan ASC (if exists), kabupaten ASC, status_kuliah ASC
|
||||
if (a.tahun_angkatan !== undefined && b.tahun_angkatan !== undefined && a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return a.tahun_angkatan - b.tahun_angkatan;
|
||||
}
|
||||
if (a.kabupaten !== b.kabupaten) {
|
||||
return a.kabupaten.localeCompare(b.kabupaten);
|
||||
}
|
||||
return a.status_kuliah.localeCompare(b.status_kuliah);
|
||||
});
|
||||
|
||||
return NextResponse.json(results, {
|
||||
headers: {
|
||||
@@ -59,16 +97,15 @@ export async function GET(request: Request) {
|
||||
console.error('Error fetching asal daerah status:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch asal daerah status data' },
|
||||
{
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Cache-Control': 'public, max-age=60, stale-while-revalidate=30',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,45 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface AsalDaerah extends RowDataPacket {
|
||||
interface AsalDaerah {
|
||||
kabupaten: string;
|
||||
jumlah: number;
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
const connection = await pool.getConnection();
|
||||
|
||||
try {
|
||||
const [results] = await connection.query<AsalDaerah[]>(`
|
||||
SELECT kabupaten, COUNT(*) AS jumlah
|
||||
FROM mahasiswa
|
||||
GROUP BY kabupaten
|
||||
ORDER BY kabupaten ASC
|
||||
`);
|
||||
const { data, error } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select('kabupaten')
|
||||
.order('kabupaten', { ascending: true });
|
||||
|
||||
if (error) {
|
||||
console.error('Error fetching asal daerah:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch asal daerah data' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Group by kabupaten and count
|
||||
const groupedData = data.reduce((acc, item) => {
|
||||
const kabupaten = item.kabupaten;
|
||||
acc[kabupaten] = (acc[kabupaten] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
// Convert to array format
|
||||
const results: AsalDaerah[] = Object.entries(groupedData).map(([kabupaten, jumlah]) => ({
|
||||
kabupaten,
|
||||
jumlah
|
||||
}));
|
||||
|
||||
return NextResponse.json(results, {
|
||||
headers: {
|
||||
@@ -39,7 +62,5 @@ export async function GET() {
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface GenderData {
|
||||
tahun_angkatan: number;
|
||||
jk: string;
|
||||
jumlah: number;
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
@@ -12,15 +18,39 @@ export async function GET(request: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
const connection = await pool.getConnection();
|
||||
|
||||
try {
|
||||
const [results] = await connection.query(`
|
||||
SELECT tahun_angkatan, jk, COUNT(*) AS jumlah
|
||||
FROM mahasiswa
|
||||
WHERE tahun_angkatan = ?
|
||||
GROUP BY jk
|
||||
`, [tahun]);
|
||||
const { data, error } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select('tahun_angkatan, jk')
|
||||
.eq('tahun_angkatan', parseInt(tahun));
|
||||
|
||||
if (error) {
|
||||
console.error('Error fetching gender per angkatan:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch gender per angkatan data' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Group by jk and count
|
||||
const groupedData = data.reduce((acc, item) => {
|
||||
acc[item.jk] = (acc[item.jk] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
// Convert to final format
|
||||
const results: GenderData[] = Object.entries(groupedData).map(([jk, jumlah]) => ({
|
||||
tahun_angkatan: parseInt(tahun),
|
||||
jk,
|
||||
jumlah
|
||||
}));
|
||||
|
||||
return NextResponse.json(results, {
|
||||
headers: {
|
||||
@@ -43,7 +73,5 @@ export async function GET(request: Request) {
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,66 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const jenisBeasiswa = searchParams.get('jenisBeasiswa');
|
||||
|
||||
const query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
COUNT(m.nim) AS total_mahasiswa_beasiswa,
|
||||
ROUND(AVG(m.ipk), 2) AS rata_rata_ipk
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
beasiswa_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.jenis_beasiswa = ?
|
||||
GROUP BY
|
||||
m.tahun_angkatan
|
||||
ORDER BY
|
||||
m.tahun_angkatan ASC
|
||||
`;
|
||||
const { data, error } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select(`
|
||||
tahun_angkatan,
|
||||
ipk,
|
||||
beasiswa_mahasiswa!inner(
|
||||
jenis_beasiswa
|
||||
)
|
||||
`)
|
||||
.eq('beasiswa_mahasiswa.jenis_beasiswa', jenisBeasiswa);
|
||||
|
||||
const [rows] = await pool.query(query, [jenisBeasiswa]);
|
||||
return NextResponse.json(rows);
|
||||
if (error) {
|
||||
console.error('Supabase error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Database error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// Group and calculate statistics in JavaScript
|
||||
const groupedData = data.reduce((acc: any[], row: any) => {
|
||||
const tahunAngkatan = row.tahun_angkatan;
|
||||
const ipk = row.ipk;
|
||||
|
||||
if (!ipk) return acc;
|
||||
|
||||
const existingGroup = acc.find(
|
||||
(item: any) => item.tahun_angkatan === tahunAngkatan
|
||||
);
|
||||
|
||||
if (existingGroup) {
|
||||
existingGroup.total_mahasiswa_beasiswa++;
|
||||
existingGroup.total_ipk += ipk;
|
||||
} else {
|
||||
acc.push({
|
||||
tahun_angkatan: tahunAngkatan,
|
||||
total_mahasiswa_beasiswa: 1,
|
||||
total_ipk: ipk
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Calculate average IPK and format the results
|
||||
const result = groupedData.map((group: any) => ({
|
||||
tahun_angkatan: group.tahun_angkatan,
|
||||
total_mahasiswa_beasiswa: group.total_mahasiswa_beasiswa,
|
||||
rata_rata_ipk: Math.round((group.total_ipk / group.total_mahasiswa_beasiswa) * 100) / 100
|
||||
}));
|
||||
|
||||
// Sort by tahun_angkatan ascending
|
||||
const sortedData = result.sort((a: any, b: any) => a.tahun_angkatan - b.tahun_angkatan);
|
||||
|
||||
return NextResponse.json(sortedData);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const tahunAngkatan = searchParams.get('tahun_angkatan');
|
||||
|
||||
if (!tahunAngkatan) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Tahun angkatan diperlukan' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const connection = await pool.getConnection();
|
||||
|
||||
try {
|
||||
const query = `
|
||||
SELECT
|
||||
jk,
|
||||
ROUND(AVG(ipk), 2) as rata_rata_ipk
|
||||
FROM mahasiswa
|
||||
WHERE tahun_angkatan = ?
|
||||
GROUP BY jk
|
||||
ORDER BY jk ASC
|
||||
`;
|
||||
|
||||
const [results] = await connection.query<RowDataPacket[]>(query, [tahunAngkatan]);
|
||||
|
||||
return NextResponse.json(results, {
|
||||
headers: {
|
||||
'Cache-Control': 'public, max-age=60, stale-while-revalidate=30',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error fetching IPK data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch IPK data' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,67 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface IpkLulusTepat {
|
||||
tahun_angkatan: number;
|
||||
rata_rata_ipk: number;
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const tahunAngkatan = searchParams.get('tahunAngkatan');
|
||||
|
||||
let query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
ROUND(AVG(m.ipk), 2) AS rata_rata_ipk
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.status_kuliah = 'Lulus'
|
||||
AND s.semester <= 8
|
||||
`;
|
||||
let query = supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('semester, mahasiswa!inner(tahun_angkatan, ipk)')
|
||||
.eq('status_kuliah', 'Lulus')
|
||||
.lte('semester', 8)
|
||||
.not('mahasiswa.ipk', 'is', null);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ` AND m.tahun_angkatan = '${tahunAngkatan}'`;
|
||||
query = query.eq('mahasiswa.tahun_angkatan', parseInt(tahunAngkatan));
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY
|
||||
m.tahun_angkatan
|
||||
ORDER BY
|
||||
m.tahun_angkatan ASC
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const [rows] = await pool.query(query);
|
||||
return NextResponse.json(rows);
|
||||
if (error) {
|
||||
console.error('Error fetching IPK lulus tepat data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch IPK lulus tepat data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// Group by tahun_angkatan and calculate average IPK
|
||||
const groupedData = data.reduce((acc, item: any) => {
|
||||
const tahun_angkatan = item.mahasiswa.tahun_angkatan;
|
||||
const ipk = item.mahasiswa.ipk;
|
||||
|
||||
if (!acc[tahun_angkatan]) {
|
||||
acc[tahun_angkatan] = {
|
||||
total_ipk: 0,
|
||||
count: 0
|
||||
};
|
||||
}
|
||||
|
||||
acc[tahun_angkatan].total_ipk += ipk;
|
||||
acc[tahun_angkatan].count += 1;
|
||||
|
||||
return acc;
|
||||
}, {} as Record<number, { total_ipk: number; count: number }>);
|
||||
|
||||
// Convert to final format and sort
|
||||
const results: IpkLulusTepat[] = Object.entries(groupedData)
|
||||
.map(([tahun_angkatan, data]) => ({
|
||||
tahun_angkatan: parseInt(tahun_angkatan),
|
||||
rata_rata_ipk: Math.round((data.total_ipk / data.count) * 100) / 100
|
||||
}))
|
||||
.sort((a, b) => {
|
||||
// Sort by tahun_angkatan ASC
|
||||
return a.tahun_angkatan - b.tahun_angkatan;
|
||||
});
|
||||
|
||||
return NextResponse.json(results);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,30 +1,66 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const jenisPrestasi = searchParams.get('jenisPrestasi');
|
||||
|
||||
const query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
COUNT(m.nim) AS total_mahasiswa_prestasi,
|
||||
ROUND(AVG(m.ipk), 2) AS rata_rata_ipk
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
prestasi_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.jenis_prestasi = ?
|
||||
GROUP BY
|
||||
m.tahun_angkatan
|
||||
ORDER BY
|
||||
m.tahun_angkatan ASC
|
||||
`;
|
||||
const { data, error } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select(`
|
||||
tahun_angkatan,
|
||||
ipk,
|
||||
prestasi_mahasiswa!inner(
|
||||
jenis_prestasi
|
||||
)
|
||||
`)
|
||||
.eq('prestasi_mahasiswa.jenis_prestasi', jenisPrestasi);
|
||||
|
||||
const [rows] = await pool.query(query, [jenisPrestasi]);
|
||||
return NextResponse.json(rows);
|
||||
if (error) {
|
||||
console.error('Supabase error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Database error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// Group and calculate statistics in JavaScript
|
||||
const groupedData = data.reduce((acc: any[], row: any) => {
|
||||
const tahunAngkatan = row.tahun_angkatan;
|
||||
const ipk = row.ipk;
|
||||
|
||||
if (!ipk) return acc;
|
||||
|
||||
const existingGroup = acc.find(
|
||||
(item: any) => item.tahun_angkatan === tahunAngkatan
|
||||
);
|
||||
|
||||
if (existingGroup) {
|
||||
existingGroup.total_mahasiswa_prestasi++;
|
||||
existingGroup.total_ipk += ipk;
|
||||
} else {
|
||||
acc.push({
|
||||
tahun_angkatan: tahunAngkatan,
|
||||
total_mahasiswa_prestasi: 1,
|
||||
total_ipk: ipk
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Calculate average IPK and format the results
|
||||
const result = groupedData.map((group: any) => ({
|
||||
tahun_angkatan: group.tahun_angkatan,
|
||||
total_mahasiswa_prestasi: group.total_mahasiswa_prestasi,
|
||||
rata_rata_ipk: Math.round((group.total_ipk / group.total_mahasiswa_prestasi) * 100) / 100
|
||||
}));
|
||||
|
||||
// Sort by tahun_angkatan ascending
|
||||
const sortedData = result.sort((a: any, b: any) => a.tahun_angkatan - b.tahun_angkatan);
|
||||
|
||||
return NextResponse.json(sortedData);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface IpkStatus {
|
||||
tahun_angkatan: number;
|
||||
@@ -22,37 +22,65 @@ export async function GET(request: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
let query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
s.status_kuliah,
|
||||
COUNT(m.nim) AS total_mahasiswa,
|
||||
ROUND(AVG(m.ipk), 2) AS rata_rata_ipk
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.status_kuliah = ?
|
||||
`;
|
||||
|
||||
const params: any[] = [statusKuliah];
|
||||
let query = supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('status_kuliah, mahasiswa!inner(tahun_angkatan, ipk, nim)')
|
||||
.eq('status_kuliah', statusKuliah)
|
||||
.not('mahasiswa.ipk', 'is', null);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ' AND m.tahun_angkatan = ?';
|
||||
params.push(tahunAngkatan);
|
||||
query = query.eq('mahasiswa.tahun_angkatan', parseInt(tahunAngkatan));
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY
|
||||
m.tahun_angkatan, s.status_kuliah
|
||||
ORDER BY
|
||||
m.tahun_angkatan DESC, s.status_kuliah
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const [rows] = await pool.query(query, params);
|
||||
if (error) {
|
||||
console.error('Error fetching IPK status data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch IPK status data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json(rows);
|
||||
// Group by tahun_angkatan and status_kuliah
|
||||
const groupedData = data.reduce((acc, item: any) => {
|
||||
const tahun_angkatan = item.mahasiswa.tahun_angkatan;
|
||||
const status_kuliah = item.status_kuliah;
|
||||
const ipk = item.mahasiswa.ipk;
|
||||
const key = `${tahun_angkatan}-${status_kuliah}`;
|
||||
|
||||
if (!acc[key]) {
|
||||
acc[key] = {
|
||||
tahun_angkatan,
|
||||
status_kuliah,
|
||||
total_mahasiswa: 0,
|
||||
total_ipk: 0
|
||||
};
|
||||
}
|
||||
|
||||
acc[key].total_mahasiswa += 1;
|
||||
acc[key].total_ipk += ipk;
|
||||
|
||||
return acc;
|
||||
}, {} as Record<string, { tahun_angkatan: number; status_kuliah: string; total_mahasiswa: number; total_ipk: number }>);
|
||||
|
||||
// Convert to final format and calculate average IPK
|
||||
const results: IpkStatus[] = Object.values(groupedData)
|
||||
.map(item => ({
|
||||
tahun_angkatan: item.tahun_angkatan,
|
||||
status_kuliah: item.status_kuliah,
|
||||
total_mahasiswa: item.total_mahasiswa,
|
||||
rata_rata_ipk: Math.round((item.total_ipk / item.total_mahasiswa) * 100) / 100
|
||||
}))
|
||||
.sort((a, b) => {
|
||||
// Sort by tahun_angkatan DESC, status_kuliah ASC
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return b.tahun_angkatan - a.tahun_angkatan;
|
||||
}
|
||||
return a.status_kuliah.localeCompare(b.status_kuliah);
|
||||
});
|
||||
|
||||
return NextResponse.json(results);
|
||||
} catch (error) {
|
||||
console.error('Error in ipk-status route:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,21 +1,49 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface IPKData extends RowDataPacket {
|
||||
interface IPKData {
|
||||
tahun_angkatan: number;
|
||||
rata_rata_ipk: number;
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
const connection = await pool.getConnection();
|
||||
|
||||
try {
|
||||
const [results] = await connection.query<IPKData[]>(`
|
||||
SELECT tahun_angkatan, ROUND(AVG(ipk), 2) AS rata_rata_ipk
|
||||
FROM mahasiswa
|
||||
GROUP BY tahun_angkatan
|
||||
`);
|
||||
const { data, error } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select('tahun_angkatan, ipk')
|
||||
.not('ipk', 'is', null);
|
||||
|
||||
if (error) {
|
||||
console.error('Error fetching IPK data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch IPK data' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Group by tahun_angkatan and calculate average IPK
|
||||
const groupedData = data.reduce((acc, item) => {
|
||||
const tahun = item.tahun_angkatan;
|
||||
if (!acc[tahun]) {
|
||||
acc[tahun] = { sum: 0, count: 0 };
|
||||
}
|
||||
acc[tahun].sum += item.ipk || 0;
|
||||
acc[tahun].count += 1;
|
||||
return acc;
|
||||
}, {} as Record<number, { sum: number; count: number }>);
|
||||
|
||||
// Convert to final format
|
||||
const results: IPKData[] = Object.entries(groupedData).map(([tahun, data]) => ({
|
||||
tahun_angkatan: parseInt(tahun),
|
||||
rata_rata_ipk: Math.round((data.sum / data.count) * 100) / 100
|
||||
}));
|
||||
|
||||
return NextResponse.json(results, {
|
||||
headers: {
|
||||
@@ -38,7 +66,5 @@ export async function GET() {
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,26 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const [rows] = await pool.query(`
|
||||
SELECT DISTINCT jenis_beasiswa
|
||||
FROM beasiswa_mahasiswa
|
||||
ORDER BY jenis_beasiswa ASC
|
||||
`);
|
||||
const { data, error } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select('jenis_beasiswa')
|
||||
.not('jenis_beasiswa', 'is', null)
|
||||
.order('jenis_beasiswa', { ascending: true });
|
||||
|
||||
return NextResponse.json(rows);
|
||||
if (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Internal Server Error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// Get unique jenis_beasiswa values
|
||||
const uniqueBeasiswa = [...new Set(data.map(item => item.jenis_beasiswa))];
|
||||
|
||||
return NextResponse.json(uniqueBeasiswa);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
@@ -7,37 +7,66 @@ export async function GET(request: Request) {
|
||||
const tahunAngkatan = searchParams.get('tahunAngkatan');
|
||||
const jenisBeasiswa = searchParams.get('jenisBeasiswa');
|
||||
|
||||
let query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
m.jenis_pendaftaran,
|
||||
COUNT(m.nim) AS jumlah_mahasiswa_beasiswa
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
beasiswa_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.jenis_beasiswa = ?
|
||||
`;
|
||||
let query = supabase
|
||||
.from('beasiswa_mahasiswa')
|
||||
.select(`
|
||||
jenis_pendaftaran,
|
||||
jenis_beasiswa,
|
||||
mahasiswa!inner(
|
||||
tahun_angkatan
|
||||
)
|
||||
`)
|
||||
.eq('jenis_beasiswa', jenisBeasiswa);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ` AND m.tahun_angkatan = ?`;
|
||||
query = query.eq('mahasiswa.tahun_angkatan', tahunAngkatan);
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY
|
||||
m.tahun_angkatan, m.jenis_pendaftaran
|
||||
ORDER BY
|
||||
m.tahun_angkatan DESC, m.jenis_pendaftaran
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const params = [jenisBeasiswa];
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
params.push(tahunAngkatan);
|
||||
if (error) {
|
||||
console.error('Supabase error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Database error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
const [rows] = await pool.query(query, params);
|
||||
return NextResponse.json(rows);
|
||||
// Group and count the data in JavaScript
|
||||
const groupedData = data.reduce((acc: any[], row: any) => {
|
||||
const tahunAngkatanValue = row.mahasiswa?.tahun_angkatan;
|
||||
const jenisPendaftaran = row.jenis_pendaftaran;
|
||||
|
||||
if (!jenisPendaftaran || !tahunAngkatanValue) return acc;
|
||||
|
||||
const existingGroup = acc.find(
|
||||
(item: any) =>
|
||||
item.tahun_angkatan === tahunAngkatanValue &&
|
||||
item.jenis_pendaftaran === jenisPendaftaran
|
||||
);
|
||||
|
||||
if (existingGroup) {
|
||||
existingGroup.jumlah_mahasiswa_beasiswa++;
|
||||
} else {
|
||||
acc.push({
|
||||
tahun_angkatan: tahunAngkatanValue,
|
||||
jenis_pendaftaran: jenisPendaftaran,
|
||||
jumlah_mahasiswa_beasiswa: 1
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Sort the results
|
||||
const sortedData = groupedData.sort((a: any, b: any) => {
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return b.tahun_angkatan - a.tahun_angkatan;
|
||||
}
|
||||
return a.jenis_pendaftaran.localeCompare(b.jenis_pendaftaran);
|
||||
});
|
||||
|
||||
return NextResponse.json(sortedData);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface JenisPendaftaranLulus {
|
||||
tahun_angkatan: number;
|
||||
@@ -12,37 +12,54 @@ export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const tahunAngkatan = searchParams.get('tahun_angkatan');
|
||||
|
||||
let query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
m.jenis_pendaftaran,
|
||||
COUNT(m.nim) AS jumlah_lulus_tepat_waktu
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.status_kuliah = 'Lulus'
|
||||
AND s.semester <= 8
|
||||
`;
|
||||
|
||||
const queryParams: any[] = [];
|
||||
let query = supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('semester, mahasiswa!inner(tahun_angkatan, jenis_pendaftaran, nim)')
|
||||
.eq('status_kuliah', 'Lulus')
|
||||
.lte('semester', 8);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ` AND m.tahun_angkatan = ?`;
|
||||
queryParams.push(parseInt(tahunAngkatan));
|
||||
query = query.eq('mahasiswa.tahun_angkatan', parseInt(tahunAngkatan));
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY
|
||||
m.tahun_angkatan, m.jenis_pendaftaran
|
||||
ORDER BY
|
||||
m.tahun_angkatan DESC, m.jenis_pendaftaran
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const [rows] = await pool.query(query, queryParams);
|
||||
if (error) {
|
||||
console.error('Error fetching jenis pendaftaran lulus data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch jenis pendaftaran lulus data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json(rows);
|
||||
// Group by tahun_angkatan and jenis_pendaftaran
|
||||
const groupedData = data.reduce((acc, item: any) => {
|
||||
const tahun_angkatan = item.mahasiswa.tahun_angkatan;
|
||||
const jenis_pendaftaran = item.mahasiswa.jenis_pendaftaran;
|
||||
const key = `${tahun_angkatan}-${jenis_pendaftaran}`;
|
||||
acc[key] = (acc[key] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
// Convert to final format and sort
|
||||
const results: JenisPendaftaranLulus[] = Object.entries(groupedData)
|
||||
.map(([key, jumlah_lulus_tepat_waktu]) => {
|
||||
const [tahun_angkatan, jenis_pendaftaran] = key.split('-');
|
||||
return {
|
||||
tahun_angkatan: parseInt(tahun_angkatan),
|
||||
jenis_pendaftaran,
|
||||
jumlah_lulus_tepat_waktu
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// Sort by tahun_angkatan DESC, jenis_pendaftaran ASC
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return b.tahun_angkatan - a.tahun_angkatan;
|
||||
}
|
||||
return a.jenis_pendaftaran.localeCompare(b.jenis_pendaftaran);
|
||||
});
|
||||
|
||||
return NextResponse.json(results);
|
||||
} catch (error) {
|
||||
console.error('Detailed error in GET /api/mahasiswa/jenis-pendaftaran-lulus:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,30 +1,65 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const jenisPrestasi = searchParams.get('jenisPrestasi');
|
||||
|
||||
const query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
m.jenis_pendaftaran,
|
||||
COUNT(m.nim) AS jenis_pendaftaran_mahasiswa_prestasi
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
prestasi_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.jenis_prestasi = ?
|
||||
GROUP BY
|
||||
m.tahun_angkatan, m.jenis_pendaftaran
|
||||
ORDER BY
|
||||
m.tahun_angkatan DESC, m.jenis_pendaftaran
|
||||
`;
|
||||
const { data, error } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select(`
|
||||
tahun_angkatan,
|
||||
jenis_pendaftaran,
|
||||
prestasi_mahasiswa!inner(
|
||||
jenis_prestasi
|
||||
)
|
||||
`)
|
||||
.eq('prestasi_mahasiswa.jenis_prestasi', jenisPrestasi);
|
||||
|
||||
const [rows] = await pool.query(query, [jenisPrestasi]);
|
||||
return NextResponse.json(rows);
|
||||
if (error) {
|
||||
console.error('Supabase error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Database error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// Group and count the data in JavaScript
|
||||
const groupedData = data.reduce((acc: any[], row: any) => {
|
||||
const tahunAngkatan = row.tahun_angkatan;
|
||||
const jenisPendaftaran = row.jenis_pendaftaran;
|
||||
|
||||
if (!tahunAngkatan || !jenisPendaftaran) return acc;
|
||||
|
||||
const existingGroup = acc.find(
|
||||
(item: any) =>
|
||||
item.tahun_angkatan === tahunAngkatan &&
|
||||
item.jenis_pendaftaran === jenisPendaftaran
|
||||
);
|
||||
|
||||
if (existingGroup) {
|
||||
existingGroup.jenis_pendaftaran_mahasiswa_prestasi++;
|
||||
} else {
|
||||
acc.push({
|
||||
tahun_angkatan: tahunAngkatan,
|
||||
jenis_pendaftaran: jenisPendaftaran,
|
||||
jenis_pendaftaran_mahasiswa_prestasi: 1
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Sort the results
|
||||
const sortedData = groupedData.sort((a: any, b: any) => {
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return b.tahun_angkatan - a.tahun_angkatan;
|
||||
}
|
||||
return a.jenis_pendaftaran.localeCompare(b.jenis_pendaftaran);
|
||||
});
|
||||
|
||||
return NextResponse.json(sortedData);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface JenisPendaftaranStatus extends RowDataPacket {
|
||||
interface JenisPendaftaranStatus {
|
||||
jenis_pendaftaran: string;
|
||||
tahun_angkatan: number;
|
||||
status_kuliah: string;
|
||||
@@ -13,39 +12,66 @@ export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const tahunAngkatan = searchParams.get('tahun_angkatan');
|
||||
const statusKuliah = searchParams.get('status_kuliah');
|
||||
|
||||
const connection = await pool.getConnection();
|
||||
|
||||
try {
|
||||
let query = `
|
||||
SELECT
|
||||
m.jenis_pendaftaran,
|
||||
m.tahun_angkatan,
|
||||
s.status_kuliah,
|
||||
COUNT(m.nim) AS total_mahasiswa
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.status_kuliah = ?
|
||||
`;
|
||||
|
||||
const params: any[] = [statusKuliah];
|
||||
try {
|
||||
let query = supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('status_kuliah, mahasiswa!inner(jenis_pendaftaran, tahun_angkatan, nim)')
|
||||
.eq('status_kuliah', statusKuliah);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ` AND m.tahun_angkatan = ?`;
|
||||
params.push(tahunAngkatan);
|
||||
query = query.eq('mahasiswa.tahun_angkatan', parseInt(tahunAngkatan));
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY
|
||||
m.jenis_pendaftaran, m.tahun_angkatan, s.status_kuliah
|
||||
ORDER BY
|
||||
m.tahun_angkatan DESC, m.jenis_pendaftaran, s.status_kuliah
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const [results] = await connection.query<JenisPendaftaranStatus[]>(query, params);
|
||||
if (error) {
|
||||
console.error('Error fetching jenis pendaftaran status:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch jenis pendaftaran status data' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Cache-Control': 'public, max-age=60, stale-while-revalidate=30',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Group by jenis_pendaftaran, tahun_angkatan, status_kuliah
|
||||
const groupedData = data.reduce((acc, item: any) => {
|
||||
const jenis_pendaftaran = item.mahasiswa.jenis_pendaftaran;
|
||||
const tahun_angkatan = item.mahasiswa.tahun_angkatan;
|
||||
const status_kuliah = item.status_kuliah;
|
||||
const key = `${jenis_pendaftaran}-${tahun_angkatan}-${status_kuliah}`;
|
||||
acc[key] = (acc[key] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
// Convert to final format and sort
|
||||
const results: JenisPendaftaranStatus[] = Object.entries(groupedData)
|
||||
.map(([key, total_mahasiswa]) => {
|
||||
const [jenis_pendaftaran, tahun_angkatan, status_kuliah] = key.split('-');
|
||||
return {
|
||||
jenis_pendaftaran,
|
||||
tahun_angkatan: parseInt(tahun_angkatan),
|
||||
status_kuliah,
|
||||
total_mahasiswa
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// Sort by tahun_angkatan DESC, jenis_pendaftaran ASC, status_kuliah ASC
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return b.tahun_angkatan - a.tahun_angkatan;
|
||||
}
|
||||
if (a.jenis_pendaftaran !== b.jenis_pendaftaran) {
|
||||
return a.jenis_pendaftaran.localeCompare(b.jenis_pendaftaran);
|
||||
}
|
||||
return a.status_kuliah.localeCompare(b.status_kuliah);
|
||||
});
|
||||
|
||||
return NextResponse.json(results, {
|
||||
headers: {
|
||||
@@ -59,16 +85,15 @@ export async function GET(request: Request) {
|
||||
console.error('Error fetching jenis pendaftaran status:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch jenis pendaftaran status data' },
|
||||
{
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Cache-Control': 'public, max-age=60, stale-while-revalidate=30',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface JenisPendaftaran extends RowDataPacket {
|
||||
interface JenisPendaftaran {
|
||||
tahun_angkatan: number;
|
||||
jenis_pendaftaran: string;
|
||||
jumlah: number;
|
||||
@@ -12,27 +11,54 @@ export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const tahunAngkatan = searchParams.get('tahun_angkatan');
|
||||
|
||||
const connection = await pool.getConnection();
|
||||
|
||||
try {
|
||||
let query = `
|
||||
SELECT tahun_angkatan, jenis_pendaftaran, COUNT(*) AS jumlah
|
||||
FROM mahasiswa
|
||||
`;
|
||||
|
||||
const params: any[] = [];
|
||||
let query = supabase
|
||||
.from('mahasiswa')
|
||||
.select('tahun_angkatan, jenis_pendaftaran');
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ` WHERE tahun_angkatan = ?`;
|
||||
params.push(tahunAngkatan);
|
||||
query = query.eq('tahun_angkatan', parseInt(tahunAngkatan));
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY tahun_angkatan, jenis_pendaftaran
|
||||
ORDER BY tahun_angkatan DESC, jenis_pendaftaran
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const [results] = await connection.query<JenisPendaftaran[]>(query, params);
|
||||
if (error) {
|
||||
console.error('Error fetching jenis pendaftaran:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch jenis pendaftaran data' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Group by tahun_angkatan and jenis_pendaftaran
|
||||
const groupedData = data.reduce((acc, item) => {
|
||||
const key = `${item.tahun_angkatan}-${item.jenis_pendaftaran}`;
|
||||
acc[key] = (acc[key] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
// Convert to final format
|
||||
const results: JenisPendaftaran[] = Object.entries(groupedData).map(([key, jumlah]) => {
|
||||
const [tahun_angkatan, jenis_pendaftaran] = key.split('-');
|
||||
return {
|
||||
tahun_angkatan: parseInt(tahun_angkatan),
|
||||
jenis_pendaftaran,
|
||||
jumlah
|
||||
};
|
||||
}).sort((a, b) => {
|
||||
// Sort by tahun_angkatan DESC, then by jenis_pendaftaran
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return b.tahun_angkatan - a.tahun_angkatan;
|
||||
}
|
||||
return a.jenis_pendaftaran.localeCompare(b.jenis_pendaftaran);
|
||||
});
|
||||
|
||||
return NextResponse.json(results, {
|
||||
headers: {
|
||||
@@ -55,7 +81,5 @@ export async function GET(request: Request) {
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,28 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const [rows] = await pool.query(`
|
||||
SELECT jenis_prestasi
|
||||
FROM prestasi_mahasiswa
|
||||
WHERE jenis_prestasi = 'Akademik' OR jenis_prestasi = 'Non-Akademik'
|
||||
GROUP BY jenis_prestasi
|
||||
ORDER BY jenis_prestasi ASC
|
||||
`);
|
||||
const { data, error } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select('jenis_prestasi')
|
||||
.in('jenis_prestasi', ['Akademik', 'Non-Akademik'])
|
||||
.order('jenis_prestasi', { ascending: true });
|
||||
|
||||
return NextResponse.json(rows);
|
||||
if (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Internal Server Error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// Get unique jenis_prestasi values
|
||||
const uniquePrestasi = [...new Set(data.map(item => item.jenis_prestasi))];
|
||||
|
||||
return NextResponse.json(uniquePrestasi);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Internal Server Error' },
|
||||
{ status: 500 }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface LulusTepatWaktu {
|
||||
tahun_angkatan: number;
|
||||
@@ -12,37 +12,56 @@ export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const tahunAngkatan = searchParams.get('tahun_angkatan');
|
||||
|
||||
let query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
m.jk,
|
||||
COUNT(m.nim) AS jumlah_lulus_tepat_waktu
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.status_kuliah = 'Lulus'
|
||||
AND s.semester <= 8
|
||||
`;
|
||||
|
||||
const params: any[] = [];
|
||||
let query = supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('semester, mahasiswa!inner(tahun_angkatan, jk, nim)')
|
||||
.eq('status_kuliah', 'Lulus')
|
||||
.lte('semester', 8);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ' AND m.tahun_angkatan = ?';
|
||||
params.push(tahunAngkatan);
|
||||
query = query.eq('mahasiswa.tahun_angkatan', parseInt(tahunAngkatan));
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY
|
||||
m.tahun_angkatan, m.jk
|
||||
ORDER BY
|
||||
m.tahun_angkatan DESC, m.jk
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const [rows] = await pool.query(query, params);
|
||||
return NextResponse.json(rows);
|
||||
if (error) {
|
||||
console.error('Error fetching lulus tepat waktu data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch lulus tepat waktu data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// Group by tahun_angkatan and jk
|
||||
const groupedData = data.reduce((acc, item: any) => {
|
||||
const tahun_angkatan = item.mahasiswa.tahun_angkatan;
|
||||
const jk = item.mahasiswa.jk;
|
||||
const key = `${tahun_angkatan}-${jk}`;
|
||||
acc[key] = (acc[key] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
// Convert to final format and sort
|
||||
const results: LulusTepatWaktu[] = Object.entries(groupedData)
|
||||
.map(([key, jumlah_lulus_tepat_waktu]) => {
|
||||
const [tahun_angkatan, jk] = key.split('-');
|
||||
return {
|
||||
tahun_angkatan: parseInt(tahun_angkatan),
|
||||
jk,
|
||||
jumlah_lulus_tepat_waktu
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// Sort by tahun_angkatan DESC, jk ASC
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return b.tahun_angkatan - a.tahun_angkatan;
|
||||
}
|
||||
return a.jk.localeCompare(b.jk);
|
||||
});
|
||||
|
||||
return NextResponse.json(results);
|
||||
} catch (error) {
|
||||
console.error('Error in lulus-tepat-waktu route:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Internal Server Error' },
|
||||
{ status: 500 }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
@@ -7,37 +7,68 @@ export async function GET(request: Request) {
|
||||
const tahunAngkatan = searchParams.get('tahunAngkatan');
|
||||
const jenisBeasiswa = searchParams.get('jenisBeasiswa');
|
||||
|
||||
let query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
s.nama_beasiswa,
|
||||
COUNT(m.nim) AS jumlah_nama_beasiswa
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
beasiswa_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.jenis_beasiswa = ?
|
||||
`;
|
||||
let query = supabase
|
||||
.from('beasiswa_mahasiswa')
|
||||
.select(`
|
||||
nama_beasiswa,
|
||||
jenis_beasiswa,
|
||||
mahasiswa!inner(
|
||||
tahun_angkatan
|
||||
)
|
||||
`)
|
||||
.eq('jenis_beasiswa', jenisBeasiswa);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ` AND m.tahun_angkatan = ?`;
|
||||
query = query.eq('mahasiswa.tahun_angkatan', tahunAngkatan);
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY
|
||||
m.tahun_angkatan, s.nama_beasiswa, s.jenis_beasiswa
|
||||
ORDER BY
|
||||
m.tahun_angkatan DESC, s.nama_beasiswa, s.jenis_beasiswa
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const params = [jenisBeasiswa];
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
params.push(tahunAngkatan);
|
||||
if (error) {
|
||||
console.error('Supabase error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Database error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
const [rows] = await pool.query(query, params);
|
||||
return NextResponse.json(rows);
|
||||
// Group and count the data in JavaScript
|
||||
const groupedData = data.reduce((acc: any[], row: any) => {
|
||||
const tahunAngkatanValue = row.mahasiswa?.tahun_angkatan;
|
||||
const namaBeasiswa = row.nama_beasiswa;
|
||||
|
||||
if (!namaBeasiswa || !tahunAngkatanValue) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
const existingGroup = acc.find(
|
||||
(item: any) =>
|
||||
item.tahun_angkatan === tahunAngkatanValue &&
|
||||
item.nama_beasiswa === namaBeasiswa
|
||||
);
|
||||
|
||||
if (existingGroup) {
|
||||
existingGroup.jumlah_nama_beasiswa++;
|
||||
} else {
|
||||
acc.push({
|
||||
tahun_angkatan: tahunAngkatanValue,
|
||||
nama_beasiswa: namaBeasiswa,
|
||||
jumlah_nama_beasiswa: 1
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Sort the results by tahun_angkatan ascending (as expected by component)
|
||||
const sortedData = groupedData.sort((a: any, b: any) => {
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return a.tahun_angkatan - b.tahun_angkatan;
|
||||
}
|
||||
return a.nama_beasiswa.localeCompare(b.nama_beasiswa);
|
||||
});
|
||||
|
||||
return NextResponse.json(sortedData);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
import supabase from '@/lib/db';
|
||||
import { cookies } from 'next/headers';
|
||||
import { jwtVerify } from 'jose';
|
||||
|
||||
interface MahasiswaProfile extends RowDataPacket {
|
||||
interface MahasiswaProfile {
|
||||
nim: string;
|
||||
nama: string;
|
||||
jk: 'Pria' | 'Wanita';
|
||||
@@ -20,7 +19,6 @@ interface MahasiswaProfile extends RowDataPacket {
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
let connection;
|
||||
try {
|
||||
// Get token from cookies
|
||||
const cookieStore = await cookies();
|
||||
@@ -41,47 +39,57 @@ export async function GET(request: Request) {
|
||||
|
||||
const nim = payload.nim as string;
|
||||
|
||||
// Get connection from pool
|
||||
connection = await pool.getConnection();
|
||||
// Get mahasiswa data
|
||||
const { data: mahasiswaData, error: mahasiswaError } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select(`
|
||||
nim,
|
||||
nama,
|
||||
jk,
|
||||
agama,
|
||||
kabupaten,
|
||||
provinsi,
|
||||
jenis_pendaftaran,
|
||||
status_beasiswa,
|
||||
tahun_angkatan,
|
||||
ipk,
|
||||
prestasi
|
||||
`)
|
||||
.eq('nim', nim)
|
||||
.single();
|
||||
|
||||
const query = `
|
||||
SELECT
|
||||
m.nim,
|
||||
m.nama,
|
||||
m.jk,
|
||||
m.agama,
|
||||
m.kabupaten,
|
||||
m.provinsi,
|
||||
m.jenis_pendaftaran,
|
||||
m.status_beasiswa,
|
||||
m.tahun_angkatan,
|
||||
m.ipk,
|
||||
m.prestasi,
|
||||
s.status_kuliah
|
||||
FROM
|
||||
mahasiswa m
|
||||
LEFT JOIN
|
||||
status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
m.nim = ?
|
||||
`;
|
||||
|
||||
const [rows] = await connection.query<MahasiswaProfile[]>(query, [nim]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
connection.release();
|
||||
if (mahasiswaError || !mahasiswaData) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Data mahasiswa tidak ditemukan' },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
connection.release();
|
||||
return NextResponse.json(rows[0]);
|
||||
// Get status_kuliah separately
|
||||
const { data: statusData, error: statusError } = await supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('status_kuliah')
|
||||
.eq('nim', nim)
|
||||
.single();
|
||||
|
||||
// Transform the data to match the expected interface
|
||||
const profile: MahasiswaProfile = {
|
||||
nim: mahasiswaData.nim,
|
||||
nama: mahasiswaData.nama,
|
||||
jk: mahasiswaData.jk,
|
||||
agama: mahasiswaData.agama,
|
||||
kabupaten: mahasiswaData.kabupaten,
|
||||
provinsi: mahasiswaData.provinsi,
|
||||
jenis_pendaftaran: mahasiswaData.jenis_pendaftaran,
|
||||
status_beasiswa: mahasiswaData.status_beasiswa,
|
||||
tahun_angkatan: mahasiswaData.tahun_angkatan,
|
||||
ipk: mahasiswaData.ipk,
|
||||
prestasi: mahasiswaData.prestasi,
|
||||
status_kuliah: statusData?.status_kuliah || ''
|
||||
};
|
||||
|
||||
return NextResponse.json(profile);
|
||||
} catch (error) {
|
||||
if (connection) {
|
||||
connection.release();
|
||||
}
|
||||
console.error('Error fetching profile data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Internal Server Error' },
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface MahasiswaStatistik extends RowDataPacket {
|
||||
interface MahasiswaStatistik {
|
||||
tahun_angkatan: number;
|
||||
total_mahasiswa: number;
|
||||
pria: number;
|
||||
@@ -23,19 +22,52 @@ export async function OPTIONS() {
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
const connection = await pool.getConnection();
|
||||
|
||||
try {
|
||||
// Query untuk mendapatkan statistik mahasiswa per tahun angkatan
|
||||
const [results] = await connection.query<MahasiswaStatistik[]>(`
|
||||
SELECT
|
||||
tahun_angkatan,
|
||||
COUNT(*) as total_mahasiswa,
|
||||
SUM(CASE WHEN jk = 'Pria' THEN 1 ELSE 0 END) as pria,
|
||||
SUM(CASE WHEN jk = 'Wanita' THEN 1 ELSE 0 END) as wanita
|
||||
FROM mahasiswa
|
||||
GROUP BY tahun_angkatan
|
||||
`);
|
||||
// Get all mahasiswa data
|
||||
const { data, error } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select('tahun_angkatan, jk');
|
||||
|
||||
if (error) {
|
||||
console.error('Error fetching mahasiswa statistik:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch mahasiswa statistik' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Group by tahun_angkatan and calculate statistics
|
||||
const groupedData = data.reduce((acc, item) => {
|
||||
const tahun = item.tahun_angkatan;
|
||||
if (!acc[tahun]) {
|
||||
acc[tahun] = {
|
||||
tahun_angkatan: tahun,
|
||||
total_mahasiswa: 0,
|
||||
pria: 0,
|
||||
wanita: 0
|
||||
};
|
||||
}
|
||||
|
||||
acc[tahun].total_mahasiswa += 1;
|
||||
if (item.jk === 'Pria') {
|
||||
acc[tahun].pria += 1;
|
||||
} else if (item.jk === 'Wanita') {
|
||||
acc[tahun].wanita += 1;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {} as Record<number, MahasiswaStatistik>);
|
||||
|
||||
// Convert to array and sort by tahun_angkatan
|
||||
const results: MahasiswaStatistik[] = Object.values(groupedData)
|
||||
.sort((a, b) => a.tahun_angkatan - b.tahun_angkatan);
|
||||
|
||||
// Menambahkan header cache dan CORS
|
||||
return NextResponse.json(results, {
|
||||
@@ -59,7 +91,5 @@ export async function GET() {
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,83 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface StatusKuliah extends RowDataPacket {
|
||||
interface StatusKuliah {
|
||||
tahun_angkatan: number;
|
||||
status_kuliah: string;
|
||||
jumlah: number;
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const tahunAngkatan = searchParams.get('tahun_angkatan');
|
||||
|
||||
const connection = await pool.getConnection();
|
||||
|
||||
try {
|
||||
let query = `
|
||||
SELECT m.tahun_angkatan, s.status_kuliah, COUNT(*) AS jumlah
|
||||
FROM mahasiswa m
|
||||
JOIN status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE s.status_kuliah IN ('Lulus', 'Cuti', 'Aktif', 'DO')
|
||||
`;
|
||||
const { searchParams } = new URL(request.url);
|
||||
const tahunAngkatan = searchParams.get('tahun_angkatan');
|
||||
|
||||
const params: any[] = [];
|
||||
let query = supabase
|
||||
.from('mahasiswa')
|
||||
.select(`
|
||||
tahun_angkatan,
|
||||
status_mahasiswa!inner(
|
||||
status_kuliah
|
||||
)
|
||||
`)
|
||||
.in('status_mahasiswa.status_kuliah', ['Lulus', 'Cuti', 'Aktif', 'DO']);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ` AND m.tahun_angkatan = ?`;
|
||||
params.push(tahunAngkatan);
|
||||
query = query.eq('tahun_angkatan', tahunAngkatan);
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY m.tahun_angkatan, s.status_kuliah
|
||||
ORDER BY m.tahun_angkatan, s.status_kuliah
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const [results] = await connection.query<StatusKuliah[]>(query, params);
|
||||
if (error) {
|
||||
console.error('Supabase error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch status kuliah data' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json(results, {
|
||||
// Group and count the data in JavaScript
|
||||
const groupedData = data.reduce((acc: any[], row: any) => {
|
||||
const tahunAngkatanValue = row.tahun_angkatan;
|
||||
const statusKuliah = row.status_mahasiswa?.status_kuliah;
|
||||
|
||||
if (!tahunAngkatanValue || !statusKuliah) return acc;
|
||||
|
||||
const existingGroup = acc.find(
|
||||
(item: any) =>
|
||||
item.tahun_angkatan === tahunAngkatanValue &&
|
||||
item.status_kuliah === statusKuliah
|
||||
);
|
||||
|
||||
if (existingGroup) {
|
||||
existingGroup.jumlah++;
|
||||
} else {
|
||||
acc.push({
|
||||
tahun_angkatan: tahunAngkatanValue,
|
||||
status_kuliah: statusKuliah,
|
||||
jumlah: 1
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Sort the results
|
||||
const sortedData = groupedData.sort((a: any, b: any) => {
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return a.tahun_angkatan - b.tahun_angkatan;
|
||||
}
|
||||
return a.status_kuliah.localeCompare(b.status_kuliah);
|
||||
});
|
||||
|
||||
return NextResponse.json(sortedData, {
|
||||
headers: {
|
||||
'Cache-Control': 'public, max-age=60, stale-while-revalidate=30',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
@@ -57,7 +98,5 @@ export async function GET(request: Request) {
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface StatusMahasiswa extends RowDataPacket {
|
||||
interface StatusMahasiswa {
|
||||
tahun_angkatan: number;
|
||||
jk: string;
|
||||
total_mahasiswa: number;
|
||||
@@ -13,41 +12,57 @@ export async function GET(request: Request) {
|
||||
const tahunAngkatan = searchParams.get('tahun_angkatan');
|
||||
const statusKuliah = searchParams.get('status_kuliah');
|
||||
|
||||
const connection = await pool.getConnection();
|
||||
|
||||
try {
|
||||
let query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
CASE
|
||||
WHEN m.jk = 'Pria' THEN 'L'
|
||||
WHEN m.jk = 'Wanita' THEN 'P'
|
||||
ELSE m.jk
|
||||
END as jk,
|
||||
COUNT(m.nim) AS total_mahasiswa
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.status_kuliah = ?
|
||||
`;
|
||||
|
||||
const params: any[] = [statusKuliah];
|
||||
let query = supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('status_kuliah, mahasiswa!inner(tahun_angkatan, jk)')
|
||||
.eq('status_kuliah', statusKuliah);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ` AND m.tahun_angkatan = ?`;
|
||||
params.push(tahunAngkatan);
|
||||
query = query.eq('mahasiswa.tahun_angkatan', parseInt(tahunAngkatan));
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY
|
||||
m.tahun_angkatan, m.jk
|
||||
ORDER BY
|
||||
m.tahun_angkatan DESC, m.jk
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const [results] = await connection.query<StatusMahasiswa[]>(query, params);
|
||||
if (error) {
|
||||
console.error('Error fetching status mahasiswa:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch status mahasiswa data' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Group by tahun_angkatan and jk
|
||||
const groupedData = data.reduce((acc, item: any) => {
|
||||
const tahun_angkatan = item.mahasiswa.tahun_angkatan;
|
||||
const jk = item.mahasiswa.jk;
|
||||
const key = `${tahun_angkatan}-${jk}`;
|
||||
acc[key] = (acc[key] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
// Convert to final format
|
||||
const results: StatusMahasiswa[] = Object.entries(groupedData).map(([key, total_mahasiswa]) => {
|
||||
const [tahun_angkatan, jk] = key.split('-');
|
||||
return {
|
||||
tahun_angkatan: parseInt(tahun_angkatan),
|
||||
jk: jk === 'Pria' ? 'L' : jk === 'Wanita' ? 'P' : jk,
|
||||
total_mahasiswa
|
||||
};
|
||||
}).sort((a, b) => {
|
||||
// Sort by tahun_angkatan DESC, then by jk
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return b.tahun_angkatan - a.tahun_angkatan;
|
||||
}
|
||||
return a.jk.localeCompare(b.jk);
|
||||
});
|
||||
|
||||
return NextResponse.json(results, {
|
||||
headers: {
|
||||
@@ -70,7 +85,5 @@ export async function GET(request: Request) {
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,47 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import db from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface StatusData {
|
||||
tahun_angkatan: number;
|
||||
status_kuliah: string;
|
||||
jumlah: number;
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const query = `
|
||||
SELECT m.tahun_angkatan, s.status_kuliah, COUNT(*) AS jumlah
|
||||
FROM mahasiswa m
|
||||
JOIN status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE s.status_kuliah IN ('Lulus', 'Cuti', 'Aktif', 'DO')
|
||||
GROUP BY m.tahun_angkatan, s.status_kuliah;
|
||||
`;
|
||||
const { data, error } = await supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('status_kuliah, mahasiswa!inner(tahun_angkatan)')
|
||||
.in('status_kuliah', ['Lulus', 'Cuti', 'Aktif', 'DO']);
|
||||
|
||||
const [rows] = await db.query(query);
|
||||
return NextResponse.json(rows);
|
||||
if (error) {
|
||||
console.error('Error fetching status data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch status data' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// Group by tahun_angkatan and status_kuliah
|
||||
const groupedData = data.reduce((acc, item: any) => {
|
||||
const tahun_angkatan = item.mahasiswa.tahun_angkatan;
|
||||
const status_kuliah = item.status_kuliah;
|
||||
const key = `${tahun_angkatan}-${status_kuliah}`;
|
||||
acc[key] = (acc[key] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
// Convert to final format
|
||||
const results: StatusData[] = Object.entries(groupedData).map(([key, jumlah]) => {
|
||||
const [tahun_angkatan, status_kuliah] = key.split('-');
|
||||
return {
|
||||
tahun_angkatan: parseInt(tahun_angkatan),
|
||||
status_kuliah,
|
||||
jumlah
|
||||
};
|
||||
});
|
||||
|
||||
return NextResponse.json(results);
|
||||
} catch (error) {
|
||||
console.error('Error fetching status data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,20 +1,38 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
export async function GET() {
|
||||
const connection = await pool.getConnection();
|
||||
|
||||
try {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const [results] = await connection.query(`
|
||||
SELECT DISTINCT tahun_angkatan
|
||||
FROM mahasiswa
|
||||
WHERE tahun_angkatan >= ?
|
||||
ORDER BY tahun_angkatan DESC
|
||||
LIMIT 7
|
||||
`, [currentYear - 6]);
|
||||
const { data, error } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select('tahun_angkatan')
|
||||
.gte('tahun_angkatan', currentYear - 10)
|
||||
.order('tahun_angkatan', { ascending: false });
|
||||
|
||||
return NextResponse.json(results, {
|
||||
if (error) {
|
||||
console.error('Error fetching tahun angkatan:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch tahun angkatan data' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Get unique tahun_angkatan values and limit to 7 most recent
|
||||
const uniqueYears = [...new Set(data.map(item => item.tahun_angkatan))]
|
||||
.sort((a, b) => b - a) // Sort descending
|
||||
.slice(0, 7); // Take only 7 most recent years
|
||||
|
||||
console.log('Available years:', uniqueYears); // Debug log
|
||||
|
||||
return NextResponse.json(uniqueYears, {
|
||||
headers: {
|
||||
'Cache-Control': 'public, max-age=60, stale-while-revalidate=30',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
@@ -35,7 +53,5 @@ export async function GET() {
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,65 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const jenisPrestasi = searchParams.get('jenisPrestasi');
|
||||
|
||||
const query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
s.tingkat,
|
||||
COUNT(m.nim) AS tingkat_mahasiswa_prestasi
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
prestasi_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.jenis_prestasi = ?
|
||||
GROUP BY
|
||||
m.tahun_angkatan, s.tingkat
|
||||
ORDER BY
|
||||
m.tahun_angkatan DESC, s.tingkat
|
||||
`;
|
||||
const { data, error } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select(`
|
||||
tahun_angkatan,
|
||||
prestasi_mahasiswa!inner(
|
||||
tingkat_prestasi,
|
||||
jenis_prestasi
|
||||
)
|
||||
`)
|
||||
.eq('prestasi_mahasiswa.jenis_prestasi', jenisPrestasi);
|
||||
|
||||
const [rows] = await pool.query(query, [jenisPrestasi]);
|
||||
return NextResponse.json(rows);
|
||||
if (error) {
|
||||
console.error('Supabase error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Database error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// Group and count the data in JavaScript
|
||||
const groupedData = data.reduce((acc: any[], row: any) => {
|
||||
const tahunAngkatan = row.tahun_angkatan;
|
||||
const tingkatPrestasi = row.prestasi_mahasiswa?.tingkat_prestasi;
|
||||
|
||||
if (!tahunAngkatan || !tingkatPrestasi) return acc;
|
||||
|
||||
const existingGroup = acc.find(
|
||||
(item: any) =>
|
||||
item.tahun_angkatan === tahunAngkatan &&
|
||||
item.tingkat_prestasi === tingkatPrestasi
|
||||
);
|
||||
|
||||
if (existingGroup) {
|
||||
existingGroup.tingkat_mahasiswa_prestasi++;
|
||||
} else {
|
||||
acc.push({
|
||||
tahun_angkatan: tahunAngkatan,
|
||||
tingkat_prestasi: tingkatPrestasi,
|
||||
tingkat_mahasiswa_prestasi: 1
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Sort the results
|
||||
const sortedData = groupedData.sort((a: any, b: any) => {
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return b.tahun_angkatan - a.tahun_angkatan;
|
||||
}
|
||||
return a.tingkat_prestasi.localeCompare(b.tingkat_prestasi);
|
||||
});
|
||||
|
||||
return NextResponse.json(sortedData);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface BeasiswaData {
|
||||
tahun_angkatan: number;
|
||||
jk: string;
|
||||
jumlah_mahasiswa_beasiswa: number;
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
@@ -7,37 +13,51 @@ export async function GET(request: Request) {
|
||||
const tahunAngkatan = searchParams.get('tahunAngkatan');
|
||||
const jenisBeasiswa = searchParams.get('jenisBeasiswa');
|
||||
|
||||
let query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
m.jk,
|
||||
COUNT(m.nim) AS jumlah_mahasiswa_beasiswa
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
beasiswa_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.jenis_beasiswa = ?
|
||||
`;
|
||||
let query = supabase
|
||||
.from('beasiswa_mahasiswa')
|
||||
.select('jenis_beasiswa, mahasiswa!inner(tahun_angkatan, jk, nim)')
|
||||
.eq('jenis_beasiswa', jenisBeasiswa);
|
||||
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
query += ` AND m.tahun_angkatan = ?`;
|
||||
query = query.eq('mahasiswa.tahun_angkatan', parseInt(tahunAngkatan));
|
||||
}
|
||||
|
||||
query += `
|
||||
GROUP BY
|
||||
m.tahun_angkatan, m.jk
|
||||
ORDER BY
|
||||
m.tahun_angkatan DESC, m.jk
|
||||
`;
|
||||
const { data, error } = await query;
|
||||
|
||||
const params = [jenisBeasiswa];
|
||||
if (tahunAngkatan && tahunAngkatan !== 'all') {
|
||||
params.push(tahunAngkatan);
|
||||
if (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Internal Server Error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
const [rows] = await pool.query(query, params);
|
||||
return NextResponse.json(rows);
|
||||
// Group by tahun_angkatan and jk
|
||||
const groupedData = data.reduce((acc, item: any) => {
|
||||
const tahun_angkatan = item.mahasiswa.tahun_angkatan;
|
||||
const jk = item.mahasiswa.jk;
|
||||
const key = `${tahun_angkatan}-${jk}`;
|
||||
acc[key] = (acc[key] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
// Convert to final format
|
||||
const results: BeasiswaData[] = Object.entries(groupedData).map(([key, jumlah_mahasiswa_beasiswa]) => {
|
||||
const [tahun_angkatan, jk] = key.split('-');
|
||||
return {
|
||||
tahun_angkatan: parseInt(tahun_angkatan),
|
||||
jk,
|
||||
jumlah_mahasiswa_beasiswa
|
||||
};
|
||||
}).sort((a, b) => {
|
||||
// Sort by tahun_angkatan DESC, then by jk
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return b.tahun_angkatan - a.tahun_angkatan;
|
||||
}
|
||||
return a.jk.localeCompare(b.jk);
|
||||
});
|
||||
|
||||
return NextResponse.json(results);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,30 +1,69 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface PrestasiData {
|
||||
tahun_angkatan: number;
|
||||
jk: string;
|
||||
jumlah_mahasiswa_prestasi: number;
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const jenisPrestasi = searchParams.get('jenisPrestasi');
|
||||
|
||||
const query = `
|
||||
SELECT
|
||||
m.tahun_angkatan,
|
||||
m.jk,
|
||||
COUNT(m.nim) AS jumlah_mahasiswa_prestasi
|
||||
FROM
|
||||
mahasiswa m
|
||||
JOIN
|
||||
prestasi_mahasiswa s ON m.nim = s.nim
|
||||
WHERE
|
||||
s.jenis_prestasi = ?
|
||||
GROUP BY
|
||||
m.tahun_angkatan, m.jk
|
||||
ORDER BY
|
||||
m.tahun_angkatan DESC, m.jk
|
||||
`;
|
||||
const { data, error } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select(`
|
||||
tahun_angkatan,
|
||||
jk,
|
||||
prestasi_mahasiswa!inner(
|
||||
jenis_prestasi
|
||||
)
|
||||
`)
|
||||
.eq('prestasi_mahasiswa.jenis_prestasi', jenisPrestasi);
|
||||
|
||||
const [rows] = await pool.query(query, [jenisPrestasi]);
|
||||
return NextResponse.json(rows);
|
||||
if (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Internal Server Error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// Group by tahun_angkatan and jk
|
||||
const groupedData = data.reduce((acc: any[], item: any) => {
|
||||
const tahunAngkatan = item.tahun_angkatan;
|
||||
const jk = item.jk;
|
||||
|
||||
if (!tahunAngkatan || !jk) return acc;
|
||||
|
||||
const existingGroup = acc.find(
|
||||
(group: any) => group.tahun_angkatan === tahunAngkatan && group.jk === jk
|
||||
);
|
||||
|
||||
if (existingGroup) {
|
||||
existingGroup.jumlah_mahasiswa_prestasi++;
|
||||
} else {
|
||||
acc.push({
|
||||
tahun_angkatan: tahunAngkatan,
|
||||
jk: jk,
|
||||
jumlah_mahasiswa_prestasi: 1
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Sort by tahun_angkatan DESC, then by jk
|
||||
const sortedData = groupedData.sort((a: any, b: any) => {
|
||||
if (a.tahun_angkatan !== b.tahun_angkatan) {
|
||||
return b.tahun_angkatan - a.tahun_angkatan;
|
||||
}
|
||||
return a.jk.localeCompare(b.jk);
|
||||
});
|
||||
|
||||
return NextResponse.json(sortedData);
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import pool from '@/lib/db';
|
||||
import { RowDataPacket } from 'mysql2';
|
||||
import supabase from '@/lib/db';
|
||||
|
||||
interface MahasiswaTotal extends RowDataPacket {
|
||||
interface MahasiswaTotal {
|
||||
total_mahasiswa: number;
|
||||
mahasiswa_aktif: number;
|
||||
total_lulus: number;
|
||||
@@ -16,6 +15,13 @@ interface MahasiswaTotal extends RowDataPacket {
|
||||
total_mahasiswa_aktif_lulus: number;
|
||||
}
|
||||
|
||||
interface IPKData {
|
||||
nim: string;
|
||||
mahasiswa: {
|
||||
ipk: number;
|
||||
};
|
||||
}
|
||||
|
||||
// Fungsi untuk menangani preflight request (OPTIONS)
|
||||
export async function OPTIONS() {
|
||||
return new NextResponse(null, {
|
||||
@@ -30,41 +36,99 @@ export async function OPTIONS() {
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
const connection = await pool.getConnection();
|
||||
|
||||
try {
|
||||
// Query gabungan untuk semua data
|
||||
const [results] = await connection.query<MahasiswaTotal[]>(`
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM mahasiswa) AS total_mahasiswa,
|
||||
(SELECT COUNT(*) FROM mahasiswa m
|
||||
JOIN status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE s.status_kuliah = 'Aktif') AS mahasiswa_aktif,
|
||||
(SELECT COUNT(*) FROM mahasiswa m
|
||||
JOIN status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE s.status_kuliah = 'Lulus') AS total_lulus,
|
||||
(SELECT COUNT(*) FROM mahasiswa m
|
||||
JOIN status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE s.status_kuliah = 'Lulus' AND m.jk = 'Pria') AS pria_lulus,
|
||||
(SELECT COUNT(*) FROM mahasiswa m
|
||||
JOIN status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE s.status_kuliah = 'Lulus' AND m.jk = 'Wanita') AS wanita_lulus,
|
||||
(SELECT COUNT(*) FROM prestasi_mahasiswa) AS total_berprestasi,
|
||||
(SELECT COUNT(*) FROM prestasi_mahasiswa WHERE jenis_prestasi = 'Akademik') AS prestasi_akademik,
|
||||
(SELECT COUNT(*) FROM prestasi_mahasiswa WHERE jenis_prestasi = 'Non-Akademik') AS prestasi_non_akademik,
|
||||
(SELECT COUNT(*) FROM mahasiswa m
|
||||
JOIN status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE s.status_kuliah IN ('Aktif', 'Lulus')) AS total_mahasiswa_aktif_lulus,
|
||||
(SELECT ROUND(AVG(m.ipk), 2) FROM mahasiswa m
|
||||
JOIN status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE s.status_kuliah = 'Aktif') AS ipk_rata_rata_aktif,
|
||||
(SELECT ROUND(AVG(m.ipk), 2) FROM mahasiswa m
|
||||
JOIN status_mahasiswa s ON m.nim = s.nim
|
||||
WHERE s.status_kuliah = 'Lulus') AS ipk_rata_rata_lulus
|
||||
`);
|
||||
// Get total mahasiswa
|
||||
const { count: totalMahasiswa } = await supabase
|
||||
.from('mahasiswa')
|
||||
.select('*', { count: 'exact', head: true });
|
||||
|
||||
// Get mahasiswa aktif
|
||||
const { count: mahasiswaAktif } = await supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('nim', { count: 'exact', head: true })
|
||||
.eq('status_kuliah', 'Aktif');
|
||||
|
||||
// Get total lulus
|
||||
const { count: totalLulus } = await supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('nim', { count: 'exact', head: true })
|
||||
.eq('status_kuliah', 'Lulus');
|
||||
|
||||
// Get pria lulus
|
||||
const { count: priaLulus } = await supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('nim, mahasiswa!inner(jk)', { count: 'exact', head: true })
|
||||
.eq('status_kuliah', 'Lulus')
|
||||
.eq('mahasiswa.jk', 'Pria');
|
||||
|
||||
// Get wanita lulus
|
||||
const { count: wanitaLulus } = await supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('nim, mahasiswa!inner(jk)', { count: 'exact', head: true })
|
||||
.eq('status_kuliah', 'Lulus')
|
||||
.eq('mahasiswa.jk', 'Wanita');
|
||||
|
||||
// Get total berprestasi
|
||||
const { count: totalBerprestasi } = await supabase
|
||||
.from('prestasi_mahasiswa')
|
||||
.select('*', { count: 'exact', head: true });
|
||||
|
||||
// Get prestasi akademik
|
||||
const { count: prestasiAkademik } = await supabase
|
||||
.from('prestasi_mahasiswa')
|
||||
.select('*', { count: 'exact', head: true })
|
||||
.eq('jenis_prestasi', 'Akademik');
|
||||
|
||||
// Get prestasi non-akademik
|
||||
const { count: prestasiNonAkademik } = await supabase
|
||||
.from('prestasi_mahasiswa')
|
||||
.select('*', { count: 'exact', head: true })
|
||||
.eq('jenis_prestasi', 'Non-Akademik');
|
||||
|
||||
// Get total mahasiswa aktif + lulus
|
||||
const { count: totalMahasiswaAktifLulus } = await supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('nim', { count: 'exact', head: true })
|
||||
.in('status_kuliah', ['Aktif', 'Lulus']);
|
||||
|
||||
// Get IPK rata-rata aktif
|
||||
const { data: ipkAktifData } = await supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('nim, mahasiswa!inner(ipk)')
|
||||
.eq('status_kuliah', 'Aktif')
|
||||
.not('mahasiswa.ipk', 'is', null);
|
||||
|
||||
const ipkRataRataAktif = ipkAktifData && ipkAktifData.length > 0
|
||||
? Math.round((ipkAktifData.reduce((sum, item: any) => sum + (item.mahasiswa.ipk || 0), 0) / ipkAktifData.length) * 100) / 100
|
||||
: 0;
|
||||
|
||||
// Get IPK rata-rata lulus
|
||||
const { data: ipkLulusData } = await supabase
|
||||
.from('status_mahasiswa')
|
||||
.select('nim, mahasiswa!inner(ipk)')
|
||||
.eq('status_kuliah', 'Lulus')
|
||||
.not('mahasiswa.ipk', 'is', null);
|
||||
|
||||
const ipkRataRataLulus = ipkLulusData && ipkLulusData.length > 0
|
||||
? Math.round((ipkLulusData.reduce((sum, item: any) => sum + (item.mahasiswa.ipk || 0), 0) / ipkLulusData.length) * 100) / 100
|
||||
: 0;
|
||||
|
||||
const results: MahasiswaTotal = {
|
||||
total_mahasiswa: totalMahasiswa || 0,
|
||||
mahasiswa_aktif: mahasiswaAktif || 0,
|
||||
total_lulus: totalLulus || 0,
|
||||
pria_lulus: priaLulus || 0,
|
||||
wanita_lulus: wanitaLulus || 0,
|
||||
total_berprestasi: totalBerprestasi || 0,
|
||||
prestasi_akademik: prestasiAkademik || 0,
|
||||
prestasi_non_akademik: prestasiNonAkademik || 0,
|
||||
ipk_rata_rata_aktif: ipkRataRataAktif,
|
||||
ipk_rata_rata_lulus: ipkRataRataLulus,
|
||||
total_mahasiswa_aktif_lulus: totalMahasiswaAktifLulus || 0,
|
||||
};
|
||||
|
||||
// Menambahkan header cache dan CORS
|
||||
return NextResponse.json(results[0], {
|
||||
return NextResponse.json(results, {
|
||||
headers: {
|
||||
'Cache-Control': 'public, max-age=60, stale-while-revalidate=30',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
@@ -85,7 +149,5 @@ export async function GET() {
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user