Files
portaldata/app/dashboard/page.tsx
Randa Firman Putra d1bd2d055b Bisa yuk
2025-09-20 16:33:11 +07:00

296 lines
12 KiB
TypeScript

'use client';
import { useState, useEffect } from "react";
import StatistikMahasiswaChart from "@/components/charts/StatistikMahasiswaChart";
import StatistikPerAngkatanChart from "@/components/charts/StatistikPerAngkatanChart";
import JenisPendaftaranChart from "@/components/charts/JenisPendaftaranChart";
import AsalDaerahChart from "@/components/charts/AsalDaerahChart";
import IPKChart from "@/components/charts/IPKChart";
import FilterTahunAngkatan from "@/components/FilterTahunAngkatan";
import JenisPendaftaranPerAngkatanChart from "@/components/charts/JenisPendaftaranPerAngkatanChart";
import AsalDaerahPerAngkatanChart from "@/components/charts/AsalDaerahPerAngkatanChart";
import StatusMahasiswaChart from "@/components/charts/StatusMahasiswaChart";
import KelompokKeahlianStatusChart from "@/components/chartsDashboard/kkdashboardchart";
import KelompokKeahlianLulusTepatPieChart from "@/components/chartsDashboard/kkdashboardtepatpiechart";
import KelompokKeahlianPieChartPerAngkatan from "@/components/chartsDashboard/kkdashboardpiechartperangkatan";
import StatusMahasiswaPieChartPerangkatan from "@/components/chartsDashboard/StatusMahasiswaPieChartPerangkatan";
import MasaStudiLulusChart from "@/components/chartsDashboard/masastudiluluschart";
import NamaBeasiswaChart from "@/components/chartsDashboard/NamaBeasiswaDashChart";
import NamaBeasiswaDashPieChartPerangkatan from "@/components/chartsDashboard/NamaBeasiswaDashPieChartPerangkatan";
import TingkatPrestasiChart from "@/components/chartsDashboard/TingkatPrestasiDashChart";
import ProvinsiMahasiswaChart from "@/components/chartsDashboard/ProvinsiMahasiswaPieChart";
import TingkatPrestasiPieChartDash from "@/components/chartsDashboard/TingkatPrestasiPieChartDash";
import LulusTepatWaktuChart from "@/components/charts/LulusTepatWaktuChart";
import BimbinganDosenChart from "@/components/charts/BimbinganDosenChart";
import BimbinganDosenPerAngkatanChart from "@/components/charts/BimbinganDosenPerAngkatanChart";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { ChevronDown, Navigation, ArrowUp } from "lucide-react";
import DashboardStats, { DashboardStatsSkeleton } from "@/components/dashboard/DashboardStats";
interface MahasiswaTotal {
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;
total_mahasiswa_aktif_lulus: number;
total_mahasiswa_beasiswa: number;
total_mahasiswa_beasiswa_pemerintah: number;
total_mahasiswa_beasiswa_non_pemerintah: number;
}
export default function TotalMahasiswaPage() {
const [selectedYear, setSelectedYear] = useState<string>("all");
const [dropdownOpen, setDropdownOpen] = useState(false);
const [showBackToTop, setShowBackToTop] = useState(false);
const [mahasiswaData, setMahasiswaData] = useState<MahasiswaTotal | null>(null);
const [loading, setLoading] = useState(true);
// Fetch mahasiswa data based on selected year
useEffect(() => {
const fetchMahasiswaData = async () => {
setLoading(true);
try {
const url = selectedYear === "all"
? '/api/mahasiswa/total'
: `/api/mahasiswa/total?tahun_angkatan=${selectedYear}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error('Failed to fetch data');
}
const data = await response.json();
setMahasiswaData(data);
} catch (error) {
console.error('Error fetching mahasiswa data:', error);
setMahasiswaData(null);
} finally {
setLoading(false);
}
};
fetchMahasiswaData();
}, [selectedYear]);
// Handle scroll event to show/hide back to top button
useEffect(() => {
const handleScroll = () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
setShowBackToTop(scrollTop > 300); // Show button after scrolling 300px
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
// Function to scroll to top smoothly
const scrollToTop = () => {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
};
// Function to scroll to section smoothly
const scrollToSection = (sectionId: string) => {
// Close dropdown first
setDropdownOpen(false);
// Use requestAnimationFrame to ensure smooth operation
requestAnimationFrame(() => {
setTimeout(() => {
const element = document.getElementById(sectionId);
if (element) {
element.scrollIntoView({
behavior: 'smooth',
block: 'start',
inline: 'nearest'
});
}
}, 200);
});
};
// Navigation menu items for all data
const allDataNavItems = [
{ id: 'overview', label: 'Jumlah & Status Mahasiswa' },
{ id: 'academic', label: 'IPK & Jenis Pendaftaran' },
{ id: 'study-duration', label: 'Kelulusan Tepat Waktu & Masa Studi' },
{ id: 'expertise', label: 'Kelompok Keahlian' },
{ id: 'scholarship', label: 'Beasiswa & Prestasi' },
{ id: 'demographics', label: 'Asal Kabupaten & Provinsi' },
{ id: 'bimbingan-dosen', label: 'Bimbingan Dosen' }
];
// Navigation menu items for per year data
const perYearNavItems = [
{ id: 'overview-year', label: 'Jumlah & Status per Angkatan' },
{ id: 'status-year', label: 'Jenis Pendaftaran & Kelompok Keahlian' },
{ id: 'achievement-year', label: 'Beasiswa & Prestasi per Angkatan' },
{ id: 'demographics-year', label: 'Asal Kabupaten per Angkatan' },
{ id: 'bimbingan-dosen-year', label: 'Bimbingan Dosen' }
];
return (
<div className="container mx-auto p-4 space-y-6">
<h1 className="text-2xl font-bold mb-2">Dashboard Mahasiswa</h1>
<div className="mb-2">
<p className="text-gray-600 dark:text-gray-300">
Visualisasi Data Akademik Mahasiswa Informatika Universitas Tanjungpura
</p>
</div>
{/* Dashboard Stats Cards */}
{loading ? (
<DashboardStatsSkeleton />
) : mahasiswaData ? (
<DashboardStats mahasiswaData={mahasiswaData} />
) : (
<div className="mb-8 p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
<p className="text-red-600 dark:text-red-400">Gagal memuat data statistik mahasiswa</p>
</div>
)}
<div className="mb-4">
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4 sm:space-x-4">
<FilterTahunAngkatan
selectedYear={selectedYear}
onYearChange={setSelectedYear}
/>
{/* Quick Navigation Dropdown */}
<DropdownMenu open={dropdownOpen} onOpenChange={setDropdownOpen}>
<DropdownMenuTrigger asChild>
<Button variant="outline" className="flex items-center gap-2">
Judul Visualisasi
<ChevronDown className="size-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-80">
{(selectedYear === "all" ? allDataNavItems : perYearNavItems).map((item) => (
<DropdownMenuItem
key={item.id}
onClick={(e) => {
e.preventDefault();
scrollToSection(item.id);
}}
className="cursor-pointer"
>
{item.label}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
{selectedYear === "all" ? (
<div className="space-y-6">
{/* Overview Section */}
<div id="overview" className="grid grid-cols-1 md:grid-cols-2 gap-4 scroll-mt-24">
<StatistikMahasiswaChart />
<StatusMahasiswaChart />
</div>
{/* Academic Performance Section */}
<div id="academic" className="grid grid-cols-1 md:grid-cols-2 gap-4 scroll-mt-24">
<IPKChart />
<JenisPendaftaranChart />
</div>
{/* Study Duration Section */}
<div id="study-duration" className="grid grid-cols-1 md:grid-cols-2 gap-4 scroll-mt-24">
<LulusTepatWaktuChart selectedYear={selectedYear} />
<MasaStudiLulusChart selectedYear={selectedYear} />
</div>
{/* Expertise & Achievement Section */}
<div id="expertise" className="grid grid-cols-1 md:grid-cols-2 gap-4 scroll-mt-24">
<KelompokKeahlianStatusChart selectedYear={selectedYear} />
<KelompokKeahlianLulusTepatPieChart />
</div>
{/* Scholarship & Achievement Section */}
<div id="scholarship" className="grid grid-cols-1 md:grid-cols-2 gap-4 scroll-mt-24">
<NamaBeasiswaChart selectedYear={selectedYear} />
<TingkatPrestasiChart selectedYear={selectedYear} />
</div>
{/* Demographics Section */}
<div id="demographics" className="grid grid-cols-1 md:grid-cols-2 gap-4 scroll-mt-24">
<div className="col-span-1">
<AsalDaerahChart />
</div>
<div className="col-span-1">
<ProvinsiMahasiswaChart />
</div>
</div>
<div id="bimbingan-dosen" className="grid grid-cols-1 md:grid-cols-2 gap-4 scroll-mt-24">
<BimbinganDosenChart />
</div>
</div>
) : (
<div className="space-y-6">
{/* Overview Section */}
<div id="overview-year" className="grid grid-cols-1 md:grid-cols-2 gap-4 scroll-mt-24">
<StatistikPerAngkatanChart tahunAngkatan={selectedYear} />
<StatusMahasiswaPieChartPerangkatan selectedYear={selectedYear} />
</div>
{/* Status Section */}
<div id="status-year" className="grid grid-cols-1 md:grid-cols-2 gap-4 scroll-mt-24">
<JenisPendaftaranPerAngkatanChart tahunAngkatan={selectedYear} />
<KelompokKeahlianPieChartPerAngkatan selectedYear={selectedYear} />
</div>
<div id="achievement-year" className="grid grid-cols-1 md:grid-cols-2 gap-4 scroll-mt-24">
<NamaBeasiswaDashPieChartPerangkatan selectedYear={selectedYear} />
<TingkatPrestasiPieChartDash selectedYear={selectedYear} />
</div>
{/* Demographics Section */}
<div id="demographics-year" className="grid grid-cols-1 md:grid-cols-1 gap-4 scroll-mt-24">
<AsalDaerahPerAngkatanChart tahunAngkatan={selectedYear} />
</div>
<div id="bimbingan-dosen-year" className="grid grid-cols-1 md:grid-cols-1 gap-4 scroll-mt-24">
<BimbinganDosenPerAngkatanChart tahunAngkatan={selectedYear} />
</div>
</div>
)}
{/* Back to Top Button */}
{showBackToTop && (
<button
onClick={scrollToTop}
className={`
fixed bottom-6 right-6 z-50
w-12 h-12 rounded-full
bg-primary text-primary-foreground
shadow-lg hover:shadow-xl
transition-all duration-300 ease-in-out
hover:scale-110 hover:bg-primary/90
flex items-center justify-center
group
`}
aria-label="Kembali ke atas"
>
<ArrowUp className="size-5 transition-transform duration-200 group-hover:-translate-y-0.5" />
</button>
)}
</div>
);
}