This commit is contained in:
Randa Firman Putra
2025-11-03 17:47:24 +07:00
parent db3db43434
commit 133ec36510
26 changed files with 3350 additions and 57 deletions

View File

@@ -0,0 +1,45 @@
import { NextRequest, NextResponse } from 'next/server';
import supabase from '@/lib/db';
// GET - Ambil data mahasiswa dengan IPK dan filter tahun angkatan untuk tabel detail
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const tahunAngkatan = searchParams.get('tahun_angkatan');
let query = supabase
.from('mahasiswa')
.select('nim, nama, ipk, tahun_angkatan')
.not('ipk', 'is', null) // Hanya ambil mahasiswa yang memiliki IPK
.order('ipk', { ascending: false }); // Urutkan berdasarkan IPK tertinggi
// Jika ada filter tahun angkatan, terapkan filter
if (tahunAngkatan && tahunAngkatan !== 'all') {
query = query.eq('tahun_angkatan', parseInt(tahunAngkatan));
}
const { data, error } = await query;
if (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ message: 'Failed to fetch data', error: error.message },
{ status: 500 }
);
}
return NextResponse.json(data || [], {
headers: {
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0',
},
});
} catch (error) {
console.error('Error in tabeldetail/ipk API:', error);
return NextResponse.json(
{ message: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,45 @@
import { NextRequest, NextResponse } from 'next/server';
import supabase from '@/lib/db';
// GET - Ambil data mahasiswa dengan jenis pendaftaran dan filter tahun angkatan untuk tabel detail
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const tahunAngkatan = searchParams.get('tahun_angkatan');
let query = supabase
.from('mahasiswa')
.select('nim, nama, jenis_pendaftaran, tahun_angkatan')
.not('jenis_pendaftaran', 'is', null) // Hanya ambil mahasiswa yang memiliki jenis pendaftaran
.order('nama'); // Urutkan berdasarkan nama
// Jika ada filter tahun angkatan, terapkan filter
if (tahunAngkatan && tahunAngkatan !== 'all') {
query = query.eq('tahun_angkatan', parseInt(tahunAngkatan));
}
const { data, error } = await query;
if (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ message: 'Failed to fetch data', error: error.message },
{ status: 500 }
);
}
return NextResponse.json(data || [], {
headers: {
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0',
},
});
} catch (error) {
console.error('Error in tabeldetail/jenis-pendaftaran API:', error);
return NextResponse.json(
{ message: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,65 @@
import { NextRequest, NextResponse } from 'next/server';
import supabase from '@/lib/db';
interface MahasiswaKelompokKeahlian {
nim: string;
nama: string;
tahun_angkatan: number;
nama_kelompok_keahlian: string;
}
// GET - Ambil data mahasiswa dengan kelompok keahlian dan filter tahun angkatan untuk tabel detail
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const tahunAngkatan = searchParams.get('tahun_angkatan');
let query = supabase
.from('mahasiswa')
.select(`
nim,
nama,
tahun_angkatan,
kelompok_keahlian!id_kelompok_keahlian(nama_kelompok)
`)
.not('id_kelompok_keahlian', 'is', null) // Hanya ambil mahasiswa yang sudah memiliki kelompok keahlian
.order('nama', { ascending: true }); // Urutkan berdasarkan nama mahasiswa
// Jika ada filter tahun angkatan, terapkan filter
if (tahunAngkatan && tahunAngkatan !== 'all') {
query = query.eq('tahun_angkatan', parseInt(tahunAngkatan));
}
const { data, error } = await query;
if (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ message: 'Failed to fetch data', error: error.message },
{ status: 500 }
);
}
// Transform data untuk meratakan field yang di-join
const transformedData: MahasiswaKelompokKeahlian[] = (data || []).map((item: any) => ({
nim: item.nim,
nama: item.nama,
tahun_angkatan: item.tahun_angkatan,
nama_kelompok_keahlian: item.kelompok_keahlian?.nama_kelompok || ''
}));
return NextResponse.json(transformedData, {
headers: {
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0',
},
});
} catch (error) {
console.error('Error in tabeldetail/kelompok-keahlian API:', error);
return NextResponse.json(
{ message: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,69 @@
import { NextRequest, NextResponse } from 'next/server';
import supabase from '@/lib/db';
interface MahasiswaKKLulusTepat {
nim: string;
nama: string;
tahun_angkatan: number;
nama_kelompok_keahlian: string;
semester: number;
}
// GET - Ambil data mahasiswa lulus tepat waktu dengan kelompok keahlian dan filter tahun angkatan untuk tabel detail
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const tahunAngkatan = searchParams.get('tahun_angkatan');
let query = supabase
.from('mahasiswa')
.select(`
nim,
nama,
tahun_angkatan,
semester,
kelompok_keahlian!inner(nama_kelompok)
`)
.eq('status_kuliah', 'Lulus') // Hanya mahasiswa yang sudah lulus
.lte('semester', 8) // Lulus tepat waktu (maksimal 8 semester)
.order('semester', { ascending: true }); // Urutkan berdasarkan semester tercepat
// Jika ada filter tahun angkatan, terapkan filter
if (tahunAngkatan && tahunAngkatan !== 'all') {
query = query.eq('tahun_angkatan', parseInt(tahunAngkatan));
}
const { data, error } = await query;
if (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ message: 'Failed to fetch data', error: error.message },
{ status: 500 }
);
}
// Transform data untuk meratakan field yang di-join
const transformedData: MahasiswaKKLulusTepat[] = (data || []).map((item: any) => ({
nim: item.nim,
nama: item.nama,
tahun_angkatan: item.tahun_angkatan,
semester: item.semester,
nama_kelompok_keahlian: item.kelompok_keahlian?.nama_kelompok || ''
}));
return NextResponse.json(transformedData, {
headers: {
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0',
},
});
} catch (error) {
console.error('Error in tabeldetail/kk-lulus-tepat API:', error);
return NextResponse.json(
{ message: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,47 @@
import { NextRequest, NextResponse } from 'next/server';
import supabase from '@/lib/db';
// GET - Ambil data mahasiswa lulus tepat waktu dengan filter tahun angkatan untuk tabel detail
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const tahunAngkatan = searchParams.get('tahun_angkatan');
let query = supabase
.from('mahasiswa')
.select('nim, nama, tahun_angkatan, ipk, semester')
.eq('status_kuliah', 'Lulus')
.lte('semester', 8) // Lulus tepat waktu maksimal 8 semester (4 tahun)
.not('ipk', 'is', null) // Hanya ambil mahasiswa yang memiliki IPK
.order('ipk', { ascending: false }); // Urutkan berdasarkan IPK tertinggi
// Jika ada filter tahun angkatan, terapkan filter
if (tahunAngkatan && tahunAngkatan !== 'all') {
query = query.eq('tahun_angkatan', parseInt(tahunAngkatan));
}
const { data, error } = await query;
if (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ message: 'Failed to fetch data', error: error.message },
{ status: 500 }
);
}
return NextResponse.json(data || [], {
headers: {
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0',
},
});
} catch (error) {
console.error('Error in tabeldetail/lulus-tepat-waktu API:', error);
return NextResponse.json(
{ message: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,69 @@
import { NextRequest, NextResponse } from 'next/server';
import supabase from '@/lib/db';
interface MahasiswaMasaStudi {
nim: string;
nama: string;
tahun_angkatan: number;
semester: number;
status_kuliah: string;
masa_studi_tahun: number;
}
// GET - Ambil data mahasiswa masa studi dengan filter tahun angkatan untuk tabel detail
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const tahunAngkatan = searchParams.get('tahun_angkatan');
let query = supabase
.from('mahasiswa')
.select('nim, nama, tahun_angkatan, semester, status_kuliah')
.eq('status_kuliah', 'Lulus') // Hanya ambil mahasiswa yang sudah lulus
.not('semester', 'is', null) // Hanya ambil mahasiswa yang memiliki data semester
.order('semester', { ascending: false }); // Urutkan berdasarkan semester tertinggi
// Jika ada filter tahun angkatan, terapkan filter
if (tahunAngkatan && tahunAngkatan !== 'all') {
query = query.eq('tahun_angkatan', parseInt(tahunAngkatan));
}
const { data, error } = await query;
if (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ message: 'Failed to fetch data', error: error.message },
{ status: 500 }
);
}
// Transform data untuk menghitung masa studi dalam tahun
const transformedData: MahasiswaMasaStudi[] = (data || []).map((item: any) => ({
nim: item.nim,
nama: item.nama,
tahun_angkatan: item.tahun_angkatan,
semester: item.semester,
status_kuliah: item.status_kuliah,
// Hitung masa studi dalam tahun berdasarkan semester (semester / 2)
masa_studi_tahun: Math.round(((item.semester || 0) / 2) * 10) / 10
}));
// Urutkan berdasarkan masa studi terlama
transformedData.sort((a, b) => b.masa_studi_tahun - a.masa_studi_tahun);
return NextResponse.json(transformedData, {
headers: {
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0',
},
});
} catch (error) {
console.error('Error in tabeldetail/masa-studi API:', error);
return NextResponse.json(
{ message: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,44 @@
import { NextRequest, NextResponse } from 'next/server';
import supabase from '@/lib/db';
// GET - Ambil data mahasiswa dengan filter tahun angkatan untuk tabel detail
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const tahunAngkatan = searchParams.get('tahun_angkatan');
let query = supabase
.from('mahasiswa')
.select('nim, nama, status_kuliah, tahun_angkatan')
.order('nama');
// Jika ada filter tahun angkatan, terapkan filter
if (tahunAngkatan && tahunAngkatan !== 'all') {
query = query.eq('tahun_angkatan', parseInt(tahunAngkatan));
}
const { data, error } = await query;
if (error) {
console.error('Error fetching data:', error);
return NextResponse.json(
{ message: 'Failed to fetch data', error: error.message },
{ status: 500 }
);
}
return NextResponse.json(data || [], {
headers: {
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0',
},
});
} catch (error) {
console.error('Error in tabeldetail API:', error);
return NextResponse.json(
{ message: 'Internal Server Error' },
{ status: 500 }
);
}
}

View File

@@ -4,6 +4,7 @@ import { useState } from "react";
import JenisPendaftaranChart from "@/components/charts/JenisPendaftaranChart";
import JenisPendaftaranPerAngkatanChart from "@/components/charts/JenisPendaftaranPerAngkatanChart";
import FilterTahunAngkatan from "@/components/FilterTahunAngkatan";
import TabelJenisPendaftaranMahasiswa from "@/components/chartstable/tabeljenisPendaftaranmahasiswa";
export default function JenisPendaftaranDetailPage() {
const [selectedYear, setSelectedYear] = useState<string>("all");
@@ -36,6 +37,9 @@ export default function JenisPendaftaranDetailPage() {
)}
</div>
{/* Tabel Section */}
<TabelJenisPendaftaranMahasiswa selectedYear={selectedYear} />
{/* Information Section */}
<div className="bg-white dark:bg-slate-900 rounded-lg shadow-sm p-6">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4">

View File

@@ -1,11 +1,22 @@
'use client';
import { useState } from "react";
import KelompokKeahlianLulusTepatPieChart from "@/components/chartsDashboard/kkdashboardtepatpiechart";
import FilterTahunAngkatan from "@/components/FilterTahunAngkatan";
import TabelKKLulusTepatMahasiswa from "@/components/chartstable/tabelkklulustepatmahasiswa";
export default function KelompokKeahlianLulusTepatDetailPage() {
const [selectedYear, setSelectedYear] = useState<string>("all");
return (
<div className="min-h-screen bg-gray-50 dark:bg-[var(--background)] p-4">
<div className="container mx-auto max-w-7xl space-y-2">
{/* Filter Section */}
<FilterTahunAngkatan
selectedYear={selectedYear}
onYearChange={setSelectedYear}
/>
{/* Chart Section - Enhanced Size */}
<div className="grid grid-cols-1 lg:grid-cols-1 gap-6">
{/* Kelompok Keahlian Lulus Tepat Chart dengan ukuran lebih besar */}
@@ -17,6 +28,9 @@ export default function KelompokKeahlianLulusTepatDetailPage() {
</div>
</div>
{/* Tabel Section */}
<TabelKKLulusTepatMahasiswa selectedYear={selectedYear} />
{/* Information Section */}
<div className="bg-white dark:bg-slate-900 rounded-lg shadow-sm p-6">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4">

View File

@@ -4,6 +4,7 @@ import { useState } from "react";
import KelompokKeahlianStatusChart from "@/components/chartsDashboard/kkdashboardchart";
import KelompokKeahlianPieChartPerAngkatan from "@/components/chartsDashboard/kkdashboardpiechartperangkatan";
import FilterTahunAngkatan from "@/components/FilterTahunAngkatan";
import TabelKelompokKeahlianMahasiswa from "@/components/chartstable/tabelkelompokkeahliamahasiswa";
export default function KelompokKeahlianDetailPage() {
const [selectedYear, setSelectedYear] = useState<string>("all");
@@ -37,6 +38,9 @@ export default function KelompokKeahlianDetailPage() {
)}
</div>
{/* Tabel Section */}
<TabelKelompokKeahlianMahasiswa selectedYear={selectedYear} />
{/* Information Section */}
<div className="bg-white dark:bg-slate-900 rounded-lg shadow-sm p-6">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4">

View File

@@ -1,23 +1,37 @@
'use client';
import { useState } from "react";
import LulusTepatWaktuChart from "@/components/charts/LulusTepatWaktuChart";
import FilterTahunAngkatan from "@/components/FilterTahunAngkatan";
import TabelLulusTepatWaktuMahasiswa from "@/components/chartstable/tabellulustepatwaktumahasiswa";
export default function LulusTepatWaktuDetailPage() {
const [selectedYear, setSelectedYear] = useState<string>("all");
return (
<div className="min-h-screen bg-gray-50 dark:bg-[var(--background)] p-4">
<div className="container mx-auto max-w-7xl space-y-2">
{/* Filter Section */}
<FilterTahunAngkatan
selectedYear={selectedYear}
onYearChange={setSelectedYear}
/>
{/* Chart Section - Enhanced Size */}
<div className="grid grid-cols-1 lg:grid-cols-1 gap-6">
{/* Lulus Tepat Waktu Chart dengan ukuran lebih besar */}
<div className="lg:col-span-2">
<LulusTepatWaktuChart
selectedYear="all"
selectedYear={selectedYear}
height="h-[400px] sm:h-[400px] lg:h-[400px]"
showDetailButton={false}
/>
</div>
</div>
{/* Tabel Section */}
<TabelLulusTepatWaktuMahasiswa selectedYear={selectedYear} />
{/* Information Section */}
<div className="bg-white dark:bg-slate-900 rounded-lg shadow-sm p-6">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4">

View File

@@ -1,23 +1,37 @@
'use client';
import { useState } from "react";
import MasaStudiLulusChart from "@/components/chartsDashboard/masastudiluluschart";
import FilterTahunAngkatan from "@/components/FilterTahunAngkatan";
import TabelMasaStudiMahasiswa from "@/components/chartstable/tabelmasastudimahasiswa";
export default function MasaStudiLulusDetailPage() {
const [selectedYear, setSelectedYear] = useState<string>("all");
return (
<div className="min-h-screen bg-gray-50 dark:bg-[var(--background)] p-4">
<div className="container mx-auto max-w-7xl space-y-2">
{/* Filter Section */}
<FilterTahunAngkatan
selectedYear={selectedYear}
onYearChange={setSelectedYear}
/>
{/* Chart Section - Enhanced Size */}
<div className="grid grid-cols-1 lg:grid-cols-1 gap-6">
{/* Masa Studi Lulus Chart dengan ukuran lebih besar */}
<div className="lg:col-span-2">
<MasaStudiLulusChart
selectedYear="all"
selectedYear={selectedYear}
height="h-[400px] sm:h-[400px] lg:h-[400px]"
showDetailButton={false}
/>
</div>
</div>
{/* Tabel Section */}
<TabelMasaStudiMahasiswa selectedYear={selectedYear} />
{/* Information Section */}
<div className="bg-white dark:bg-slate-900 rounded-lg shadow-sm p-6">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4">

View File

@@ -1,11 +1,22 @@
'use client';
import { useState } from "react";
import IPKChart from "@/components/charts/IPKChart";
import FilterTahunAngkatan from "@/components/FilterTahunAngkatan";
import TabelIPKMahasiswa from "@/components/chartstable/tabelipkmahasiswa";
export default function RataRataIPKDetailPage() {
const [selectedYear, setSelectedYear] = useState<string>("all");
return (
<div className="min-h-screen bg-gray-50 dark:bg-[var(--background)] p-4">
<div className="container mx-auto max-w-7xl space-y-2">
{/* Filter Section */}
<FilterTahunAngkatan
selectedYear={selectedYear}
onYearChange={setSelectedYear}
/>
{/* Chart Section - Enhanced Size */}
<div className="grid grid-cols-1 lg:grid-cols-1 gap-6">
{/* IPK Chart dengan ukuran lebih besar */}
@@ -17,6 +28,9 @@ export default function RataRataIPKDetailPage() {
</div>
</div>
{/* Tabel Section */}
<TabelIPKMahasiswa selectedYear={selectedYear} />
{/* Information Section */}
<div className="bg-white dark:bg-slate-900 rounded-lg shadow-sm p-6">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4">

View File

@@ -4,6 +4,7 @@ import { useState } from "react";
import StatusMahasiswaChart from "@/components/charts/StatusMahasiswaChart";
import StatusMahasiswaPieChartPerangkatan from "@/components/chartsDashboard/StatusMahasiswaPieChartPerangkatan";
import FilterTahunAngkatan from "@/components/FilterTahunAngkatan";
import TabelStatusMahasiswa from "@/components/chartstable/tabelstatusmahasiswa";
export default function StatusMahasiswaDetailPage() {
const [selectedYear, setSelectedYear] = useState<string>("all");
@@ -38,6 +39,9 @@ export default function StatusMahasiswaDetailPage() {
)}
</div>
{/* Tabel Section */}
<TabelStatusMahasiswa selectedYear={selectedYear} />
{/* Information Section */}
<div className="bg-white dark:bg-slate-900 rounded-lg shadow-sm p-6">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4">