First commit

This commit is contained in:
Randa Firman Putra
2025-06-18 22:03:32 +07:00
parent 852121be46
commit e028039ee2
123 changed files with 17506 additions and 144 deletions

View File

@@ -0,0 +1,58 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
import { RowDataPacket } from 'mysql2';
interface AsalDaerah extends RowDataPacket {
kabupaten: string;
jumlah: number;
}
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 kabupaten, COUNT(*) AS jumlah
FROM mahasiswa
WHERE tahun_angkatan = ?
GROUP BY kabupaten
ORDER BY jumlah DESC, kabupaten ASC
`;
const [results] = await connection.query<AsalDaerah[]>(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 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',
},
}
);
} finally {
connection.release();
}
}

View File

@@ -0,0 +1,48 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
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 = ?
`;
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ` AND m.tahun_angkatan = ?`;
}
query += `
GROUP BY
m.kabupaten, m.tahun_angkatan
ORDER BY
m.tahun_angkatan ASC, m.kabupaten
`;
const params = [jenisBeasiswa];
if (tahunAngkatan && tahunAngkatan !== 'all') {
params.push(tahunAngkatan);
}
const [rows] = await pool.query(query, params);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,43 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
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
`;
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ` AND m.tahun_angkatan = '${tahunAngkatan}'`;
}
query += `
GROUP BY
m.tahun_angkatan, m.kabupaten
ORDER BY
m.tahun_angkatan DESC, jumlah_lulus_tepat_waktu DESC
`;
const [rows] = await pool.query(query);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,48 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
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 = ?
`;
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ` AND m.tahun_angkatan = ?`;
}
query += `
GROUP BY
m.tahun_angkatan, m.kabupaten
ORDER BY
m.tahun_angkatan DESC, m.kabupaten
`;
const params = [jenisPrestasi];
if (tahunAngkatan && tahunAngkatan !== 'all') {
params.push(tahunAngkatan);
}
const [rows] = await pool.query(query, params);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,74 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
import { RowDataPacket } from 'mysql2';
interface AsalDaerahStatus extends RowDataPacket {
kabupaten: string;
tahun_angkatan?: number;
status_kuliah: string;
total_mahasiswa: number;
}
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];
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ` AND m.tahun_angkatan = ?`;
params.push(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 [results] = await connection.query<AsalDaerahStatus[]>(query, params);
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 asal daerah status:', error);
return NextResponse.json(
{ error: 'Failed to fetch asal daerah status data' },
{
status: 500,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
}
);
} finally {
connection.release();
}
}

View File

