Point Docker and Coolify compose to the Laravel rebuild app so mahasiswa, dosen, and admin flows are served from the new Laravel public entrypoint.
182 lines
8.8 KiB
PHP
182 lines
8.8 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Dashboard;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\View\View;
|
|
|
|
class MahasiswaDashboardController extends Controller
|
|
{
|
|
public function __invoke(Request $request): View
|
|
{
|
|
$auth = $request->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');
|
|
}
|
|
}
|