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', []); $jawabanJson = []; // ============================================= // PERUBAHAN: +1 poin per soal yang dijawab BENAR // (tidak lagi pakai exp_per_soal dari database) // ============================================= $totalExp = 0; 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 += 1; // +1 poin per soal benar } } $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 $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); // Update ranking semua siswa di kelas ini 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 baru $badgeSesudah = SiswaBadge::where('id_siswa', $siswa->id_siswa) ->pluck('id_badge') ->toArray(); $idBadgeBaru = array_diff($badgeSesudah, $badgeSebelum); 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; $badgeBaru = session('badge_baru', collect()); return view('siswa.challenge.hasil', compact( 'challenge', 'peserta', 'jawabanSiswa', 'benar', 'salah', 'totalSoal', 'persentase', 'badgeBaru' )); } }