diff --git a/app/Http/Controllers/Siswa/DashboardController.php b/app/Http/Controllers/Siswa/DashboardController.php new file mode 100644 index 0000000..dc33d7a --- /dev/null +++ b/app/Http/Controllers/Siswa/DashboardController.php @@ -0,0 +1,109 @@ +middleware('auth:siswa'); + } + + public function index() + { + /** @var \App\Models\Siswa $siswa */ + $siswa = Auth::guard('siswa')->user(); + + // ============================================= + // 1. TUGAS โ€” ambil tugas yang belum dikumpulkan + // dan deadline-nya belum lewat, urutkan by deadline + // ============================================= + $tugasRaw = Tugas::with('mataPelajaran') // eager load relasi mapel + ->whereDoesntHave('pengumpulan', function ($q) use ($siswa) { + // tugas yang BELUM dikumpulkan oleh siswa ini + $q->where('siswa_id', $siswa->id); + }) + ->where('deadline', '>=', Carbon::now()) + ->orderBy('deadline', 'asc') + ->take(5) // tampilkan maks 5 tugas di dashboard + ->get(); + + // Kelompokkan tugas berdasarkan tanggal deadline + $tugasList = []; + foreach ($tugasRaw as $tugas) { + $tgl = Carbon::parse($tugas->deadline) + ->locale('id') + ->isoFormat('dddd, D MMMM YYYY'); // contoh: "Sabtu, 10 Mei 2025" + + $tugasList[$tgl][] = [ + 'jam' => Carbon::parse($tugas->deadline)->format('H.i'), + 'nama' => $tugas->judul, + // sesuaikan nama kolom dengan model kamu + 'mapel' => 'Belum ยท ' . ($tugas->mataPelajaran->nama ?? '-'), + ]; + } + + // ============================================= + // 2. CHALLENGE MINGGUAN + // ============================================= + $startMingguIni = Carbon::now()->startOfWeek(); + $endMingguIni = Carbon::now()->endOfWeek(); + + // Total challenge aktif minggu ini + $challengeTotal = Challenge::whereBetween('created_at', [$startMingguIni, $endMingguIni]) + ->where('is_active', true) + ->count(); + + // Challenge yang sudah diselesaikan siswa minggu ini + $challengeDone = ChallengeSiswa::where('siswa_id', $siswa->id) + ->where('status', 'selesai') + ->whereBetween('created_at', [$startMingguIni, $endMingguIni]) + ->count(); + + // ============================================= + // 3. TUGAS SELESAI MINGGU INI (untuk speech bubble mascot) + // ============================================= + $tugasSelesai = TugasSiswa::where('siswa_id', $siswa->id) + ->whereBetween('created_at', [$startMingguIni, $endMingguIni]) + ->count(); + + // ============================================= + // 4. LEADERBOARD โ€” top 3 siswa berdasarkan total EXP + // Asumsi: kolom 'exp' ada di tabel siswa + // Sesuaikan jika EXP disimpan di tabel lain + // ============================================= + $leaderboardRaw = Siswa::orderBy('exp', 'desc') + ->take(3) + ->get(); + + $leaderboard = $leaderboardRaw->map(function ($item, $index) { + return [ + 'rank' => $index + 1, + 'nama' => $item->nama, + 'exp' => $item->exp, + ]; + })->toArray(); + + return view('siswa.dashboard', compact( + 'tugasList', + 'challengeDone', + 'challengeTotal', + 'tugasSelesai', + 'leaderboard', + )); + } +} \ No newline at end of file diff --git a/resources/views/siswa/dashboard.blade.php b/resources/views/siswa/dashboard.blade.php index 674cce6..71b468b 100644 --- a/resources/views/siswa/dashboard.blade.php +++ b/resources/views/siswa/dashboard.blade.php @@ -1,75 +1,498 @@ -@extends('siswa.layouts.app') +@extends('layouts.siswa.app') @section('title', 'Dashboard Siswa') +@push('styles') + +@endpush + @section('content') -
-

Dashboard

+@php $namaSaya = Auth::guard('siswa')->user()->nama ?? ''; @endphp - -
-
-
-
-
- -
-
-
Tugas Aktif
-
0
-
-
-
+
+ + {{-- ===== TUGAS ===== --}} +
+
+

Tugas

+ LIHAT SEMUA
-
-
-
-
- -
-
-
Challenge Selesai
-
0
+ @forelse($tugasList as $tanggal => $items) +

{{ $tanggal }}

+ @foreach($items as $item) +
+ {{ $item['jam'] }} + ๐Ÿ“‹ +
+

{{ $item['nama'] }}

+

{{ $item['mapel'] }}

-
-
- -
-
-
-
- -
-
-
Total EXP
-
0
-
-
-
-
+ @endforeach + @empty +
๐ŸŽ‰ Tidak ada tugas yang pending!
+ @endforelse
- -
-
Informasi Akun
- - - - - - - - - - - - - + {{-- ===== KALENDER ===== --}} +
+
+ + + +
+
Nama: {{ Auth::guard('siswa')->user()->nama }}
NISN: {{ Auth::guard('siswa')->user()->nisn }}
Kelas: {{ Auth::guard('siswa')->user()->kelas->nama_kelas ?? '-' }}
+ + + + + + +
SUNMONTUEWEDTHUFRISAT
+ + {{-- ===== CHALLENGE MINGGUAN ===== --}} +
+
+

Challenge Mingguan

+
+ + @php + $persen = $challengeTotal > 0 + ? round(($challengeDone / $challengeTotal) * 100) + : 0; + @endphp + +
+
โšก
+
+

Ayo kerjakan challenge dan dapatkan EXP tambahan!

+
+
+
+

{{ $challengeDone }}/{{ $challengeTotal }}

+
+
+ + +
+ + {{-- ===== MASCOT + SPEECH BUBBLE ===== --}} +
+
+ @if($tugasSelesai > 0) + Kamu sudah mengerjakan {{ $tugasSelesai }} tugas minggu + ini, yuk lanjutkan untuk mendapatkan badge yang lebih menarik! + @else + Belum ada tugas yang diselesaikan minggu ini. + Ayo mulai kerjakan tugasmu! ๐Ÿ’ช + @endif +
+ + @if(file_exists(public_path('images/mascot.png'))) + Mascot + @else +
๐Ÿถ
+ @endif +
+ + {{-- ===== LEADERBOARD ===== --}} +
+
+

Leaderboard

+ LIHAT SEMUA +
+ + @forelse($leaderboard as $lb) +
+ + @if($lb['rank'] === 1) ๐Ÿฅ‡ + @elseif($lb['rank'] === 2) ๐Ÿฅˆ + @else ๐Ÿฅ‰ + @endif + +
{{ strtoupper(substr($lb['nama'], 0, 1)) }}
+ + {{ $lb['nama'] }} + + {{ number_format($lb['exp']) }} EXP +
+ @empty +

+ Belum ada data leaderboard. +

+ @endforelse +
+
-@endsection \ No newline at end of file +@endsection + +@push('scripts') + +@endpush \ No newline at end of file diff --git a/resources/views/siswa/layouts/app.blade.php b/resources/views/siswa/layouts/app.blade.php index 6c8f4ef..4f53f55 100644 --- a/resources/views/siswa/layouts/app.blade.php +++ b/resources/views/siswa/layouts/app.blade.php @@ -16,30 +16,36 @@ } .siswa-wrapper { - display: flex; - min-height: 100vh; + display: flex; + min-height: 100vh; + position: relative; } + /* ===== SIDEBAR ===== */ .sidebar { - width: 260px; - background: #ffffff; - border-right: 2px solid #e6f0ff; - padding: 30px 20px; - display: flex; - flex-direction: column; - transition: all 0.3s ease; + width: 260px; + background: #ffffff; + border-right: 2px solid #e6f0ff; + padding: 30px 20px; + display: flex; + flex-direction: column; + transition: width 0.3s ease, padding 0.3s ease; + overflow: hidden; + flex-shrink: 0; + position: relative; } + /* Default: collapsed saat pertama load */ .sidebar.collapsed { - width: 0; - padding: 0; - overflow: hidden; - border: none; + width: 0; + padding: 0; + border-right: none; } .sidebar-logo { text-align: center; margin-bottom: 40px; + white-space: nowrap; } .sidebar-logo img { @@ -49,6 +55,7 @@ .sidebar-menu { display: flex; flex-direction: column; + white-space: nowrap; } .sidebar-link { @@ -82,6 +89,7 @@ .sidebar-logout { margin-top: auto; + white-space: nowrap; } .sidebar-logout button { @@ -95,16 +103,60 @@ cursor: pointer; } - .main { - flex: 1; - background: #f5f9ff; - display: flex; - flex-direction: column; - transition: all 0.3s ease; + /* ===== TOGGLE ARROW BUTTON ===== */ + .sidebar-toggle-btn { + position: fixed; + top: 50%; + transform: translateY(-50%); + left: 260px; /* sama dengan lebar sidebar saat terbuka */ + z-index: 1000; + width: 22px; + height: 48px; + background: #2b8ef3; + border: none; + border-radius: 0 10px 10px 0; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: left 0.3s ease, background 0.2s ease; + box-shadow: 2px 0 8px rgba(43, 142, 243, 0.3); } - .main.full { - margin-left: 0; + .sidebar-toggle-btn:hover { + background: #1a7ae0; + } + + /* Posisi tombol saat sidebar collapsed */ + .sidebar-toggle-btn.collapsed { + left: 0; + } + + /* Arrow icon SVG */ + .toggle-arrow { + width: 12px; + height: 12px; + fill: none; + stroke: white; + stroke-width: 2.5; + stroke-linecap: round; + stroke-linejoin: round; + transition: transform 0.3s ease; + } + + /* Saat collapsed, panah mengarah ke kanan (buka) */ + .sidebar-toggle-btn.collapsed .toggle-arrow { + transform: rotate(180deg); + } + + /* ===== MAIN ===== */ + .main { + flex: 1; + background: #f5f9ff; + display: flex; + flex-direction: column; + transition: all 0.3s ease; + min-width: 0; /* prevent overflow */ } /* TOPBAR */ @@ -122,6 +174,9 @@ .topbar-left { font-weight: 600; font-size: 16px; + display: flex; + align-items: center; + gap: 10px; } .topbar-right { @@ -149,8 +204,8 @@
- -