diff --git a/manajemen_mp/app/Http/Controllers/JadwalController.php b/manajemen_mp/app/Http/Controllers/JadwalController.php index 8bf1735..0a0c924 100644 --- a/manajemen_mp/app/Http/Controllers/JadwalController.php +++ b/manajemen_mp/app/Http/Controllers/JadwalController.php @@ -13,12 +13,26 @@ class JadwalController extends Controller public function index() { - // Mengambil data jadwal beserta relasi kolat dan pelatih - $data_jadwal = Jadwal::with(['kolat', 'pelatih'])->orderBy('tanggal', 'desc')->get(); + $data_jadwal = Jadwal::with(['kolat', 'pelatih']) + ->orderBy('tanggal', 'desc') + ->orderBy('jam_mulai', 'desc') + ->get(); return view('jadwal.jadwal', compact('data_jadwal')); } + public function konfirmasiSelesai($id) +{ + $jadwal = Jadwal::findOrFail($id); + + // Kita paksa ubah status ke 'selesai' + $jadwal->status = 'selesai'; + $jadwal->save(); + + return redirect()->route('jadwal.index') + ->with('success', 'Latihan ' . $jadwal->judul_kegiatan . ' telah dikonfirmasi selesai!'); +} + public function create() { @@ -70,19 +84,21 @@ public function edit($id) $query->where('nama_role', 'Pelatih'); })->get(); - return view('jadwal.edit', compact('jadwal', 'data_kolat', 'data_pelatih')); + return view('jadwal.editjadwal', compact('jadwal', 'data_kolat', 'data_pelatih')); } - public function update(Request $request, $id) { $jadwal = Jadwal::findOrFail($id); - $request->validate([ - 'judul_kegiatan' => 'required|string', - 'kolat_id' => 'required', - 'pelatih_id' => 'required', - 'tanggal' => 'required|date', + $request->validate([ + 'judul_kegiatan' => 'required|string|max:255', + 'kolat_id' => 'required|exists:kolat,id', + 'pelatih_id' => 'required|exists:anggotas,id', + 'jenis' => 'required|in:Rutin,Tambahan,Pengumuman', + 'tanggal' => 'required|date', + 'jam_mulai' => 'required', + 'lokasi' => 'required|string', ]); $jadwal->update($request->all()); @@ -100,4 +116,5 @@ public function destroy($id) return redirect()->route('jadwal.index') ->with('success', 'Jadwal telah dihapus dari sistem.'); } + } diff --git a/manajemen_mp/app/Http/Controllers/PelatihController.php b/manajemen_mp/app/Http/Controllers/PelatihController.php index 6befb87..4b265b6 100644 --- a/manajemen_mp/app/Http/Controllers/PelatihController.php +++ b/manajemen_mp/app/Http/Controllers/PelatihController.php @@ -75,7 +75,7 @@ public function store(Request $request) public function edit($id) { $pelatih = Anggota::findOrFail($id); - return view('pelatih.edit', compact('pelatih')); + return view('pelatih.editpelatih', compact('pelatih')); } public function update(Request $request, $id) diff --git a/manajemen_mp/app/Http/Controllers/PresensiController.php b/manajemen_mp/app/Http/Controllers/PresensiController.php index 48dca04..1351a48 100644 --- a/manajemen_mp/app/Http/Controllers/PresensiController.php +++ b/manajemen_mp/app/Http/Controllers/PresensiController.php @@ -4,7 +4,152 @@ use Illuminate\Http\Request; +// TAMBAHAN WAJIB: Memanggil Facades dan Model yang digunakan +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Auth; +use App\Models\Jadwal; +use App\Models\Presensi; +use App\Models\Anggota; + class PresensiController extends Controller { - // + public function index() + { + // Mengambil semua jadwal secara manual menggunakan Query Builder (JOIN) + $data_jadwal = DB::table('jadwals') + ->leftJoin('anggotas', 'jadwals.pelatih_id', '=', 'anggotas.id') + ->leftJoin('kolat', 'jadwals.kolat_id', '=', 'kolat.id') // Sesuaikan jika nama tabel di database kamu adalah 'kolat' + ->select( + 'jadwals.*', + 'anggotas.nama_lengkap as nama_pelatih', + 'kolat.nama_kolat as nama_kolat' + ) + ->orderBy('jadwals.tanggal', 'desc') + ->get(); + + // Pastikan nama foldernya konsisten (admin atau pengurus) + return view('presensi.pengurus.index', compact('data_jadwal')); + } + + public function kehadiran($jadwal_id) +{ + // Variabel dibuat dengan nama $jadwal (tunggal) + $jadwal = Jadwal::with(['kolat', 'pelatih'])->findOrFail($jadwal_id); + + $data_presensi = Presensi::with('anggota', 'pelatihVerifikator') + ->where('jadwal_id', $jadwal_id) + ->get(); + + $daftar_anggota = Anggota::where('kolat_id', $jadwal->kolat_id) + ->where('status', 'Aktif') + ->get(); + + // Pastikan di sini tulisannya 'jadwal' (sesuai nama variabel di atas) + return view('presensi.pengurus.kehadiran', compact('jadwal', 'data_presensi', 'daftar_anggota')); +} + + /** + * 2. Proses Pelatih klik "Konfirmasi Hadir" + */ + public function konfirmasi($presensi_id) + { + $presensi = Presensi::findOrFail($presensi_id); + + // Ubah status menjadi terverifikasi dan catat ID Pelatih yang klik + $presensi->update([ + 'is_verified' => true, + 'verified_by' => Auth::user()->id + ]); + + return redirect()->back()->with('success', 'Kehadiran ' . $presensi->anggota->nama_lengkap . ' berhasil dikonfirmasi!'); + } + + /** + * 3. Proses Pelatih input manual dari Modal (Kasus Lupa HP) + */ + public function storeManual(Request $request) + { + // Validasi input dari form modal + $request->validate([ + 'jadwal_id' => 'required|exists:jadwals,id', + 'anggota_id' => 'required|exists:anggotas,id', + ]); + + // Cek apakah anggota tersebut sudah absen sebelumnya agar tidak ada data ganda (double input) + $sudah_absen = Presensi::where('jadwal_id', $request->jadwal_id) + ->where('anggota_id', $request->anggota_id) + ->first(); + + if ($sudah_absen) { + return redirect()->back()->with('error', 'Anggota tersebut sudah tercatat di daftar kehadiran!'); + } + + // Simpan data presensi baru + // Karena diinput langsung oleh pelatih, is_verified otomatis bernilai true + Presensi::create([ + 'jadwal_id' => $request->jadwal_id, + 'anggota_id' => $request->anggota_id, + 'status' => 'Hadir', + 'waktu_presensi' => now(), // Waktu dicatat saat form disubmit + 'is_verified' => true, // Langsung Sah + 'verified_by' => Auth::user()->id + ]); + + return redirect()->back()->with('success', 'Presensi manual berhasil ditambahkan!'); + } + + + public function indexAnggota() + { + $now = \Carbon\Carbon::now('Asia/Jakarta'); + $hari_ini = $now->format('Y-m-d'); + $user = Auth::user(); + + // 1. Ambil jadwal latihan yang terjadi HARI INI sesuai dengan Kolat si Anggota + // Asumsinya di tabel anggotas (users) ada kolom kolat_id + $jadwal_hari_ini = Jadwal::with('pelatih') + ->where('tanggal', $hari_ini) + ->where('kolat_id', $user->kolat_id) + ->orderBy('jam_mulai', 'asc') + ->get(); + + // 2. Cek apakah anggota ini sudah absen di jadwal tersebut + // Menggunakan pluck() untuk mengambil ID jadwal hari ini saja + $presensi_saya = Presensi::where('anggota_id', $user->id) + ->whereIn('jadwal_id', $jadwal_hari_ini->pluck('id')) + ->get() + ->keyBy('jadwal_id'); // Jadikan ID jadwal sebagai key array agar mudah dicek di View + + return view('presensi.anggota.index', compact('jadwal_hari_ini', 'presensi_saya', 'now')); + } + + public function storeMandiri(Request $request) + { + $request->validate([ + 'jadwal_id' => 'required|exists:jadwals,id', + ]); + + $user = Auth::user(); + + // Cek agar tidak bisa klik absen 2 kali (Double submit) + $sudah_absen = Presensi::where('jadwal_id', $request->jadwal_id) + ->where('anggota_id', $user->id) + ->exists(); + + if ($sudah_absen) { + return redirect()->back()->with('error', 'Kamu sudah melakukan absensi untuk jadwal ini!'); + } + + // Simpan data presensi dengan status is_verified = false (Menunggu ACC) + Presensi::create([ + 'jadwal_id' => $request->jadwal_id, + 'anggota_id' => $user->id, + 'status' => 'Hadir', + 'waktu_presensi' => now(), + 'is_verified' => false, // Belum Sah, butuh ACC Pelatih + 'verified_by' => null + ]); + + return redirect()->back()->with('success', 'Berhasil! Kehadiranmu sedang menunggu konfirmasi Pelatih.'); + } } diff --git a/manajemen_mp/app/Models/Presensi.php b/manajemen_mp/app/Models/Presensi.php index 168c475..658cd9f 100644 --- a/manajemen_mp/app/Models/Presensi.php +++ b/manajemen_mp/app/Models/Presensi.php @@ -9,12 +9,14 @@ class Presensi extends Model { use HasFactory; protected $fillable = [ - 'jadwal_id', - 'anggota_id', - 'status', - 'keterangan', - 'waktu_presensi' - ]; + 'jadwal_id', + 'anggota_id', + 'status', + 'keterangan', + 'waktu_presensi', + 'is_verified', + 'verified_by' +]; // Relasi: Presensi ini untuk jadwal yang mana? public function jadwal() diff --git a/manajemen_mp/config/app.php b/manajemen_mp/config/app.php index 9207160..3556121 100644 --- a/manajemen_mp/config/app.php +++ b/manajemen_mp/config/app.php @@ -70,7 +70,7 @@ | */ - 'timezone' => 'UTC', + 'timezone' => 'Asia/Jakarta', /* |-------------------------------------------------------------------------- diff --git a/manajemen_mp/database/migrations/2026_04_13_165708_create_presensis_table.php b/manajemen_mp/database/migrations/2026_04_13_165708_create_presensis_table.php index cacba96..6a7a632 100644 --- a/manajemen_mp/database/migrations/2026_04_13_165708_create_presensis_table.php +++ b/manajemen_mp/database/migrations/2026_04_13_165708_create_presensis_table.php @@ -12,14 +12,22 @@ public function up(): void { Schema::create('presensis', function (Blueprint $table) { - $table->id(); - $table->foreignId('jadwal_id')->constrained('jadwals')->onDelete('cascade'); - $table->foreignId('anggota_id')->constrained('anggotas')->onDelete('cascade'); - $table->enum('status', ['Hadir', 'Izin', 'Sakit', 'Alfa'])->default('Alfa'); - $table->text('keterangan')->nullable(); // Alasan izin/sakit - $table->timestamp('waktu_presensi')->nullable(); // Catat jam tepatnya dia absen - $table->timestamps(); - }); + $table->id(); + $table->foreignId('jadwal_id')->constrained('jadwals')->onDelete('cascade'); + $table->foreignId('anggota_id')->constrained('anggotas')->onDelete('cascade'); + $table->enum('status', ['Hadir', 'Izin', 'Sakit', 'Alfa'])->default('Alfa'); + $table->text('keterangan')->nullable(); + $table->timestamp('waktu_presensi')->nullable(); + + // TAMBAHKAN 2 BARIS INI: + $table->boolean('is_verified')->default(false); // Untuk tahu sudah di-ACC pelatih atau belum + $table->unsignedBigInteger('verified_by')->nullable(); // Untuk catat ID pelatih yang meng-ACC + + $table->timestamps(); + + // Tambahkan foreign key untuk verified_by + $table->foreign('verified_by')->references('id')->on('anggotas'); + }); } /** diff --git a/manajemen_mp/database/migrations/2026_04_20_163145_add_status_to_jadwals_table.php b/manajemen_mp/database/migrations/2026_04_20_163145_add_status_to_jadwals_table.php new file mode 100644 index 0000000..5d714ca --- /dev/null +++ b/manajemen_mp/database/migrations/2026_04_20_163145_add_status_to_jadwals_table.php @@ -0,0 +1,30 @@ +string('status')->default('pending')->after('jenis'); + }); + + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('jadwals', function (Blueprint $table) { + $table->dropColumn('status'); + }); + } +}; diff --git a/manajemen_mp/database/migrations/2026_04_22_125908_add_report_to_jadwals.php b/manajemen_mp/database/migrations/2026_04_22_125908_add_report_to_jadwals.php new file mode 100644 index 0000000..6cb0e08 --- /dev/null +++ b/manajemen_mp/database/migrations/2026_04_22_125908_add_report_to_jadwals.php @@ -0,0 +1,31 @@ +string('foto_bukti')->nullable()->after('lokasi'); + // Menambah kolom untuk materi/catatan latihan + $table->text('catatan_latihan')->nullable()->after('foto_bukti'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('jadwals', function (Blueprint $table) { + $table->dropColumn(['foto_bukti', 'catatan_latihan']); + }); + } +}; diff --git a/manajemen_mp/database/seeders/DatabaseSeeder.php b/manajemen_mp/database/seeders/DatabaseSeeder.php index a9f4519..3ae00ff 100644 --- a/manajemen_mp/database/seeders/DatabaseSeeder.php +++ b/manajemen_mp/database/seeders/DatabaseSeeder.php @@ -12,6 +12,9 @@ class DatabaseSeeder extends Seeder */ public function run(): void { + $this->call([ + RoleSeeder::class, + ]); // \App\Models\User::factory(10)->create(); // \App\Models\User::factory()->create([ diff --git a/manajemen_mp/database/seeders/RoleSeeder.php b/manajemen_mp/database/seeders/RoleSeeder.php new file mode 100644 index 0000000..4f9efd7 --- /dev/null +++ b/manajemen_mp/database/seeders/RoleSeeder.php @@ -0,0 +1,28 @@ +insert([ + 'nama_role' => $role, + 'slug' => Str::slug($role), + 'created_at' => now(), + 'updated_at' => now(), + ]); + } + } +} diff --git a/manajemen_mp/resources/views/anggota/editanggota.blade.php b/manajemen_mp/resources/views/anggota/editanggota.blade.php index 1bf9f50..fc3d108 100644 --- a/manajemen_mp/resources/views/anggota/editanggota.blade.php +++ b/manajemen_mp/resources/views/anggota/editanggota.blade.php @@ -1,181 +1,221 @@ @extends('layout.app') @section('content') -
Perbarui informasi identitas atau legalitas SK anggota di bawah ini.
-Perbarui informasi identitas atau legalitas SK anggota di bawah ini.
+