@@ -0,0 +1,45 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
import { RowDataPacket } from 'mysql2';
interface AsalDaerah extends RowDataPacket {
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
`);
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 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',
},
}
);
} finally {
connection.release();
}
}

View File

@@ -0,0 +1,49 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const tahun = searchParams.get('tahun');
if (!tahun) {
return NextResponse.json(
{ error: 'Tahun angkatan is required' },
{ status: 400 }
);
}
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]);
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 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',
},
}
);
} finally {
connection.release();
}
}

View File

@@ -0,0 +1,35 @@
import { NextResponse } from 'next/server';
import pool 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 [rows] = await pool.query(query, [jenisBeasiswa]);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,55 @@
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();
}
}

View File

@@ -0,0 +1,42 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
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
`;
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ` AND m.tahun_angkatan = '${tahunAngkatan}'`;
}
query += `
GROUP BY
m.tahun_angkatan
ORDER BY
m.tahun_angkatan ASC
`;
const [rows] = await pool.query(query);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,35 @@
import { NextResponse } from 'next/server';
import pool 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 [rows] = await pool.query(query, [jenisPrestasi]);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,63 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
interface IpkStatus {
tahun_angkatan: number;
status_kuliah: string;
total_mahasiswa: number;
rata_rata_ipk: number;
}
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const tahunAngkatan = searchParams.get('tahun_angkatan');
const statusKuliah = searchParams.get('status_kuliah');
if (!statusKuliah) {
console.error('Missing required parameter: status_kuliah');
return NextResponse.json(
{ error: 'Missing required parameter: status_kuliah' },
{ status: 400 }
);
}
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];
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ' AND m.tahun_angkatan = ?';
params.push(tahunAngkatan);
}
query += `
GROUP BY
m.tahun_angkatan, s.status_kuliah
ORDER BY
m.tahun_angkatan DESC, s.status_kuliah
`;
const [rows] = await pool.query(query, params);
return NextResponse.json(rows);
} catch (error) {
console.error('Error in ipk-status route:', error);
return NextResponse.json(
{ error: 'Internal Server Error', details: error instanceof Error ? error.message : 'Unknown error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,44 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
import { RowDataPacket } from 'mysql2';
interface IPKData extends RowDataPacket {
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
`);
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();
}
}

View File

@@ -0,0 +1,20 @@
import { NextResponse } from 'next/server';
import pool 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
`);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,48 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
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 = ?
`;
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ` AND m.tahun_angkatan = ?`;
}
query += `
GROUP BY
m.tahun_angkatan, m.jenis_pendaftaran
ORDER BY
m.tahun_angkatan DESC, m.jenis_pendaftaran
`;
const params = [jenisBeasiswa];
if (tahunAngkatan && tahunAngkatan !== 'all') {
params.push(tahunAngkatan);
}
const [rows] = await pool.query(query, params);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,53 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
interface JenisPendaftaranLulus {
tahun_angkatan: number;
jenis_pendaftaran: string;
jumlah_lulus_tepat_waktu: number;
}
export async function GET(request: Request) {
try {
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[] = [];
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ` AND m.tahun_angkatan = ?`;
queryParams.push(parseInt(tahunAngkatan));
}
query += `
GROUP BY
m.tahun_angkatan, m.jenis_pendaftaran
ORDER BY
m.tahun_angkatan DESC, m.jenis_pendaftaran
`;
const [rows] = await pool.query(query, queryParams);
return NextResponse.json(rows);
} catch (error) {
console.error('Detailed error in GET /api/mahasiswa/jenis-pendaftaran-lulus:', error);
return NextResponse.json(
{ error: 'Internal Server Error', details: error instanceof Error ? error.message : 'Unknown error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,35 @@
import { NextResponse } from 'next/server';
import pool 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 [rows] = await pool.query(query, [jenisPrestasi]);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,74 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
import { RowDataPacket } from 'mysql2';
interface JenisPendaftaranStatus extends RowDataPacket {
jenis_pendaftaran: string;
tahun_angkatan: number;
status_kuliah: string;
total_mahasiswa: number;
}
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];
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ` AND m.tahun_angkatan = ?`;
params.push(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 [results] = await connection.query<JenisPendaftaranStatus[]>(query, params);
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 jenis pendaftaran status:', error);
return NextResponse.json(
{ error: 'Failed to fetch jenis pendaftaran status data' },
{
status: 500,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
}
);
} finally {
connection.release();
}
}

View File

@@ -0,0 +1,61 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
import { RowDataPacket } from 'mysql2';
interface JenisPendaftaran extends RowDataPacket {
tahun_angkatan: number;
jenis_pendaftaran: 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 tahun_angkatan, jenis_pendaftaran, COUNT(*) AS jumlah
FROM mahasiswa
`;
const params: any[] = [];
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ` WHERE tahun_angkatan = ?`;
params.push(tahunAngkatan);
}
query += `
GROUP BY tahun_angkatan, jenis_pendaftaran
ORDER BY tahun_angkatan DESC, jenis_pendaftaran
`;
const [results] = await connection.query<JenisPendaftaran[]>(query, params);
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 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',
},
}
);
} finally {
connection.release();
}
}

View File

