user(); $challenges = Challenge::whereHas('kelas', function ($q) use ($siswa) { $q->where('challenge_kelas.id_kelas', $siswa->id_kelas); }) ->with(['soal']) ->withCount('soal') ->orderBy('tenggat_waktu', 'asc') ->get(); $sudahDikerjakan = PesertaChallenge::where('id_siswa', $siswa->id_siswa) ->where('status', 'selesai') ->pluck('id_challenge') ->toArray(); return view('siswa.challenge.index', compact('challenges', 'sudahDikerjakan')); } public function kerjakan($id_challenge) { $siswa = Auth::guard('siswa')->user(); $challenge = Challenge::whereHas('kelas', function ($q) use ($siswa) { $q->where('challenge_kelas.id_kelas', $siswa->id_kelas); }) ->with('soal') ->findOrFail($id_challenge); $sudah = PesertaChallenge::where('id_siswa', $siswa->id_siswa) ->where('id_challenge', $id_challenge) ->where('status', 'selesai') ->exists(); if ($sudah) { return redirect()->route('siswa.challenge.hasil', $id_challenge); } if (Carbon::parse($challenge->tenggat_waktu)->isPast()) { return redirect()->route('siswa.challenge.index') ->with('error', 'Challenge ini sudah melewati tenggat waktu.'); } if ($challenge->soal->isEmpty()) { return redirect()->route('siswa.challenge.index') ->with('error', 'Challenge ini belum memiliki soal.'); } return view('siswa.challenge.kerjakan', compact('challenge')); } public function submit(Request $request, $id_challenge) { $siswa = Auth::guard('siswa')->user(); $challenge = Challenge::whereHas('kelas', function ($q) use ($siswa) { $q->where('challenge_kelas.id_kelas', $siswa->id_kelas); }) ->with('soal') ->findOrFail($id_challenge); $sudah = PesertaChallenge::where('id_siswa', $siswa->id_siswa) ->where('id_challenge', $id_challenge) ->where('status', 'selesai') ->exists(); if ($sudah) { return redirect()->route('siswa.challenge.hasil', $id_challenge); } if (Carbon::parse($challenge->tenggat_waktu)->isPast()) { return redirect()->route('siswa.challenge.index') ->with('error', 'Challenge sudah melewati tenggat waktu.'); } $jawaban = $request->input('jawaban', []); $totalExp = 0; $jawabanJson = []; foreach ($challenge->soal as $soal) { $jwb = $jawaban[$soal->id_soal] ?? null; $jawabanJson[$soal->id_soal] = $jwb; if ($jwb && strtoupper($jwb) === strtoupper($soal->jawaban_benar)) { $totalExp += $soal->exp_per_soal; } } $now = Carbon::now(); $semester = $now->month >= 7 ? '1' : '2'; $tahunAjaran = $now->month >= 7 ? $now->year . '/' . ($now->year + 1) : ($now->year - 1) . '/' . $now->year; // Snapshot badge sebelum submit — untuk deteksi badge baru $badgeSebelum = SiswaBadge::where('id_siswa', $siswa->id_siswa) ->pluck('id_badge') ->toArray(); DB::transaction(function () use ($siswa, $challenge, $jawabanJson, $totalExp, $semester, $tahunAjaran) { PesertaChallenge::create([ 'id_challenge' => $challenge->id_challenge, 'id_siswa' => $siswa->id_siswa, 'jawaban' => json_encode($jawabanJson), 'waktu_submit' => Carbon::now(), 'exp' => $totalExp, 'status' => 'selesai', ]); $lb = Leaderboard::firstOrCreate( [ 'id_siswa' => $siswa->id_siswa, 'id_kelas' => $siswa->id_kelas, 'semester' => $semester, 'tahun_ajaran' => $tahunAjaran, ], ['total_exp' => 0, 'ranking' => 0] ); $lb->increment('total_exp', $totalExp); Leaderboard::where('id_kelas', $siswa->id_kelas) ->where('semester', $semester) ->where('tahun_ajaran', $tahunAjaran) ->orderBy('total_exp', 'desc') ->get() ->each(fn($row, $i) => $row->update(['ranking' => $i + 1])); }); // Cek & berikan badge challenge app(BadgeService::class)->checkChallengeBadges($siswa->id_siswa); // Deteksi badge yang baru didapat (selisih sebelum & sesudah) $badgeSesudah = SiswaBadge::where('id_siswa', $siswa->id_siswa) ->pluck('id_badge') ->toArray(); $idBadgeBaru = array_diff($badgeSesudah, $badgeSebelum); // Simpan ke session agar bisa ditampilkan di halaman hasil if (!empty($idBadgeBaru)) { $badgeBaru = Badge::whereIn('id_badge', $idBadgeBaru)->get(); session()->flash('badge_baru', $badgeBaru); } return redirect()->route('siswa.challenge.hasil', $id_challenge); } public function hasil($id_challenge) { $siswa = Auth::guard('siswa')->user(); $challenge = Challenge::with('soal')->findOrFail($id_challenge); $peserta = PesertaChallenge::where('id_siswa', $siswa->id_siswa) ->where('id_challenge', $id_challenge) ->firstOrFail(); $jawabanSiswa = json_decode($peserta->jawaban, true) ?? []; $benar = 0; $salah = 0; foreach ($challenge->soal as $soal) { $jwb = $jawabanSiswa[$soal->id_soal] ?? null; strtoupper((string)$jwb) === strtoupper($soal->jawaban_benar) ? $benar++ : $salah++; } $totalSoal = $challenge->soal->count(); $persentase = $totalSoal > 0 ? round(($benar / $totalSoal) * 100) : 0; // Ambil badge baru dari session (hanya ada jika baru saja submit) $badgeBaru = session('badge_baru', collect()); return view('siswa.challenge.hasil', compact( 'challenge', 'peserta', 'jawabanSiswa', 'benar', 'salah', 'totalSoal', 'persentase', 'badgeBaru' )); } }