session()->get('legacy_auth'); abort_unless(($auth['role'] ?? null) === 'mahasiswa', 403); $user = $auth['user']; $latestPraoutline = DB::table('tbpraoutline as tp') ->leftJoin('tbrekaphasil as trh', 'tp.id', '=', 'trh.idpraoutline') ->select(['tp.id', 'tp.judul', 'tp.status_usulan', 'trh.ket']) ->where('tp.nim', $user['nim']) ->where('tp.idProdi', $user['prodi']) ->orderByDesc('tp.id') ->first(); $unreadAnnouncements = DB::table('tbpengumuman') ->where('idProdi', $user['prodi']) ->whereIn('tujuan', ['A', 'M']) ->whereNotIn('id', function ($query) use ($user) { $query->select('idkonten') ->from('tmp_notif') ->where('iduser', $user['id']) ->where('typeuser', 'M') ->where('jenis', 'P'); }) ->count(); $publishedSchedules = DB::table('tbjadwal') ->where('idProdi', $user['prodi']) ->where('publish', 'Y') ->count(); $nextSchedule = DB::table('tbjadwal') ->select(['jenis', 'start', 'ruangan']) ->where('idMhs', $user['id']) ->where('publish', 'Y') ->whereNotNull('start') ->orderBy('start') ->first(); $activeDrafts = DB::table('tbpraoutline') ->where('nim', $user['nim']) ->whereIn('status_usulan', ['0', '1']) ->count(); $statusAlert = match ($latestPraoutline?->status_usulan) { '0' => [ 'title' => 'Draft Praoutline Masih Dalam Proses Review', 'description' => 'Silakan cek menu review untuk melihat tanggapan dosen terhadap draft yang sedang berjalan.', 'button' => 'Lihat Review', 'buttonHref' => route('mahasiswa.status-usulan', [], false), 'class' => 'border-sky-200 bg-sky-50 text-sky-900', 'buttonClass' => 'bg-sky-600 text-white hover:opacity-90', ], '1' => [ 'title' => 'Draft Praoutline Anda Telah Disetujui', 'description' => 'Judul terakhir sudah memperoleh persetujuan. Silakan pantau tahapan berikutnya pada modul yang terkait.', 'button' => 'Lihat Putusan', 'buttonHref' => route('mahasiswa.status-usulan', [], false), 'class' => 'border-emerald-200 bg-emerald-50 text-emerald-900', 'buttonClass' => 'bg-emerald-600 text-white hover:opacity-90', ], '2' => [ 'title' => 'Judul yang Anda Ajukan Tidak Disetujui', 'description' => $latestPraoutline?->ket ?: 'Silakan periksa catatan keputusan dan siapkan upload judul baru.', 'button' => 'Lihat Catatan Putusan', 'buttonHref' => route('mahasiswa.status-usulan', [], false), 'class' => 'border-rose-200 bg-rose-50 text-rose-900', 'buttonClass' => 'bg-rose-600 text-white hover:opacity-90', ], default => [ 'title' => 'Belum Ada Draft Praoutline Aktif', 'description' => 'Mahasiswa ini belum memiliki usulan judul aktif yang tercatat pada data SPOTA saat ini.', 'button' => 'Ajukan Outline Baru', 'buttonHref' => route('mahasiswa.praoutline.upload', [], false), 'class' => 'border-slate-200 bg-slate-50 text-slate-900', 'buttonClass' => 'bg-[#15171A] text-white hover:opacity-90', ], }; $announcementAlert = [ 'title' => 'Pengumuman Terbaru', 'description' => $unreadAnnouncements > 0 ? 'Terdapat '.$unreadAnnouncements.' pengumuman program studi yang belum dibaca.' : 'Tidak terdapat pengumuman baru yang perlu dibaca saat ini.', 'button' => 'Lihat Semua Pengumuman', 'buttonHref' => route('mahasiswa.pengumuman.index', [], false), 'class' => 'border-amber-200 bg-amber-50 text-amber-900', 'buttonClass' => 'bg-amber-400 text-[#15171A] hover:bg-amber-300', ]; $dashboard = [ 'eyebrow' => 'Dashboard Mahasiswa', 'title' => 'Halo, '.$user['nama_lengkap'].'.', 'description' => 'Selamat datang di Sistem Pendukung Outline Tugas Akhir (SPOTA) Universitas Tanjungpura.', 'menus' => [ ['title' => 'Dashboard', 'href' => route('dashboard.mahasiswa'), 'icon' => 'home', 'active' => true], ['title' => 'Informasi', 'icon' => 'folder', 'children' => [ ['title' => 'Status Usulan', 'href' => route('mahasiswa.status-usulan', [], false), 'icon' => 'chart'], ['title' => 'Ajukan Outline Baru', 'href' => route('mahasiswa.praoutline.upload', [], false), 'icon' => 'clipboard'], ['title' => 'Penawaran Judul', 'href' => route('mahasiswa.penawaran.index', [], false), 'icon' => 'briefcase'], ['title' => 'Pengumuman', 'href' => route('mahasiswa.pengumuman.index', [], false), 'icon' => 'bell'], ['title' => 'Jadwal Terdekat', 'href' => '#jadwal', 'icon' => 'clock'], ]], ], 'stats' => [ ['label' => 'Status Usulan Terakhir', 'value' => $this->statusLabel($latestPraoutline?->status_usulan), 'delta' => $latestPraoutline ? 'Draft #'.$latestPraoutline->id : 'Belum ada draft', 'deltaClass' => $this->statusDeltaClass($latestPraoutline?->status_usulan), 'note' => $latestPraoutline?->judul ? $latestPraoutline->judul : 'Belum ada judul yang tercatat di sistem.'], ['label' => 'Pengumuman Belum Dibaca', 'value' => (string) $unreadAnnouncements, 'delta' => $unreadAnnouncements > 0 ? 'Perlu dibaca' : 'Sudah aman', 'deltaClass' => $unreadAnnouncements > 0 ? 'bg-amber-100 text-amber-800' : 'bg-emerald-100 text-emerald-800', 'note' => 'Jumlah pengumuman program studi yang belum dibaca.'], ['label' => 'Jadwal Terdekat', 'value' => $nextSchedule ? $this->scheduleLabel($nextSchedule->jenis) : '-', 'delta' => $nextSchedule ? 'Terjadwal' : 'Belum ada jadwal', 'deltaClass' => $nextSchedule ? 'bg-sky-100 text-sky-800' : 'bg-slate-200 text-slate-700', 'note' => $nextSchedule ? $this->formatDateTime($nextSchedule->start).' ยท '.$nextSchedule->ruangan : 'Belum ada jadwal seminar yang dipublikasikan untuk mahasiswa ini.'], ['label' => 'Draft Aktif', 'value' => (string) $activeDrafts, 'delta' => $activeDrafts > 0 ? 'Masih berjalan' : 'Tidak ada', 'deltaClass' => $activeDrafts > 0 ? 'bg-violet-100 text-violet-800' : 'bg-slate-200 text-slate-700', 'note' => 'Jumlah draft yang masih aktif pada data SPOTA.'], ], 'latestTitle' => $latestPraoutline?->judul, 'statusAlert' => $statusAlert, 'announcementAlert' => $announcementAlert, 'nextSchedule' => $nextSchedule ? [ 'jenis' => $this->scheduleLabel($nextSchedule->jenis), 'tanggal' => $this->formatDateTime($nextSchedule->start), 'ruangan' => $nextSchedule->ruangan ?: '-', ] : null, 'publishedSchedules' => $publishedSchedules, ]; return view('dashboard.mahasiswa', [ 'title' => 'Dashboard Mahasiswa | SPOTA Rebuild', 'dashboard' => $dashboard, 'user' => $user, ]); } private function statusLabel(?string $status): string { return match ($status) { '0' => 'Dalam Review', '1' => 'Disetujui', '2' => 'Ditolak', default => 'Belum Ada Draft', }; } private function statusDeltaClass(?string $status): string { return match ($status) { '0' => 'bg-sky-100 text-sky-800', '1' => 'bg-emerald-100 text-emerald-800', '2' => 'bg-rose-100 text-rose-800', default => 'bg-slate-200 text-slate-700', }; } private function scheduleLabel(?string $jenis): string { return match ($jenis) { 'Sidang' => 'Sidang', 'Outline' => 'Outline', 'SidHas' => 'Seminar Hasil', default => $jenis ?? 'Jadwal', }; } private function formatDateTime(?string $value): string { if (! $value) { return '-'; } return Carbon::parse($value)->locale('id')->translatedFormat('j F Y, H:i'); } }