@@ -0,0 +1,21 @@
import { NextResponse } from 'next/server';
import pool 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
`);
return NextResponse.json(rows);
} catch (error) {
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,51 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
interface LulusTepatWaktu {
tahun_angkatan: number;
jk: string;
jumlah_lulus_tepat_waktu: number;
}
export async function GET(request: Request) {
try {
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[] = [];
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ' AND m.tahun_angkatan = ?';
params.push(tahunAngkatan);
}
query += `
GROUP BY
m.tahun_angkatan, m.jk
ORDER BY
m.tahun_angkatan DESC, m.jk
`;
const [rows] = await pool.query(query, params);
return NextResponse.json(rows);
} catch (error) {
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,48 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
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 = ?
`;
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ` AND m.tahun_angkatan = ?`;
}
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 params = [jenisBeasiswa];
if (tahunAngkatan && tahunAngkatan !== 'all') {
params.push(tahunAngkatan);
}
const [rows] = await pool.query(query, params);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,91 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
import { RowDataPacket } from 'mysql2';
import { cookies } from 'next/headers';
import { jwtVerify } from 'jose';
interface MahasiswaProfile extends RowDataPacket {
nim: string;
nama: string;
jk: 'Pria' | 'Wanita';
agama: string;
kabupaten: string;
provinsi: string;
jenis_pendaftaran: string;
status_beasiswa: 'YA' | 'TIDAK';
tahun_angkatan: string;
ipk: number | null;
prestasi: 'YA' | 'TIDAK';
status_kuliah: string;
}
export async function GET(request: Request) {
let connection;
try {
// Get token from cookies
const cookieStore = await cookies();
const token = cookieStore.get('token')?.value;
if (!token) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
}
// Verify JWT token
const { payload } = await jwtVerify(
token,
new TextEncoder().encode(process.env.JWT_SECRET || 'your-secret-key')
);
const nim = payload.nim as string;
// Get connection from pool
connection = await pool.getConnection();
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();
return NextResponse.json(
{ error: 'Data mahasiswa tidak ditemukan' },
{ status: 404 }
);
}
connection.release();
return NextResponse.json(rows[0]);
} catch (error) {
if (connection) {
connection.release();
}
console.error('Error fetching profile data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,65 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
import { RowDataPacket } from 'mysql2';
interface MahasiswaStatistik extends RowDataPacket {
tahun_angkatan: number;
total_mahasiswa: number;
pria: number;
wanita: number;
}
// Fungsi untuk menangani preflight request (OPTIONS)
export async function OPTIONS() {
return new NextResponse(null, {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400', // 24 jam
},
});
}
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
`);
// Menambahkan header cache dan CORS
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 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',
},
}
);
} finally {
connection.release();
}
}

View File

@@ -0,0 +1,63 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
import { RowDataPacket } from 'mysql2';
interface StatusKuliah extends RowDataPacket {
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 params: any[] = [];
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ` AND m.tahun_angkatan = ?`;
params.push(tahunAngkatan);
}
query += `
GROUP BY m.tahun_angkatan, s.status_kuliah
ORDER BY m.tahun_angkatan, s.status_kuliah
`;
const [results] = await connection.query<StatusKuliah[]>(query, params);
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 status kuliah:', 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',
},
}
);
} finally {
connection.release();
}
}

View File

@@ -0,0 +1,76 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
import { RowDataPacket } from 'mysql2';
interface StatusMahasiswa extends RowDataPacket {
tahun_angkatan: number;
jk: string;
total_mahasiswa: number;
}
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.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];
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ` AND m.tahun_angkatan = ?`;
params.push(tahunAngkatan);
}
query += `
GROUP BY
m.tahun_angkatan, m.jk
ORDER BY
m.tahun_angkatan DESC, m.jk
`;
const [results] = await connection.query<StatusMahasiswa[]>(query, params);
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 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',
},
}
);
} finally {
connection.release();
}
}

View File

@@ -0,0 +1,23 @@
import { NextResponse } from 'next/server';
import db from '@/lib/db';
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 [rows] = await db.query(query);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching status data:', error);
return NextResponse.json(
{ error: 'Failed to fetch status data' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,41 @@
import { NextResponse } from 'next/server';
import pool 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]);
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 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',
},
}
);
} finally {
connection.release();
}
}

View File

@@ -0,0 +1,35 @@
import { NextResponse } from 'next/server';
import pool 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 [rows] = await pool.query(query, [jenisPrestasi]);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,48 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
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 = ?
`;
if (tahunAngkatan && tahunAngkatan !== 'all') {
query += ` AND m.tahun_angkatan = ?`;
}
query += `
GROUP BY
m.tahun_angkatan, m.jk
ORDER BY
m.tahun_angkatan DESC, m.jk
`;
const params = [jenisBeasiswa];
if (tahunAngkatan && tahunAngkatan !== 'all') {
params.push(tahunAngkatan);
}
const [rows] = await pool.query(query, params);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,35 @@
import { NextResponse } from 'next/server';
import pool 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.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 [rows] = await pool.query(query, [jenisPrestasi]);
return NextResponse.json(rows);
} catch (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,91 @@
import { NextResponse } from 'next/server';
import pool from '@/lib/db';
import { RowDataPacket } from 'mysql2';
interface MahasiswaTotal extends RowDataPacket {
total_mahasiswa: number;
mahasiswa_aktif: number;
total_lulus: number;
pria_lulus: number;
wanita_lulus: number;
total_berprestasi: number;
prestasi_akademik: number;
prestasi_non_akademik: number;
ipk_rata_rata_aktif: number;
ipk_rata_rata_lulus: number;
total_mahasiswa_aktif_lulus: number;
}
// Fungsi untuk menangani preflight request (OPTIONS)
export async function OPTIONS() {
return new NextResponse(null, {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400', // 24 jam
},
});
}
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
`);
// Menambahkan header cache dan CORS
return NextResponse.json(results[0], {
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 total mahasiswa:', error);
return NextResponse.json(
{ error: 'Failed to fetch total mahasiswa' },
{
status: 500,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
}
);
} finally {
connection.release();
}
}