diff --git a/app/Http/Controllers/Siswa/DashboardController.php b/app/Http/Controllers/Siswa/DashboardController.php index dc33d7a..ac35bb0 100644 --- a/app/Http/Controllers/Siswa/DashboardController.php +++ b/app/Http/Controllers/Siswa/DashboardController.php @@ -6,18 +6,15 @@ use Illuminate\Support\Facades\Auth; use Carbon\Carbon; -// Sesuaikan nama model-model ini dengan yang kamu punya use App\Models\Tugas; -use App\Models\TugasSiswa; // tabel pengumpulan tugas +use App\Models\PengumpulanTugas; use App\Models\Challenge; -use App\Models\ChallengeSiswa; // tabel progress challenge siswa +use App\Models\PesertaChallenge; +use App\Models\Leaderboard; use App\Models\Siswa; class DashboardController extends Controller { - /** - * Pastikan hanya siswa yang sudah login yang bisa akses. - */ public function __construct() { $this->middleware('auth:siswa'); @@ -29,72 +26,83 @@ public function index() $siswa = Auth::guard('siswa')->user(); // ============================================= - // 1. TUGAS — ambil tugas yang belum dikumpulkan - // dan deadline-nya belum lewat, urutkan by deadline + // 1. TUGAS — yang belum dikumpulkan siswa ini + // dan deadline belum lewat // ============================================= - $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); - }) + + // id_tugas yang sudah dikumpulkan siswa ini + $sudahDikumpulkan = PengumpulanTugas::where('id_siswa', $siswa->id_siswa) + ->pluck('id_tugas'); + + // Tugas untuk kelas siswa yang belum dikumpulkan + $tugasRaw = Tugas::with(['mengajar.mapel']) + ->whereNotIn('id_tugas', $sudahDikumpulkan) ->where('deadline', '>=', Carbon::now()) + ->whereHas('mengajar', function ($q) use ($siswa) { + $q->where('id_kelas', $siswa->id_kelas); + }) ->orderBy('deadline', 'asc') - ->take(5) // tampilkan maks 5 tugas di dashboard + ->take(5) ->get(); - // Kelompokkan tugas berdasarkan tanggal deadline + // Kelompokkan per tanggal deadline $tugasList = []; foreach ($tugasRaw as $tugas) { $tgl = Carbon::parse($tugas->deadline) ->locale('id') - ->isoFormat('dddd, D MMMM YYYY'); // contoh: "Sabtu, 10 Mei 2025" + ->isoFormat('dddd, D MMMM YYYY'); + + $namaMapel = optional(optional($tugas->mengajar)->mapel)->nama_mapel ?? '-'; $tugasList[$tgl][] = [ 'jam' => Carbon::parse($tugas->deadline)->format('H.i'), - 'nama' => $tugas->judul, - // sesuaikan nama kolom dengan model kamu - 'mapel' => 'Belum · ' . ($tugas->mataPelajaran->nama ?? '-'), + 'nama' => $tugas->judul_tugas, + 'mapel' => 'Belum · ' . $namaMapel, ]; } // ============================================= // 2. CHALLENGE MINGGUAN // ============================================= - $startMingguIni = Carbon::now()->startOfWeek(); - $endMingguIni = Carbon::now()->endOfWeek(); + $startMinggu = Carbon::now()->startOfWeek(); + $endMinggu = Carbon::now()->endOfWeek(); - // Total challenge aktif minggu ini - $challengeTotal = Challenge::whereBetween('created_at', [$startMingguIni, $endMingguIni]) - ->where('is_active', true) + // Challenge untuk kelas siswa yang masih aktif minggu ini + $challengeTotal = Challenge::whereHas('kelas', function ($q) use ($siswa) { + $q->where('challenge_kelas.id_kelas', $siswa->id_kelas); + }) + ->where('tenggat_waktu', '>=', Carbon::now()) + ->whereBetween('created_at', [$startMinggu, $endMinggu]) ->count(); - // Challenge yang sudah diselesaikan siswa minggu ini - $challengeDone = ChallengeSiswa::where('siswa_id', $siswa->id) + // Challenge yang sudah selesai dikerjakan siswa minggu ini + $challengeDone = PesertaChallenge::where('id_siswa', $siswa->id_siswa) ->where('status', 'selesai') - ->whereBetween('created_at', [$startMingguIni, $endMingguIni]) + ->whereBetween('waktu_submit', [$startMinggu, $endMinggu]) ->count(); // ============================================= - // 3. TUGAS SELESAI MINGGU INI (untuk speech bubble mascot) + // 3. TUGAS SELESAI MINGGU INI (mascot speech bubble) // ============================================= - $tugasSelesai = TugasSiswa::where('siswa_id', $siswa->id) - ->whereBetween('created_at', [$startMingguIni, $endMingguIni]) + $tugasSelesai = PengumpulanTugas::where('id_siswa', $siswa->id_siswa) + ->whereIn('status', ['dikumpulkan', 'terlambat']) + ->whereBetween('tanggal_submit', [$startMinggu, $endMinggu]) ->count(); // ============================================= - // 4. LEADERBOARD — top 3 siswa berdasarkan total EXP - // Asumsi: kolom 'exp' ada di tabel siswa - // Sesuaikan jika EXP disimpan di tabel lain + // 4. LEADERBOARD — top 3 kelas siswa yang login // ============================================= - $leaderboardRaw = Siswa::orderBy('exp', 'desc') + $leaderboardRaw = Leaderboard::with('siswa') + ->where('id_kelas', $siswa->id_kelas) + ->orderBy('total_exp', 'desc') ->take(3) ->get(); $leaderboard = $leaderboardRaw->map(function ($item, $index) { return [ 'rank' => $index + 1, - 'nama' => $item->nama, - 'exp' => $item->exp, + 'nama' => optional($item->siswa)->nama ?? '-', + 'exp' => $item->total_exp, ]; })->toArray(); diff --git a/app/Http/Controllers/Siswa/MateriController.php b/app/Http/Controllers/Siswa/MateriController.php new file mode 100644 index 0000000..748748d --- /dev/null +++ b/app/Http/Controllers/Siswa/MateriController.php @@ -0,0 +1,59 @@ +middleware('auth:siswa'); + } + + /** + * Halaman daftar mata pelajaran siswa + */ + public function index() + { + $siswa = Auth::guard('siswa')->user(); + + // Ambil semua mapel yang diajarkan di kelas siswa ini + $mapelList = Mengajar::with(['mapel', 'guru']) + ->where('id_kelas', $siswa->id_kelas) + ->get() + ->map(function ($mengajar) { + return [ + 'id_mengajar' => $mengajar->id_mengajar, + 'nama_mapel' => optional($mengajar->mapel)->nama_mapel ?? '-', + 'nama_guru' => optional($mengajar->guru)->nama ?? '-', + 'jumlah_materi' => Materi::where('id_mengajar', $mengajar->id_mengajar)->count(), + ]; + }); + + return view('siswa.materi.index', compact('mapelList')); + } + + /** + * Halaman daftar materi per mata pelajaran + */ + public function show($id_mengajar) + { + $siswa = Auth::guard('siswa')->user(); + + // Pastikan mengajar ini memang untuk kelas siswa + $mengajar = Mengajar::with(['mapel', 'guru']) + ->where('id_mengajar', $id_mengajar) + ->where('id_kelas', $siswa->id_kelas) + ->firstOrFail(); + + $materiList = Materi::where('id_mengajar', $id_mengajar) + ->orderBy('tanggal_upload', 'desc') + ->get(); + + return view('siswa.materi.show', compact('mengajar', 'materiList')); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Siswa/TugasController.php b/app/Http/Controllers/Siswa/TugasController.php new file mode 100644 index 0000000..67463cf --- /dev/null +++ b/app/Http/Controllers/Siswa/TugasController.php @@ -0,0 +1,152 @@ +middleware('auth:siswa'); + } + + /** + * Daftar semua tugas untuk kelas siswa + */ + public function index() + { + $siswa = Auth::guard('siswa')->user(); + + // Ambil semua tugas untuk kelas siswa + $semuaTugas = Tugas::with(['mengajar.mapel', 'mengajar.guru']) + ->whereHas('mengajar', function ($q) use ($siswa) { + $q->where('id_kelas', $siswa->id_kelas); + }) + ->orderBy('deadline', 'asc') + ->get(); + + // Tandai status tiap tugas untuk siswa ini + $tugasList = $semuaTugas->map(function ($tugas) use ($siswa) { + $pengumpulan = PengumpulanTugas::where('id_tugas', $tugas->id_tugas) + ->where('id_siswa', $siswa->id_siswa) + ->first(); + + $now = Carbon::now(); + $deadline = Carbon::parse($tugas->deadline); + + if ($pengumpulan) { + $status = $pengumpulan->status; // 'dikumpulkan' atau 'terlambat' + } else { + $status = $now->greaterThan($deadline) ? 'terlambat' : 'belum'; + } + + return [ + 'id_tugas' => $tugas->id_tugas, + 'judul' => $tugas->judul_tugas, + 'keterangan' => $tugas->keterangan, + 'deadline' => $deadline, + 'nama_mapel' => optional(optional($tugas->mengajar)->mapel)->nama_mapel ?? '-', + 'nama_guru' => optional(optional($tugas->mengajar)->guru)->nama ?? '-', + 'status' => $status, + 'sudah_kumpul'=> !is_null($pengumpulan), + 'lampiran' => $pengumpulan?->lampiran_tugas, + 'exp' => $pengumpulan?->exp ?? 0, + ]; + }); + + // Kelompokkan: belum & pending vs sudah dikumpulkan + $tugasBelum = $tugasList->filter(fn($t) => !$t['sudah_kumpul'] && $t['status'] !== 'terlambat'); + $tugasTerlambat = $tugasList->filter(fn($t) => !$t['sudah_kumpul'] && $t['status'] === 'terlambat'); + $tugasSelesai = $tugasList->filter(fn($t) => $t['sudah_kumpul']); + + return view('siswa.tugas.index', compact('tugasBelum', 'tugasTerlambat', 'tugasSelesai')); + } + + /** + * Detail tugas + form submit + */ + public function show($id_tugas) + { + $siswa = Auth::guard('siswa')->user(); + + $tugas = Tugas::with(['mengajar.mapel', 'mengajar.guru']) + ->whereHas('mengajar', function ($q) use ($siswa) { + $q->where('id_kelas', $siswa->id_kelas); + }) + ->where('id_tugas', $id_tugas) + ->firstOrFail(); + + $pengumpulan = PengumpulanTugas::where('id_tugas', $id_tugas) + ->where('id_siswa', $siswa->id_siswa) + ->first(); + + $sudahKumpul = !is_null($pengumpulan); + $terlambat = Carbon::now()->greaterThan(Carbon::parse($tugas->deadline)); + + return view('siswa.tugas.show', compact('tugas', 'pengumpulan', 'sudahKumpul', 'terlambat')); + } + + /** + * Submit / upload jawaban tugas + */ + public function submit(Request $request, $id_tugas) + { + $siswa = Auth::guard('siswa')->user(); + + $request->validate([ + 'lampiran_tugas' => 'required|file|mimes:pdf,doc,docx,jpg,jpeg,png|max:5120', + ], [ + 'lampiran_tugas.required' => 'File jawaban wajib diupload.', + 'lampiran_tugas.mimes' => 'Format file harus pdf, doc, docx, jpg, atau png.', + 'lampiran_tugas.max' => 'Ukuran file maksimal 5MB.', + ]); + + // Cek tugas valid untuk kelas siswa + $tugas = Tugas::whereHas('mengajar', function ($q) use ($siswa) { + $q->where('id_kelas', $siswa->id_kelas); + }) + ->where('id_tugas', $id_tugas) + ->firstOrFail(); + + // Cek sudah dikumpulkan belum + $sudahAda = PengumpulanTugas::where('id_tugas', $id_tugas) + ->where('id_siswa', $siswa->id_siswa) + ->exists(); + + if ($sudahAda) { + return back()->with('error', 'Kamu sudah mengumpulkan tugas ini.'); + } + + // Upload file + $file = $request->file('lampiran_tugas'); + $filename = 'tugas_' . $siswa->id_siswa . '_' . $id_tugas . '_' . time() . '.' . $file->getClientOriginalExtension(); + $path = $file->storeAs('pengumpulan_tugas', $filename, 'public'); + + // Tentukan status: terlambat atau dikumpulkan + $now = Carbon::now(); + $deadline = Carbon::parse($tugas->deadline); + $status = $now->greaterThan($deadline) ? 'terlambat' : 'dikumpulkan'; + + PengumpulanTugas::create([ + 'id_tugas' => $id_tugas, + 'id_siswa' => $siswa->id_siswa, + 'lampiran_tugas' => $path, + 'tanggal_submit' => $now, + 'exp' => 0, // exp diberikan guru saat menilai + 'status' => $status, + ]); + + $pesan = $status === 'terlambat' + ? 'Tugas berhasil dikumpulkan (terlambat).' + : 'Tugas berhasil dikumpulkan! 🎉'; + + return redirect()->route('siswa.tugas.index')->with('success', $pesan); + } +} \ No newline at end of file diff --git a/app/Models/Materi.php b/app/Models/Materi.php index 4f1b5d3..fd8be96 100644 --- a/app/Models/Materi.php +++ b/app/Models/Materi.php @@ -9,7 +9,7 @@ class Materi extends Model { use HasFactory; - protected $table = 'materis'; + protected $table = 'materis'; protected $primaryKey = 'id_materi'; protected $fillable = [ @@ -19,4 +19,13 @@ class Materi extends Model 'deskripsi', 'tanggal_upload', ]; + + protected $casts = [ + 'tanggal_upload' => 'datetime', + ]; + + public function mengajar() + { + return $this->belongsTo(Mengajar::class, 'id_mengajar', 'id_mengajar'); + } } \ No newline at end of file diff --git a/app/Models/Tugas.php b/app/Models/Tugas.php index 9302c06..8ddd25e 100644 --- a/app/Models/Tugas.php +++ b/app/Models/Tugas.php @@ -9,7 +9,7 @@ class Tugas extends Model { use HasFactory; - protected $table = 'tugas'; + protected $table = 'tugas'; protected $primaryKey = 'id_tugas'; protected $fillable = [ @@ -18,4 +18,24 @@ class Tugas extends Model 'keterangan', 'deadline', ]; + + protected $casts = [ + 'deadline' => 'datetime', + ]; + + /** + * Tugas dibuat melalui relasi mengajar (guru - mapel - kelas) + */ + public function mengajar() + { + return $this->belongsTo(Mengajar::class, 'id_mengajar', 'id_mengajar'); + } + + /** + * Satu tugas bisa punya banyak pengumpulan dari siswa + */ + public function pengumpulanTugas() + { + return $this->hasMany(PengumpulanTugas::class, 'id_tugas', 'id_tugas'); + } } \ No newline at end of file diff --git a/resources/views/siswa/dashboard.blade.php b/resources/views/siswa/dashboard.blade.php index 71b468b..416d0e4 100644 --- a/resources/views/siswa/dashboard.blade.php +++ b/resources/views/siswa/dashboard.blade.php @@ -1,4 +1,4 @@ -@extends('layouts.siswa.app') +@extends('siswa.layouts.app') @section('title', 'Dashboard Siswa') @@ -319,7 +319,7 @@
Belum ada mata pelajaran untuk kelasmu.
+{{ $mapel['nama_mapel'] }}
+{{ $mapel['nama_guru'] }}
+{{ optional($mengajar->mapel)->nama_mapel ?? '-' }}
+Guru: {{ optional($mengajar->guru)->nama ?? '-' }} • {{ $materiList->count() }} Materi
+Belum ada materi yang diupload untuk mata pelajaran ini.
+{{ $materi->judul_materi }}
+ + @if($materi->deskripsi) +{{ $materi->deskripsi }}
+ @endif +Semua tugas sudah dikerjakan!
+{{ $tugas['judul'] }}
+ +Deadline
+{{ $tugas['deadline']->format('d M Y H:i') }}
+ Belum +Tidak ada tugas terlambat!
+{{ $tugas['judul'] }}
+ +Deadline lewat
+{{ $tugas['deadline']->format('d M Y H:i') }}
+ Terlambat +Belum ada tugas yang dikumpulkan.
+{{ $tugas['judul'] }}
+ +Tugas sudah dikumpulkan!
++ Dikumpulkan pada {{ \Carbon\Carbon::parse($pengumpulan->tanggal_submit)->format('d M Y, H:i') }} + • Status: {{ ucfirst($pengumpulan->status) }} +
+ @if($pengumpulan->exp > 0) ++ EXP akan diberikan setelah guru menilai tugasmu. +
+ @endif + + @if($pengumpulan->lampiran_tugas) + + 📎 Lihat File yang Dikumpulkan + + @endif +📤 Upload Jawaban
+ + +