'Senin', 'Tuesday' => 'Selasa', 'Wednesday' => 'Rabu', 'Thursday' => 'Kamis', 'Friday' => 'Jumat', 'Saturday' => 'Sabtu', 'Sunday' => 'Ahad', ]; // ── Tentukan mode & rentang tanggal ─────────────────────────────────── $mode = $request->get('mode', 'hari_ini'); if ($mode === 'minggu_ini') { $dari = now()->startOfWeek(Carbon::MONDAY)->format('Y-m-d'); $sampai = now()->endOfWeek(Carbon::SUNDAY)->format('Y-m-d'); $tanggal = null; } elseif ($mode === 'custom') { $dari = $request->get('dari', now()->subDays(6)->format('Y-m-d')); $sampai = $request->get('sampai', now()->format('Y-m-d')); if ($dari > $sampai) { [$dari, $sampai] = [$sampai, $dari]; } $tanggal = null; } else { $mode = 'hari_ini'; $tanggal = $request->get('tanggal', now()->format('Y-m-d')); $dari = $tanggal; $sampai = $tanggal; } $kategoris = KategoriKegiatan::select('kategori_id', 'nama_kategori')->orderBy('nama_kategori')->get(); $kategoriId = $request->get('kategori_id', ''); // ── Label periode ───────────────────────────────────────────────────── if ($mode === 'hari_ini') { $periodeLabel = Carbon::parse($dari)->locale('id')->isoFormat('dddd, D MMMM Y'); } elseif ($mode === 'minggu_ini') { $periodeLabel = Carbon::parse($dari)->locale('id')->isoFormat('D MMM') . ' – ' . Carbon::parse($sampai)->locale('id')->isoFormat('D MMM Y'); } else { $periodeLabel = Carbon::parse($dari)->locale('id')->isoFormat('D MMM Y') . ' – ' . Carbon::parse($sampai)->locale('id')->isoFormat('D MMM Y'); } // ═══════════════════════════════════════════════════════════════════ // MODE HARI INI — flat list kegiatan (paginated) // ═══════════════════════════════════════════════════════════════════ if ($mode === 'hari_ini') { $hariDipilih = $hariMap[Carbon::parse($dari)->format('l')] ?? null; $baseQuery = Kegiatan::with(['kategori', 'kelasKegiatan.kelompok']) ->when($hariDipilih, fn($q) => $q->where('hari', $hariDipilih)) ->when($kategoriId, fn($q) => $q->where('kategori_id', $kategoriId)) ->withCount([ 'absensis as total_absensi' => fn($q) => $q->whereDate('tanggal', $dari), 'absensis as hadir' => fn($q) => $q->where('status', 'Hadir')->whereDate('tanggal', $dari), 'absensis as terlambat' => fn($q) => $q->where('status', 'Terlambat')->whereDate('tanggal', $dari), 'absensis as izin' => fn($q) => $q->where('status', 'Izin')->whereDate('tanggal', $dari), 'absensis as sakit' => fn($q) => $q->where('status', 'Sakit')->whereDate('tanggal', $dari), 'absensis as alpa' => fn($q) => $q->where('status', 'Alpa')->whereDate('tanggal', $dari), 'absensis as pulang' => fn($q) => $q->where('status', 'Pulang')->whereDate('tanggal', $dari), ]) ->orderBy('waktu_mulai'); $kegiatans = (clone $baseQuery)->paginate(20)->appends($request->query()); $kegiatanPerTanggal = null; $allItems = (clone $baseQuery)->get(); $summary = [ 'hadir' => $allItems->sum('hadir') + $allItems->sum('terlambat'), 'terlambat' => $allItems->sum('terlambat'), 'izin' => $allItems->sum('izin'), 'sakit' => $allItems->sum('sakit'), 'alpa' => $allItems->sum('alpa'), 'total_absensi' => $allItems->sum('total_absensi'), 'jumlah_kegiatan' => $allItems->count(), 'jumlah_hari' => 1, ]; // ═══════════════════════════════════════════════════════════════════ // MODE MULTI-HARI — grouped by actual date // ═══════════════════════════════════════════════════════════════════ } else { $kegiatans = null; // Ambil semua tanggal yang ada absensi dalam range (terbaru dulu) $tanggalList = AbsensiKegiatan::selectRaw('DATE(tanggal) as tgl') ->whereDate('tanggal', '>=', $dari) ->whereDate('tanggal', '<=', $sampai) ->when($kategoriId, fn($q) => $q->whereHas('kegiatan', fn($qq) => $qq->where('kategori_id', $kategoriId))) ->groupBy('tgl') ->orderBy('tgl', 'desc') ->pluck('tgl'); // Untuk tiap tanggal: kegiatan + stats khusus tanggal itu saja $kegiatanPerTanggal = collect(); foreach ($tanggalList as $tgl) { $hariIndo = $hariMap[Carbon::parse($tgl)->format('l')] ?? null; $items = Kegiatan::with(['kategori', 'kelasKegiatan.kelompok']) ->when($hariIndo, fn($q) => $q->where('hari', $hariIndo)) ->when($kategoriId, fn($q) => $q->where('kategori_id', $kategoriId)) ->whereHas('absensis', fn($q) => $q->whereDate('tanggal', $tgl)) ->withCount([ 'absensis as total_absensi' => fn($q) => $q->whereDate('tanggal', $tgl), 'absensis as hadir' => fn($q) => $q->where('status', 'Hadir')->whereDate('tanggal', $tgl), 'absensis as terlambat' => fn($q) => $q->where('status', 'Terlambat')->whereDate('tanggal', $tgl), 'absensis as izin' => fn($q) => $q->where('status', 'Izin')->whereDate('tanggal', $tgl), 'absensis as sakit' => fn($q) => $q->where('status', 'Sakit')->whereDate('tanggal', $tgl), 'absensis as alpa' => fn($q) => $q->where('status', 'Alpa')->whereDate('tanggal', $tgl), 'absensis as pulang' => fn($q) => $q->where('status', 'Pulang')->whereDate('tanggal', $tgl), ]) ->orderBy('waktu_mulai') ->get(); if ($items->count() > 0) { $kegiatanPerTanggal[$tgl] = $items; } } $allKeg = $kegiatanPerTanggal->flatten(); $summary = [ 'hadir' => $allKeg->sum('hadir') + $allKeg->sum('terlambat'), 'terlambat' => $allKeg->sum('terlambat'), 'izin' => $allKeg->sum('izin'), 'sakit' => $allKeg->sum('sakit'), 'alpa' => $allKeg->sum('alpa'), 'total_absensi' => $allKeg->sum('total_absensi'), 'jumlah_kegiatan' => $allKeg->count(), 'jumlah_hari' => $kegiatanPerTanggal->count(), ]; } return view('admin.kegiatan.riwayat.index', compact( 'kegiatans', 'kegiatanPerTanggal', 'kategoris', 'summary', 'mode', 'dari', 'sampai', 'tanggal', 'periodeLabel', 'kategoriId' )); } /** * Detail riwayat per kegiatan — santri per kelas + filter */ public function show($id, Request $request) { $kegiatan = Kegiatan::with(['kategori', 'kelasKegiatan.kelompok']) ->findOrFail($id); // ── Ambil parameter periode dari index ──────────────────────────────── $mode = $request->get('mode', 'hari_ini'); $dari = $request->get('dari', now()->format('Y-m-d')); $sampai = $request->get('sampai', now()->format('Y-m-d')); $tanggal = $request->get('tanggal', now()->format('Y-m-d')); if ($mode === 'hari_ini') { $dari = $tanggal; $sampai = $tanggal; } // ── Query absensi ───────────────────────────────────────────────────── $query = AbsensiKegiatan::with(['santri.kelasSantri.kelas.kelompok']) ->where('kegiatan_id', $kegiatan->kegiatan_id) ->whereDate('tanggal', '>=', $dari) ->whereDate('tanggal', '<=', $sampai); if ($request->filled('id_santri')) $query->where('id_santri', $request->id_santri); if ($request->filled('id_kelas')) $query->whereHas('santri.kelasSantri', fn($q) => $q->where('id_kelas', $request->id_kelas)); if ($request->filled('status')) $query->where('status', $request->status); if ($request->filled('tanggal_spesifik')) $query->whereDate('tanggal', $request->tanggal_spesifik); $riwayats = $query->orderBy('tanggal', 'desc')->orderBy('waktu_absen')->paginate(50)->appends($request->query()); // ── Statistik ───────────────────────────────────────────────────────── $statsQuery = AbsensiKegiatan::where('kegiatan_id', $kegiatan->kegiatan_id) ->whereDate('tanggal', '>=', $dari)->whereDate('tanggal', '<=', $sampai); if ($request->filled('id_kelas')) { $statsQuery->whereHas('santri.kelasSantri', fn($q) => $q->where('id_kelas', $request->id_kelas)); } $stats = $statsQuery->select('status', DB::raw('count(*) as total')) ->groupBy('status')->pluck('total', 'status')->toArray(); // ── Total santri yang seharusnya hadir ──────────────────────────────── if ($kegiatan->kelasKegiatan->isEmpty()) { $totalSantriEligible = Santri::where('status', 'Aktif')->count(); } else { $kelasIds = $kegiatan->kelasKegiatan->pluck('id')->toArray(); $totalSantriEligible = Santri::where('status', 'Aktif') ->whereHas('kelasSantri', fn($q) => $q->whereIn('id_kelas', $kelasIds)) ->count(); if ($totalSantriEligible === 0) $totalSantriEligible = Santri::where('status', 'Aktif')->count(); } $totalRecorded = array_sum($stats); $hadirCount = ($stats['Hadir'] ?? 0) + ($stats['Terlambat'] ?? 0); $persenHadir = $totalSantriEligible > 0 ? round($hadirCount / $totalSantriEligible * 100, 1) : 0; // ── Filter dropdown ─────────────────────────────────────────────────── $santris = Santri::where('status', 'Aktif')->select('id_santri', 'nama_lengkap')->orderBy('nama_lengkap')->get(); $kelasList = Kelas::active()->ordered()->with('kelompok')->get(); // ── Label periode ───────────────────────────────────────────────────── if ($mode === 'hari_ini') { $periodeLabel = Carbon::parse($dari)->locale('id')->isoFormat('dddd, D MMMM Y'); } else { $periodeLabel = Carbon::parse($dari)->locale('id')->isoFormat('D MMM Y') . ' – ' . Carbon::parse($sampai)->locale('id')->isoFormat('D MMM Y'); } return view('admin.kegiatan.riwayat.show', compact( 'kegiatan', 'riwayats', 'santris', 'kelasList', 'stats', 'totalSantriEligible', 'totalRecorded', 'persenHadir', 'mode', 'dari', 'sampai', 'tanggal', 'periodeLabel' )); } /** * Riwayat kehadiran per santri — tabbed per kategori */ public function detailSantri($id_santri, Request $request) { $santri = Santri::where('id_santri', $id_santri)->firstOrFail(); // ── Statistik ringkasan (Terlambat = Hadir, bukan Alpa) ────────────── $rawStats = AbsensiKegiatan::where('id_santri', $id_santri) ->select('status', DB::raw('count(*) as total')) ->groupBy('status')->pluck('total', 'status')->toArray(); // Hadir efektif = Hadir + Terlambat $stats = $rawStats; $stats['_hadir_efektif'] = ($rawStats['Hadir'] ?? 0) + ($rawStats['Terlambat'] ?? 0); // ── Tren 30 hari — Hadir efektif (Hadir + Terlambat) ───────────────── $riwayat30Hari = AbsensiKegiatan::where('id_santri', $id_santri) ->whereDate('tanggal', '>=', now()->subDays(29)) ->select( DB::raw('DATE(tanggal) as tanggal'), DB::raw('SUM(CASE WHEN status IN ("Hadir","Terlambat") THEN 1 ELSE 0 END) as hadir'), DB::raw('COUNT(*) as total') ) ->groupBy('tanggal')->orderBy('tanggal', 'asc')->get(); // ── Daftar semua kategori yang punya riwayat untuk santri ini ───────── $kategoriList = AbsensiKegiatan::where('id_santri', $id_santri) ->join('kegiatans', 'absensi_kegiatans.kegiatan_id', '=', 'kegiatans.kegiatan_id') ->join('kategori_kegiatans', 'kegiatans.kategori_id', '=', 'kategori_kegiatans.kategori_id') ->select( 'kategori_kegiatans.kategori_id', 'kategori_kegiatans.nama_kategori', DB::raw('COUNT(*) as total'), DB::raw('SUM(CASE WHEN absensi_kegiatans.status IN ("Hadir","Terlambat") THEN 1 ELSE 0 END) as hadir_efektif') ) ->groupBy('kategori_kegiatans.kategori_id', 'kategori_kegiatans.nama_kategori') ->orderBy('kategori_kegiatans.nama_kategori') ->get(); // ── Tab aktif & per_page ─────────────────────────────────────────────── $activeKategori = $request->get('tab_kat', $kategoriList->first()?->kategori_id ?? ''); // per_page: 15 | 50 | 100 | 'all' (semua data, tanpa paginasi) $perPageRaw = $request->get('per_page', 15); $showAll = ($perPageRaw === 'all'); $perPage = $showAll ? 'all' : (in_array((int)$perPageRaw, [15, 50, 100]) ? (int)$perPageRaw : 15); // ── Riwayat untuk tab aktif ──────────────────────────────────────────── $riwayatsQuery = AbsensiKegiatan::with('kegiatan.kategori') ->where('id_santri', $id_santri) ->whereHas('kegiatan', fn($q) => $q->where('kategori_id', $activeKategori)) ->orderBy('tanggal', 'desc'); if ($showAll) { // Wrap sebagai LengthAwarePaginator manual agar view tetap konsisten $allItems = $riwayatsQuery->get(); $riwayats = new \Illuminate\Pagination\LengthAwarePaginator( $allItems, $allItems->count(), max($allItems->count(), 1), 1, ['path' => $request->url(), 'query' => $request->query()] ); } else { $riwayats = $riwayatsQuery->paginate($perPage)->appends($request->query()); } return view('admin.kegiatan.riwayat.detail-santri', compact( 'santri', 'stats', 'riwayat30Hari', 'riwayats', 'kategoriList', 'activeKategori', 'perPage', 'showAll' )); } public function edit(AbsensiKegiatan $riwayat) { $riwayat->load(['santri', 'kegiatan']); return view('admin.kegiatan.riwayat.edit', compact('riwayat')); } public function update(Request $request, AbsensiKegiatan $riwayat) { $validated = $request->validate([ 'status' => 'required|in:Hadir,Izin,Sakit,Alpa,Terlambat,Pulang', 'waktu_absen' => 'nullable|date_format:H:i', ]); $riwayat->update($validated); return redirect()->route('admin.riwayat-kegiatan.index')->with('success', 'Riwayat absensi berhasil diperbarui.'); } public function destroy(AbsensiKegiatan $riwayat) { $nama = $riwayat->santri->nama_lengkap; $riwayat->delete(); return redirect()->route('admin.riwayat-kegiatan.index')->with('success', "Riwayat absensi $nama berhasil dihapus."); } }