3 hari * - 5 poin per tugas yang tidak dikumpulkan sama sekali (setelah deadline) */ private function hitungExpSiswa(int $idSiswa, int $idKelas): int { $now = Carbon::now(); // ── 1. EXP dari challenge (soal yang dijawab benar) ────────────── $expChallenge = 0; $pesertaList = DB::table('peserta_challenges') ->where('id_siswa', $idSiswa) ->get(); foreach ($pesertaList as $peserta) { $jawaban = json_decode($peserta->jawaban, true) ?? []; $soalList = DB::table('soal_challenge') ->where('id_challenge', $peserta->id_challenge) ->get(); foreach ($soalList as $soal) { $jwb = $jawaban[$soal->id_soal] ?? null; if ($jwb && strtoupper($jwb) === strtoupper($soal->jawaban_benar)) { $expChallenge += 1; // +1 per soal benar } } } // ── 2. EXP dari tugas ──────────────────────────────────────────── $semuaTugasIdKelas = DB::table('tugas') ->join('mengajars', 'tugas.id_mengajar', '=', 'mengajars.id_mengajar') ->where('mengajars.id_kelas', $idKelas) ->select('tugas.id_tugas', 'tugas.deadline') ->get(); $expTugas = 0; foreach ($semuaTugasIdKelas as $tugas) { $deadline = Carbon::parse($tugas->deadline); $pengumpulan = DB::table('pengumpulan_tugas') ->where('id_tugas', $tugas->id_tugas) ->where('id_siswa', $idSiswa) ->first(); if ($pengumpulan && $pengumpulan->lampiran_tugas !== null) { $tanggalSubmit = Carbon::parse($pengumpulan->tanggal_submit); if ($tanggalSubmit->lessThanOrEqualTo($deadline)) { $expTugas += 10; // Tepat waktu → +10 } else { $hariTerlambat = $deadline->diffInDays($tanggalSubmit); // ← dibalik if ($hariTerlambat <= 1) { $expTugas += 5; // Terlambat ≤ 1 hari → +5 } elseif ($hariTerlambat <= 3) { $expTugas += 1; // Terlambat 2-3 hari → +3 } else { $expTugas -= 5; // Lewat grace period > 3 hari → dianggap tidak kumpul } } } else { // Belum mengumpulkan file sama sekali if ($now->greaterThan($deadline)) { // Deadline sudah lewat → penalti -5 $expTugas -= 5; } // Deadline belum lewat → tidak ada penalti, tidak ada poin } } // Total EXP tidak bisa negatif return max(0, $expChallenge + $expTugas); } /** * Ambil data leaderboard dengan EXP yang dihitung dinamis. */ private function getData(): array { $siswa = Auth::guard('siswa')->user(); $now = Carbon::now(); $semester = $now->month >= 7 ? '1' : '2'; $tahunAjaran = $now->month >= 7 ? $now->year . '/' . ($now->year + 1) : ($now->year - 1) . '/' . $now->year; // Ambil semua siswa di kelas yang sama $semuaSiswa = Siswa::where('id_kelas', $siswa->id_kelas)->get(); // Hitung EXP tiap siswa secara dinamis $leaderboard = $semuaSiswa->map(function ($s) { return [ 'id_siswa' => $s->id_siswa, 'nama' => $s->nama, 'nisn' => $s->nisn, 'foto_profil' => $s->foto_profil, 'foto_url' => $s->foto_profil ? Storage::url($s->foto_profil) : null, 'exp' => $this->hitungExpSiswa($s->id_siswa, $s->id_kelas), ]; }) ->sortByDesc('exp') ->values() ->map(function ($item, $i) { $item['ranking'] = $i + 1; return $item; }); // Sinkronisasi ke tabel leaderboards agar badge bisa dicek foreach ($leaderboard as $item) { Leaderboard::updateOrCreate( [ 'id_siswa' => $item['id_siswa'], 'id_kelas' => $siswa->id_kelas, 'semester' => $semester, 'tahun_ajaran' => $tahunAjaran, ], [ 'total_exp' => $item['exp'], 'ranking' => $item['ranking'], ] ); } $myRank = $leaderboard->firstWhere('id_siswa', $siswa->id_siswa); return compact('leaderboard', 'myRank', 'semester', 'tahunAjaran', 'siswa'); } public function index() { $data = $this->getData(); unset($data['siswa']); return view('siswa.leaderboard.index', $data); } /** * Endpoint JSON untuk polling real-time. */ public function json() { $data = $this->getData(); $siswa = $data['siswa']; // Evaluasi badge leaderboard berdasarkan data terbaru app(BadgeService::class)->checkLeaderboardBadges( $siswa->id_siswa, $siswa->id_kelas ); $badgeSiswa = SiswaBadge::with('badge') ->where('id_siswa', $siswa->id_siswa) ->whereHas('badge', fn($q) => $q->whereIn('syarat', ['leaderboard_top5', 'leaderboard_top1'])) ->get() ->map(fn($sb) => [ 'id_badge' => $sb->id_badge, 'nama_badge' => $sb->badge->nama_badge, 'deskripsi' => $sb->badge->deskripsi, 'icon_url' => asset($sb->badge->icon_badge), ]); unset($data['siswa']); $data['badgeSiswa'] = $badgeSiswa; return response()->json($data); } }