765 lines
29 KiB
PHP
765 lines
29 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>ASGARD - Dashboard Siswa</title>
|
|
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
|
|
<style>
|
|
body {
|
|
font-family: 'Plus Jakarta Sans', sans-serif;
|
|
background:
|
|
radial-gradient(circle at 8% 12%, rgba(16, 185, 129, 0.10), transparent 32%),
|
|
radial-gradient(circle at 92% 8%, rgba(59, 130, 246, 0.08), transparent 30%),
|
|
linear-gradient(180deg, #f8fafc 0%, #f3f7fb 48%, #f8fafc 100%);
|
|
}
|
|
|
|
nav {
|
|
box-shadow: 0 10px 35px rgba(15, 23, 42, 0.05);
|
|
}
|
|
|
|
nav a {
|
|
position: relative;
|
|
}
|
|
|
|
nav a::after {
|
|
content: "";
|
|
position: absolute;
|
|
left: 0;
|
|
bottom: -10px;
|
|
width: 0;
|
|
height: 2px;
|
|
border-radius: 999px;
|
|
background: #10b981;
|
|
transition: width 0.25s ease;
|
|
}
|
|
|
|
nav a:hover::after,
|
|
nav a.text-emerald-600::after {
|
|
width: 100%;
|
|
}
|
|
|
|
main > header {
|
|
background: rgba(255, 255, 255, 0.88);
|
|
border: 1px solid rgba(226, 232, 240, 0.9);
|
|
border-radius: 32px;
|
|
padding: 34px;
|
|
box-shadow: 0 18px 55px rgba(15, 23, 42, 0.06);
|
|
backdrop-filter: blur(18px);
|
|
}
|
|
|
|
main > header h1 {
|
|
letter-spacing: -0.045em;
|
|
}
|
|
|
|
.card-shadow {
|
|
box-shadow: 0 18px 50px rgba(15, 23, 42, 0.07);
|
|
}
|
|
|
|
.card-hover {
|
|
transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease, background-color 0.25s ease;
|
|
}
|
|
|
|
.card-hover:hover {
|
|
transform: translateY(-4px);
|
|
box-shadow: 0 24px 60px rgba(15, 23, 42, 0.11);
|
|
border-color: rgba(16, 185, 129, 0.20);
|
|
}
|
|
|
|
main section.bg-white,
|
|
main section > div.bg-white,
|
|
main .bg-white.p-8,
|
|
main .bg-white.p-8.md\:p-10 {
|
|
background: rgba(255, 255, 255, 0.93);
|
|
backdrop-filter: blur(14px);
|
|
}
|
|
|
|
#activity-list a,
|
|
#activity-list-large a {
|
|
box-shadow: 0 6px 18px rgba(15, 23, 42, 0.035);
|
|
}
|
|
|
|
#activity-list a:hover,
|
|
#activity-list-large a:hover {
|
|
transform: translateX(4px);
|
|
}
|
|
|
|
#trendChart {
|
|
filter: drop-shadow(0 12px 24px rgba(16, 185, 129, 0.10));
|
|
}
|
|
|
|
footer {
|
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
main > header {
|
|
padding: 24px;
|
|
border-radius: 26px;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body class="flex flex-col min-h-screen text-slate-800">
|
|
|
|
<!-- Navbar -->
|
|
<nav class="sticky top-0 z-50 bg-white/95 backdrop-blur-md border-b border-slate-100 px-6 py-4">
|
|
<div class="max-w-7xl mx-auto flex justify-between items-center gap-4">
|
|
<div class="flex items-center gap-4">
|
|
<div class="w-10 h-10 bg-emerald-100 rounded-xl flex items-center justify-center text-emerald-600 font-bold">
|
|
AS
|
|
</div>
|
|
<span class="font-black text-xl tracking-tighter text-emerald-950 uppercase italic">
|
|
ASGARD.
|
|
</span>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-8">
|
|
<div class="hidden md:flex gap-8 text-[11px] font-bold uppercase tracking-widest text-slate-400">
|
|
<a href="{{ route('student.profile') }}" class="text-emerald-600">
|
|
Beranda
|
|
</a>
|
|
|
|
<a href="{{ route('student.prediction') }}" class="hover:text-emerald-600 transition">
|
|
Cek Rekomendasi
|
|
</a>
|
|
|
|
<!-- Menu ini membuka hasil rekomendasi terakhir -->
|
|
<a href="#" onclick="goToLastResult(event)" class="hover:text-emerald-600 transition">
|
|
Hasil Rekomendasi
|
|
</a>
|
|
|
|
<!-- <a href="#" class="hover:text-emerald-600 transition">
|
|
Kontak BK
|
|
</a> -->
|
|
</div>
|
|
|
|
<div class="flex items-center gap-3">
|
|
<div class="hidden sm:flex items-center gap-3 bg-emerald-50 px-4 py-2 rounded-full border border-emerald-100">
|
|
<div class="w-2 h-2 bg-emerald-500 rounded-full animate-pulse"></div>
|
|
<span id="student-name-label" class="text-[10px] font-bold text-emerald-700 uppercase">
|
|
Siswa
|
|
</span>
|
|
</div>
|
|
|
|
<button onclick="handleLogout()" class="bg-red-50 hover:bg-red-100 text-red-600 border border-red-100 px-4 py-2 rounded-full transition-all">
|
|
<span class="text-[10px] font-bold uppercase tracking-widest">
|
|
Logout
|
|
</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="max-w-7xl mx-auto px-6 flex-grow py-10">
|
|
|
|
<!-- Header -->
|
|
<header class="mb-10">
|
|
<h1 class="text-4xl font-extrabold text-slate-900 tracking-tight">
|
|
Halo, Siswa SMAPA! 👋
|
|
</h1>
|
|
|
|
<p class="text-slate-500 font-medium mt-2 max-w-3xl">
|
|
Dashboard ini menampilkan ringkasan aktivitas rekomendasi jurusan, riwayat analisis, dan perkembangan nilai yang pernah kamu masukkan.
|
|
</p>
|
|
</header>
|
|
|
|
<!-- Statistik -->
|
|
<section class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-10">
|
|
<div class="bg-white p-8 rounded-3xl card-shadow border border-slate-100 card-hover">
|
|
<h4 class="text-slate-400 text-xs font-bold uppercase tracking-widest mb-4">
|
|
Total Rekomendasi
|
|
</h4>
|
|
|
|
<p id="stat-total" class="text-6xl font-black text-emerald-600 tracking-tighter">
|
|
0
|
|
</p>
|
|
|
|
<p class="text-[12px] text-slate-500 mt-6 font-medium leading-relaxed">
|
|
Jumlah rekomendasi jurusan yang pernah diproses melalui sistem.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="bg-white p-8 rounded-3xl card-shadow border border-slate-100 card-hover">
|
|
<h4 class="text-slate-400 text-xs font-bold uppercase tracking-widest mb-4">
|
|
Rekomendasi Terakhir
|
|
</h4>
|
|
|
|
<p id="stat-last" class="text-lg font-extrabold text-slate-800 leading-relaxed">
|
|
Memuat data...
|
|
</p>
|
|
|
|
<p class="text-[12px] text-slate-500 mt-6 leading-relaxed">
|
|
Detail hasil terakhir dapat dibuka melalui menu <b>Hasil Rekomendasi</b> pada navbar.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="bg-white p-8 rounded-3xl card-shadow border border-slate-100">
|
|
<h4 class="text-slate-400 text-xs font-bold uppercase tracking-widest mb-4">
|
|
Riwayat Terbaru
|
|
</h4>
|
|
|
|
<div id="activity-list" class="space-y-3 py-2">
|
|
<p class="text-xs text-slate-400 italic">
|
|
Belum ada riwayat rekomendasi.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Akses cepat -->
|
|
<section class="bg-white p-8 md:p-10 rounded-[2.5rem] card-shadow border border-slate-100 mb-10">
|
|
<div class="mb-8">
|
|
<h3 class="text-xl font-black text-slate-900">
|
|
Akses Cepat
|
|
</h3>
|
|
|
|
<p class="text-sm text-slate-500 mt-2">
|
|
Gunakan menu berikut untuk melanjutkan aktivitas pada sistem.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
<a href="{{ route('student.prediction') }}"
|
|
class="flex items-center p-6 bg-blue-50 rounded-2xl border border-blue-100 card-hover">
|
|
<div class="w-12 h-12 bg-blue-500 text-white rounded-xl flex items-center justify-center text-xl mr-5 shadow-lg shadow-blue-100">
|
|
📝
|
|
</div>
|
|
|
|
<div>
|
|
<h4 class="font-black text-blue-900 text-sm">
|
|
Cek Rekomendasi Baru
|
|
</h4>
|
|
<p class="text-[11px] text-blue-700 font-semibold mt-1">
|
|
Isi data kembali untuk mendapatkan hasil terbaru.
|
|
</p>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="#" onclick="goToLastResult(event)"
|
|
class="flex items-center p-6 bg-emerald-50 rounded-2xl border border-emerald-100 card-hover">
|
|
<div class="w-12 h-12 bg-emerald-500 text-white rounded-xl flex items-center justify-center text-xl mr-5 shadow-lg shadow-emerald-100">
|
|
📄
|
|
</div>
|
|
|
|
<div>
|
|
<h4 class="font-black text-emerald-900 text-sm">
|
|
Hasil Rekomendasi
|
|
</h4>
|
|
<p class="text-[11px] text-emerald-700 font-semibold mt-1">
|
|
Buka kembali hasil rekomendasi terakhir.
|
|
</p>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="#riwayat-section"
|
|
class="flex items-center p-6 bg-violet-50 rounded-2xl border border-violet-100 card-hover">
|
|
<div class="w-12 h-12 bg-violet-500 text-white rounded-xl flex items-center justify-center text-xl mr-5 shadow-lg shadow-violet-100">
|
|
🕘
|
|
</div>
|
|
|
|
<div>
|
|
<h4 class="font-black text-violet-900 text-sm">
|
|
Riwayat Rekomendasi
|
|
</h4>
|
|
<p class="text-[11px] text-violet-700 font-semibold mt-1">
|
|
Lihat daftar rekomendasi yang pernah dibuat.
|
|
</p>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Grafik -->
|
|
<section class="bg-white p-8 md:p-10 rounded-[2.5rem] card-shadow border border-slate-100 mb-10">
|
|
<h3 class="text-xl font-black text-slate-900 mb-2">
|
|
Perkembangan Rata-Rata Nilai
|
|
</h3>
|
|
|
|
<p class="text-sm text-slate-500 font-medium mb-8">
|
|
Grafik ini menampilkan perubahan rata-rata nilai berdasarkan data yang pernah kamu masukkan saat melakukan rekomendasi.
|
|
</p>
|
|
|
|
<div id="chart-container" class="h-80 w-full">
|
|
<canvas id="trendChart"></canvas>
|
|
</div>
|
|
|
|
<p id="chart-placeholder" class="hidden text-center text-slate-400 italic text-sm py-20">
|
|
Grafik akan muncul setelah terdapat data rekomendasi.
|
|
</p>
|
|
</section>
|
|
|
|
<!-- Panduan -->
|
|
<section id="panduan-section" class="bg-white p-8 md:p-10 rounded-[2.5rem] card-shadow border border-slate-100 mb-10">
|
|
<div class="flex flex-col lg:flex-row gap-8">
|
|
<div class="lg:w-1/3">
|
|
<div class="w-14 h-14 rounded-2xl bg-emerald-100 text-emerald-700 flex items-center justify-center text-2xl mb-5">
|
|
📌
|
|
</div>
|
|
|
|
<h3 class="text-2xl font-black text-slate-900">
|
|
Panduan Membaca Hasil
|
|
</h3>
|
|
|
|
<p class="text-sm text-slate-500 mt-3 leading-relaxed">
|
|
Hasil rekomendasi digunakan sebagai bahan pertimbangan awal. Keputusan akhir tetap perlu disesuaikan dengan minat, kemampuan, dan arahan Guru BK.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="lg:w-2/3 grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<div class="rounded-3xl bg-slate-50 border border-slate-100 p-6">
|
|
<h4 class="font-extrabold text-slate-800 mb-3">
|
|
1. Periksa Data
|
|
</h4>
|
|
|
|
<p class="text-sm text-slate-500 leading-relaxed">
|
|
Pastikan nilai rapor, minat, dan kondisi ekonomi sudah sesuai dengan data sebenarnya.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="rounded-3xl bg-slate-50 border border-slate-100 p-6">
|
|
<h4 class="font-extrabold text-slate-800 mb-3">
|
|
2. Pelajari Jurusan
|
|
</h4>
|
|
|
|
<p class="text-sm text-slate-500 leading-relaxed">
|
|
Cari informasi tentang mata kuliah, biaya kuliah, peluang kerja, dan kampus yang menyediakan jurusan tersebut.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="rounded-3xl bg-slate-50 border border-slate-100 p-6">
|
|
<h4 class="font-extrabold text-slate-800 mb-3">
|
|
3. Konsultasi BK
|
|
</h4>
|
|
|
|
<p class="text-sm text-slate-500 leading-relaxed">
|
|
Diskusikan hasil rekomendasi dengan Guru BK agar pilihan jurusan lebih matang.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Riwayat -->
|
|
<section id="riwayat-section" class="bg-white p-8 md:p-10 rounded-[2.5rem] card-shadow border border-slate-100 mb-16">
|
|
<div class="mb-6">
|
|
<h3 class="text-xl font-black text-slate-900">
|
|
Riwayat Rekomendasi
|
|
</h3>
|
|
|
|
<p class="text-sm text-slate-500 mt-2">
|
|
Riwayat terbaru akan muncul pada daftar berikut.
|
|
</p>
|
|
</div>
|
|
|
|
<div id="activity-list-large" class="space-y-3">
|
|
<p class="text-sm text-slate-400 italic">
|
|
Belum ada riwayat rekomendasi.
|
|
</p>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<!-- Footer -->
|
|
<footer class="bg-[#062C22] text-white py-16 px-6">
|
|
<div class="max-w-7xl mx-auto grid grid-cols-1 md:grid-cols-3 gap-12">
|
|
<div class="space-y-6">
|
|
<span class="font-black text-2xl tracking-tighter uppercase italic">
|
|
ASGARD.
|
|
</span>
|
|
|
|
<p class="text-slate-300 text-sm leading-relaxed max-w-xs">
|
|
Sistem rekomendasi jurusan kuliah SMAN 4 Jember berbasis profil siswa dan data akademik.
|
|
</p>
|
|
</div>
|
|
|
|
<div>
|
|
<h5 class="font-bold text-xs uppercase tracking-widest text-emerald-400 mb-6">
|
|
Informasi
|
|
</h5>
|
|
|
|
<ul class="space-y-4 text-sm text-slate-300">
|
|
<li>
|
|
<a href="{{ route('panduan') }}" class="hover:text-white transition">
|
|
Panduan Sistem
|
|
</a>
|
|
</li>
|
|
<!-- <li>
|
|
<a href="#" class="hover:text-white transition">
|
|
Kebijakan Privasi
|
|
</a>
|
|
</li> -->
|
|
</ul>
|
|
</div>
|
|
|
|
<div>
|
|
<h5 class="font-bold text-xs uppercase tracking-widest text-emerald-400 mb-6">
|
|
Sekolah
|
|
</h5>
|
|
|
|
<ul class="space-y-4 text-sm text-slate-300">
|
|
<li>SMAN 4 Jember</li>
|
|
<li>Jl. Wolter Monginsidi No.24</li>
|
|
<li>Jember, Jawa Timur</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="max-w-7xl mx-auto mt-16 pt-8 border-t border-white/10 text-center">
|
|
<p class="text-[10px] font-medium uppercase tracking-[0.35em] text-slate-400">
|
|
© 2026 GALANG SEFIAN ADJI - POLITEKNIK NEGERI JEMBER
|
|
</p>
|
|
</div>
|
|
</footer>
|
|
|
|
<script>
|
|
let trendChartInstance = null;
|
|
|
|
const routeLogin = @json(route('login'));
|
|
const routeDashboard = @json(route('student.profile'));
|
|
const routePrediction = @json(route('student.prediction'));
|
|
const routeAdminDashboard = @json(route('admin.dashboard'));
|
|
|
|
function getAccessToken() {
|
|
return localStorage.getItem('access_token');
|
|
}
|
|
|
|
function getUserRole() {
|
|
return localStorage.getItem('user_role');
|
|
}
|
|
|
|
function redirectByRole(role) {
|
|
if (role === 'admin') {
|
|
window.location.href = routeAdminDashboard;
|
|
return;
|
|
}
|
|
|
|
if (role === 'siswa') {
|
|
window.location.href = routeDashboard;
|
|
return;
|
|
}
|
|
|
|
window.location.href = routeLogin;
|
|
}
|
|
|
|
function getStoredLastResult() {
|
|
try {
|
|
const saved = localStorage.getItem('asgard_last_result');
|
|
return saved ? JSON.parse(saved) : null;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function saveStoredLastResult(data) {
|
|
if (!data || !data.jurusan) return;
|
|
|
|
const oldData = getStoredLastResult() || {};
|
|
|
|
const nextData = {
|
|
id: data.id || oldData.id || '',
|
|
jurusan: data.jurusan || oldData.jurusan || '',
|
|
tanggal: data.tanggal || oldData.tanggal || '',
|
|
url: data.url || oldData.url || ''
|
|
};
|
|
|
|
localStorage.setItem('asgard_last_result', JSON.stringify(nextData));
|
|
}
|
|
|
|
function goToLastResult(event) {
|
|
event.preventDefault();
|
|
|
|
const saved = getStoredLastResult();
|
|
|
|
if (saved && saved.url) {
|
|
window.location.href = saved.url;
|
|
return;
|
|
}
|
|
|
|
if (saved && saved.id) {
|
|
window.location.href = `/student/result/${saved.id}`;
|
|
return;
|
|
}
|
|
|
|
alert('Belum ada hasil rekomendasi yang bisa dibuka. Silakan lakukan cek rekomendasi terlebih dahulu.');
|
|
window.location.href = routePrediction;
|
|
}
|
|
|
|
function getHistoryId(item) {
|
|
if (!item || typeof item !== 'object') return '';
|
|
|
|
return item.id
|
|
|| item.riwayat_id
|
|
|| item.riwayat_rekomendasi_id
|
|
|| item.rekomendasi_id
|
|
|| item.result_id
|
|
|| item.hasil_id
|
|
|| '';
|
|
}
|
|
|
|
function makeResultUrl(id) {
|
|
return id ? `/student/result/${id}` : '';
|
|
}
|
|
|
|
function isValidRecommendationName(value) {
|
|
if (!value) return false;
|
|
|
|
const text = String(value).trim().toLowerCase();
|
|
|
|
return text !== ''
|
|
&& text !== '-'
|
|
&& text !== 'null'
|
|
&& text !== 'undefined'
|
|
&& !text.includes('belum');
|
|
}
|
|
|
|
async function handleLogout() {
|
|
const token = getAccessToken();
|
|
|
|
if (token) {
|
|
try {
|
|
await fetch('/api/logout', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('Logout error:', error);
|
|
}
|
|
}
|
|
|
|
localStorage.removeItem('access_token');
|
|
localStorage.removeItem('user_role');
|
|
localStorage.removeItem('asgard_last_result');
|
|
window.location.href = routeLogin;
|
|
}
|
|
|
|
function renderActivityList(activities) {
|
|
const smallList = document.getElementById('activity-list');
|
|
const largeList = document.getElementById('activity-list-large');
|
|
|
|
if (!Array.isArray(activities) || activities.length === 0) {
|
|
smallList.innerHTML = `
|
|
<p class="text-xs text-slate-400 italic">
|
|
Belum ada riwayat rekomendasi.
|
|
</p>
|
|
`;
|
|
|
|
largeList.innerHTML = `
|
|
<p class="text-sm text-slate-400 italic">
|
|
Belum ada riwayat rekomendasi.
|
|
</p>
|
|
`;
|
|
|
|
return;
|
|
}
|
|
|
|
smallList.innerHTML = activities.slice(0, 5).map((act) => {
|
|
const id = getHistoryId(act);
|
|
const url = makeResultUrl(id);
|
|
const jurusan = act.jurusan || act.hasil_rekomendasi_jurusan || 'Rekomendasi Jurusan';
|
|
const tanggal = act.tanggal || act.created_at || '';
|
|
|
|
return `
|
|
<a href="${url || '#'}"
|
|
class="flex items-center justify-between bg-slate-50 hover:bg-emerald-50 p-3 rounded-xl border border-slate-100 hover:border-emerald-100 transition">
|
|
<div class="flex items-center gap-3">
|
|
<span class="text-lg">📄</span>
|
|
<span class="text-[11px] font-bold text-slate-700 uppercase tracking-tight">
|
|
${jurusan}
|
|
</span>
|
|
</div>
|
|
<span class="text-[9px] font-black text-slate-400 uppercase">
|
|
${tanggal}
|
|
</span>
|
|
</a>
|
|
`;
|
|
}).join('');
|
|
|
|
largeList.innerHTML = activities.map((act) => {
|
|
const id = getHistoryId(act);
|
|
const url = makeResultUrl(id);
|
|
const jurusan = act.jurusan || act.hasil_rekomendasi_jurusan || 'Rekomendasi Jurusan';
|
|
const tanggal = act.tanggal || act.created_at || 'Tanggal tidak tersedia';
|
|
|
|
return `
|
|
<a href="${url || '#'}"
|
|
class="flex flex-col md:flex-row md:items-center md:justify-between gap-3 rounded-2xl border border-slate-100 bg-slate-50 hover:bg-emerald-50 hover:border-emerald-100 p-5 transition">
|
|
<div class="flex items-center gap-4">
|
|
<div class="w-11 h-11 rounded-2xl bg-white flex items-center justify-center border border-slate-100">
|
|
📄
|
|
</div>
|
|
<div>
|
|
<h4 class="font-extrabold text-slate-800 uppercase">
|
|
${jurusan}
|
|
</h4>
|
|
<p class="text-xs text-slate-500 mt-1">
|
|
${tanggal}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<span class="text-xs font-bold text-emerald-700">
|
|
${url ? 'Lihat detail →' : 'Detail tidak tersedia'}
|
|
</span>
|
|
</a>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
function renderTrendChart(tren) {
|
|
const canvas = document.getElementById('trendChart');
|
|
const placeholder = document.getElementById('chart-placeholder');
|
|
|
|
if (!Array.isArray(tren) || tren.length === 0) {
|
|
canvas.classList.add('hidden');
|
|
placeholder.classList.remove('hidden');
|
|
return;
|
|
}
|
|
|
|
canvas.classList.remove('hidden');
|
|
placeholder.classList.add('hidden');
|
|
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
if (trendChartInstance) {
|
|
trendChartInstance.destroy();
|
|
}
|
|
|
|
trendChartInstance = new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: tren.map(t => t.label),
|
|
datasets: [{
|
|
label: 'Rata-rata Nilai',
|
|
data: tren.map(t => t.nilai),
|
|
borderColor: '#10b981',
|
|
backgroundColor: 'rgba(16, 185, 129, 0.12)',
|
|
fill: true,
|
|
tension: 0.4,
|
|
pointRadius: 5,
|
|
pointBackgroundColor: '#ffffff',
|
|
pointBorderColor: '#10b981',
|
|
pointBorderWidth: 3
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
display: false
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
min: 0,
|
|
max: 100,
|
|
ticks: {
|
|
color: '#64748b'
|
|
},
|
|
grid: {
|
|
color: '#f1f5f9'
|
|
}
|
|
},
|
|
x: {
|
|
ticks: {
|
|
color: '#64748b'
|
|
},
|
|
grid: {
|
|
display: false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', async function () {
|
|
const token = getAccessToken();
|
|
const role = getUserRole();
|
|
|
|
if (!token) {
|
|
window.location.href = routeLogin;
|
|
return;
|
|
}
|
|
|
|
if (role !== 'siswa') {
|
|
redirectByRole(role);
|
|
return;
|
|
}
|
|
|
|
const savedName = localStorage.getItem('user_name') || localStorage.getItem('name') || 'Siswa';
|
|
document.getElementById('student-name-label').innerText = savedName;
|
|
|
|
try {
|
|
const response = await fetch('/api/student/dashboard-stats', {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
});
|
|
|
|
if (response.status === 401) {
|
|
localStorage.removeItem('access_token');
|
|
localStorage.removeItem('user_role');
|
|
window.location.href = routeLogin;
|
|
return;
|
|
}
|
|
|
|
const result = await response.json();
|
|
|
|
if (!result.success) {
|
|
document.getElementById('stat-total').innerText = 0;
|
|
document.getElementById('stat-last').innerText = 'Belum ada rekomendasi';
|
|
renderActivityList([]);
|
|
renderTrendChart([]);
|
|
return;
|
|
}
|
|
|
|
const data = result.data || {};
|
|
const activities = Array.isArray(data.aktivitas_terbaru) ? data.aktivitas_terbaru : [];
|
|
const firstActivity = activities.length > 0 ? activities[0] : null;
|
|
|
|
document.getElementById('stat-total').innerText = data.total_aktivitas ?? 0;
|
|
|
|
const lastName = data.rekomendasi_terakhir || '';
|
|
|
|
document.getElementById('stat-last').innerText = isValidRecommendationName(lastName)
|
|
? lastName
|
|
: 'Belum ada rekomendasi';
|
|
|
|
// Simpan hasil terakhir dari data dashboard jika API mengirim id riwayat
|
|
const firstId = getHistoryId(firstActivity);
|
|
|
|
if (isValidRecommendationName(lastName) && firstId) {
|
|
saveStoredLastResult({
|
|
id: firstId,
|
|
jurusan: lastName,
|
|
tanggal: firstActivity?.tanggal || '',
|
|
url: makeResultUrl(firstId)
|
|
});
|
|
}
|
|
|
|
renderActivityList(activities);
|
|
renderTrendChart(data.tren_nilai || []);
|
|
|
|
} catch (error) {
|
|
console.error('Gagal memuat data dashboard:', error);
|
|
|
|
document.getElementById('stat-total').innerText = 0;
|
|
document.getElementById('stat-last').innerText = 'Data belum dapat dimuat';
|
|
renderActivityList([]);
|
|
renderTrendChart([]);
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |