MIF_E31230356/app/Http/Controllers/Siswa/ChallengeController.php

197 lines
6.8 KiB
PHP

<?php
namespace App\Http\Controllers\Siswa;
use App\Http\Controllers\Controller;
use App\Models\Badge;
use App\Models\Challenge;
use App\Models\PesertaChallenge;
use App\Models\Leaderboard;
use App\Models\SiswaBadge;
use App\Services\BadgeService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class ChallengeController extends Controller
{
public function index()
{
$siswa = Auth::guard('siswa')->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'
));
}
}