This commit is contained in:
HelgaFaisa 2026-03-19 06:39:44 +07:00
parent 46ded0ee5c
commit 1332db7373
124 changed files with 7211 additions and 22166 deletions

View File

@ -11,7 +11,7 @@ LOG_LEVEL=debug
DB_CONNECTION=mysql DB_CONNECTION=mysql
DB_HOST=127.0.0.1 DB_HOST=127.0.0.1
DB_PORT=3306 DB_PORT=3306
DB_DATABASE=sim_santri DB_DATABASE=laravel
DB_USERNAME=root DB_USERNAME=root
DB_PASSWORD= DB_PASSWORD=

View File

@ -23,7 +23,6 @@ public function __construct(private EpposGLogParser $parser) {}
// ────────────────────────────────────────────────────────── // ──────────────────────────────────────────────────────────
public function index() public function index()
{ {
// Hitung yang benar-benar belum punya santri (id_santri null atau kosong)
$belumMapping = MesinSantriMapping::where('is_active', true) $belumMapping = MesinSantriMapping::where('is_active', true)
->where(function ($q) { ->where(function ($q) {
$q->whereNull('id_santri')->orWhere('id_santri', ''); $q->whereNull('id_santri')->orWhere('id_santri', '');
@ -35,9 +34,9 @@ public function index()
} }
// ────────────────────────────────────────────────────────── // ──────────────────────────────────────────────────────────
// PREVIEW — hanya POST // PREVIEW — POST
// Setelah proses selesai, redirect ke showPreview (GET) // Proses file GLog, simpan hasil ke session, redirect ke
// Ini mencegah error "MethodNotAllowed" saat user refresh halaman preview // showPreview (GET). PRG pattern agar refresh tidak error.
// ────────────────────────────────────────────────────────── // ──────────────────────────────────────────────────────────
public function preview(Request $request) public function preview(Request $request)
{ {
@ -49,8 +48,11 @@ public function preview(Request $request)
'conflict_strategy' => 'nullable|in:mesin,exist,manual', 'conflict_strategy' => 'nullable|in:mesin,exist,manual',
]); ]);
$tolSebelum = (int)($request->tol_sebelum ?? 15); // ── Baca toleransi PERSIS dari form (bukan hardcode) ──
$tolSesudah = (int)($request->tol_sesudah ?? 10); // Jika field tidak dikirim (misal: disable JS), fallback ke nilai
// default form (15 dan 10) yang sama persis dengan default di index.blade.php
$tolSebelum = (int)($request->input('tol_sebelum', 15));
$tolSesudah = (int)($request->input('tol_sesudah', 10));
$isiAlpa = $request->has('isi_alpa'); $isiAlpa = $request->has('isi_alpa');
$conflictStrategy = $request->input('conflict_strategy', 'mesin'); $conflictStrategy = $request->input('conflict_strategy', 'mesin');
@ -70,29 +72,18 @@ public function preview(Request $request)
); );
} }
// ── Ambil infoData dari mapping yang sudah ada ──────── // ── Bangun infoData dari mapping yang sudah ada ───────
// Kita bangun infoData dari tabel mesin_santri_mappings
// sehingga tidak perlu upload INFO.XLS lagi
$mappingAll = MesinSantriMapping::where('is_active', true)->get(); $mappingAll = MesinSantriMapping::where('is_active', true)->get();
$infoData = ['shifts' => [], 'jadwal' => []];
// Bangun struktur infoData['jadwal'] dari mapping yang ada
// shifts dikosongkan karena matching pakai jam langsung
$infoData = [
'shifts' => [],
'jadwal' => [],
];
foreach ($mappingAll as $m) { foreach ($mappingAll as $m) {
$infoData['jadwal'][$m->id_mesin] = [ $infoData['jadwal'][$m->id_mesin] = [
'nama' => $m->nama_mesin ?? '', 'nama' => $m->nama_mesin ?? '',
'dept' => $m->dept_mesin ?? '', 'dept' => $m->dept_mesin ?? '',
'shift' => 1, // default, tidak dipakai untuk matching jam 'shift' => 1,
]; ];
} }
// ── Kegiatan dari DB ────────────────────────────────── // ── Kegiatan dari DB ──────────────────────────────────
// Ambil semua kegiatan — waktu_selesai boleh null, pakai waktu_mulai sebagai fallback
// getRawOriginal() bypass Eloquent cast (datetime:H:i → Carbon)
// sehingga kita dapat string murni "04:00:00" dari DB, lalu substr → "04:00"
$kegiatans = Kegiatan::orderBy('hari')->orderBy('waktu_mulai') $kegiatans = Kegiatan::orderBy('hari')->orderBy('waktu_mulai')
->get() ->get()
->map(function ($k) { ->map(function ($k) {
@ -116,13 +107,17 @@ public function preview(Request $request)
); );
} }
// ── Match ──────────────────────────────────────────── // ── Match scan ke kegiatan (pakai toleransi dari form)
$glogGrouped = $this->parser->groupGLogByDay($glogRecords); $glogGrouped = $this->parser->groupGLogByDay($glogRecords);
$rawHasil = $this->parser->matchToKegiatan( $rawHasil = $this->parser->matchToKegiatan(
$glogGrouped, $infoData, $kegiatans, $tolSebelum, $tolSesudah $glogGrouped,
$infoData,
$kegiatans,
$tolSebelum, // ← dari form, bukan hardcode
$tolSesudah // ← dari form, bukan hardcode
); );
// ── Enrich (santri web + kepulangan + konflik) ──────── // ── Enrich: santri web + kepulangan + deteksi konflik ─
$kepulanganCache = []; $kepulanganCache = [];
$hasilEnriched = []; $hasilEnriched = [];
@ -139,7 +134,7 @@ public function preview(Request $request)
$namaWeb = $mapping?->santri?->nama_lengkap; $namaWeb = $mapping?->santri?->nama_lengkap;
$kelas = $mapping?->santri?->kelasPrimary?->kelas?->nama_kelas ?? '-'; $kelas = $mapping?->santri?->kelasPrimary?->kelas?->nama_kelas ?? '-';
// Cache kepulangan per tanggal agar tidak query berulang // Cache kepulangan per tanggal
if (!isset($kepulanganCache[$tanggal])) { if (!isset($kepulanganCache[$tanggal])) {
$kepulanganCache[$tanggal] = Kepulangan::where('status', 'Disetujui') $kepulanganCache[$tanggal] = Kepulangan::where('status', 'Disetujui')
->where('tanggal_pulang', '<=', $tanggal) ->where('tanggal_pulang', '<=', $tanggal)
@ -150,10 +145,8 @@ public function preview(Request $request)
$rows = array_map( $rows = array_map(
function ($row) use ($idSantri, $tanggal, $isPulang, $isiAlpa) { function ($row) use ($idSantri, $tanggal, $isPulang, $isiAlpa) {
// Override jika santri sedang kepulangan
$statusFinal = $isPulang ? 'Pulang' : $row['status']; $statusFinal = $isPulang ? 'Pulang' : $row['status'];
// Jangan isi Alpa jika opsi tidak aktif
if (!$isiAlpa && $statusFinal === 'Alpa' && !$row['matched']) { if (!$isiAlpa && $statusFinal === 'Alpa' && !$row['matched']) {
$statusFinal = null; $statusFinal = null;
} }
@ -168,26 +161,18 @@ function ($row) use ($idSantri, $tanggal, $isPulang, $isiAlpa) {
->first(); ->first();
if ($rec) { if ($rec) {
// getRawOriginal bypass Eloquent datetime cast
$rawWaktu = $rec->getRawOriginal('waktu_absen'); $rawWaktu = $rec->getRawOriginal('waktu_absen');
$existing = [ $existing = [
'status' => $rec->status, 'status' => $rec->status,
'waktu' => $rawWaktu 'waktu' => $rawWaktu ? substr($rawWaktu, 0, 5) : null,
? substr($rawWaktu, 0, 5) : null,
'metode' => $rec->metode_absen ?? 'Manual', 'metode' => $rec->metode_absen ?? 'Manual',
]; ];
// PENTING: Jika mesin TIDAK punya scan untuk kegiatan
// ini (matched=false, status=Alpa), jangan override
// data manual yang sudah ada. "Tidak ada scan" ≠ "Alpa".
// Pertahankan data lama secara otomatis.
if (!$row['matched'] && $statusFinal === 'Alpa') { if (!$row['matched'] && $statusFinal === 'Alpa') {
// Tidak override — pakai data existing // Tidak ada scan = tidak override data manual
$statusFinal = $rec->status; $statusFinal = $rec->status;
$isConflict = false; $isConflict = false;
} else { } else {
// Konflik hanya jika mesin MEMANG punya scan
// (matched=true) tapi statusnya beda dari manual
$isConflict = ($rec->metode_absen !== 'Import_Mesin') $isConflict = ($rec->metode_absen !== 'Import_Mesin')
&& ($rec->status !== $statusFinal) && ($rec->status !== $statusFinal)
&& $statusFinal !== null; && $statusFinal !== null;
@ -222,15 +207,11 @@ function ($row) use ($idSantri, $tanggal, $isPulang, $isiAlpa) {
<=> [$b['tanggal'], $b['nama_web'] ?? $b['nama_mesin']] <=> [$b['tanggal'], $b['nama_web'] ?? $b['nama_mesin']]
); );
// ── Simpan ke session lalu REDIRECT ke showPreview ──── // ── Simpan ke session lalu redirect (PRG pattern) ─────
// Ini adalah PRG Pattern (Post-Redirect-Get):
// POST /import/preview → proses → session → redirect
// GET /import/preview → ambil dari session → tampilkan view
// Sehingga refresh halaman tidak error MethodNotAllowed
session([ session([
'eppos_hasil' => $hasilEnriched, 'eppos_hasil' => $hasilEnriched,
'tol_sebelum' => $tolSebelum, 'tol_sebelum' => $tolSebelum, // nilai dari form
'tol_sesudah' => $tolSesudah, 'tol_sesudah' => $tolSesudah, // nilai dari form
'isi_alpa' => $isiAlpa, 'isi_alpa' => $isiAlpa,
'conflict_strategy' => $conflictStrategy, 'conflict_strategy' => $conflictStrategy,
]); ]);
@ -245,12 +226,12 @@ public function showPreview()
{ {
$hasilEnriched = session('eppos_hasil'); $hasilEnriched = session('eppos_hasil');
// Jika session kosong (user buka langsung tanpa upload)
if (empty($hasilEnriched)) { if (empty($hasilEnriched)) {
return redirect()->route('admin.mesin.import.index') return redirect()->route('admin.mesin.import.index')
->with('error', 'Tidak ada data preview. Silakan upload file GLog terlebih dahulu.'); ->with('error', 'Tidak ada data preview. Silakan upload file GLog terlebih dahulu.');
} }
// Ambil toleransi dari session (nilai yang dipakai saat matching)
$tolSebelum = session('tol_sebelum', 15); $tolSebelum = session('tol_sebelum', 15);
$tolSesudah = session('tol_sesudah', 10); $tolSesudah = session('tol_sesudah', 10);
$isiAlpa = session('isi_alpa', true); $isiAlpa = session('isi_alpa', true);
@ -259,7 +240,6 @@ public function showPreview()
$tanggalList = array_unique(array_column($hasilEnriched, 'tanggal')); $tanggalList = array_unique(array_column($hasilEnriched, 'tanggal'));
sort($tanggalList); sort($tanggalList);
// Debug: kumpulkan info scan yang tidak cocok untuk ditampilkan
$debugScans = []; $debugScans = [];
foreach ($hasilEnriched as $h) { foreach ($hasilEnriched as $h) {
if (!empty($h['unmatched_scans'])) { if (!empty($h['unmatched_scans'])) {
@ -330,15 +310,14 @@ public function store(Request $request)
continue; continue;
} }
// Alpa tanpa scan (matched=false) + sudah ada data existing // Alpa tanpa scan + sudah ada data existing → pertahankan
// → pertahankan data lama, jangan simpan Alpa if (!$row['matched'] && $row['status_final'] === 'Alpa'
if (!$row['matched'] && $row['status_final'] === 'Alpa' && !empty($row['existing'])) { && !empty($row['existing'])) {
$counters['skipped']++; $counters['skipped']++;
continue; continue;
} }
// Jika mesin tidak punya scan dan statusFinal = status existing // Status sama dengan existing → tidak perlu update
// (artinya sudah diset ke status existing di preview), skip
if (!$row['matched'] && !empty($row['existing']) if (!$row['matched'] && !empty($row['existing'])
&& $row['status_final'] === $row['existing']['status']) { && $row['status_final'] === $row['existing']['status']) {
$counters['skipped']++; $counters['skipped']++;
@ -350,7 +329,7 @@ public function store(Request $request)
$isConflict = $row['is_conflict'] ?? false; $isConflict = $row['is_conflict'] ?? false;
if (!$hasExisting) { if (!$hasExisting) {
// Belum ada data → langsung buat // Belum ada data → buat baru
AbsensiKegiatan::create([ AbsensiKegiatan::create([
'kegiatan_id' => $row['kegiatan_id'], 'kegiatan_id' => $row['kegiatan_id'],
'id_santri' => $dayData['id_santri'], 'id_santri' => $dayData['id_santri'],
@ -367,20 +346,18 @@ public function store(Request $request)
continue; continue;
} }
// Ada data existing tapi tidak konflik (status sama) // Ada existing tapi tidak konflik → skip
// → skip, tidak perlu diubah
if (!$isConflict) { if (!$isConflict) {
$counters['skipped']++; $counters['skipped']++;
continue; continue;
} }
// Ada konflik → lihat strategi bulk dulu, baru per-cell // Ada konflik → cek strategi
$choice = ($bulkStrategy !== 'manual') $choice = ($bulkStrategy !== 'manual')
? $bulkStrategy ? $bulkStrategy
: ($choices[$key] ?? null); : ($choices[$key] ?? null);
if ($choice === 'mesin') { if ($choice === 'mesin') {
// Admin pilih: pakai data mesin
AbsensiKegiatan::where('kegiatan_id', $row['kegiatan_id']) AbsensiKegiatan::where('kegiatan_id', $row['kegiatan_id'])
->where('id_santri', $dayData['id_santri']) ->where('id_santri', $dayData['id_santri'])
->whereDate('tanggal', $dayData['tanggal']) ->whereDate('tanggal', $dayData['tanggal'])
@ -402,8 +379,7 @@ public function store(Request $request)
]); ]);
$counters['updated']++; $counters['updated']++;
} else { } else {
// Admin pilih: pertahankan data lama // Pertahankan data lama
// Tidak melakukan apa-apa
$counters['kept']++; $counters['kept']++;
} }
} }
@ -428,7 +404,10 @@ public function store(Request $request)
} }
// Hapus session setelah berhasil // Hapus session setelah berhasil
session()->forget(['eppos_hasil', 'tol_sebelum', 'tol_sesudah', 'isi_alpa', 'conflict_strategy']); session()->forget([
'eppos_hasil', 'tol_sebelum', 'tol_sesudah',
'isi_alpa', 'conflict_strategy',
]);
$msg = "Import selesai! " $msg = "Import selesai! "
. "{$counters['created']} data baru tersimpan, " . "{$counters['created']} data baru tersimpan, "

View File

@ -15,7 +15,7 @@
class KegiatanController extends Controller class KegiatanController extends Controller
{ {
/** /**
* Dashboard Kegiatan Hari Ini (ENHANCED) * Dashboard Kegiatan Hari Ini
*/ */
public function index(Request $request) public function index(Request $request)
{ {
@ -55,13 +55,72 @@ public function index(Request $request)
} }
$kegiatanHariIni = $query->orderBy('waktu_mulai')->get(); $kegiatanHariIni = $query->orderBy('waktu_mulai')->get();
// ── Total santri aktif (dipakai sebagai denominator kegiatan umum) ──────
$totalSantriAktif = Santri::where('status', 'Aktif')->count(); $totalSantriAktif = Santri::where('status', 'Aktif')->count();
$kegiatanHariIni->each(function ($kegiatan) use ($totalSantriAktif, $selectedDate) { // ── Pre-load semua santri aktif beserta kelas mereka (1 query) ────────────
$totalAbsensi = $kegiatan->absensis->count(); // Ini dipakai untuk menghitung "berapa santri yang seharusnya hadir" per kegiatan
$hadir = $kegiatan->absensis->where('status', 'Hadir')->count(); $allSantriAktif = Santri::where('status', 'Aktif')
$persenKehadiran = $totalAbsensi > 0 ? round(($hadir / $totalAbsensi) * 100) : 0; ->with('kelasSantri')
->get();
$kegiatanHariIni->each(function ($kegiatan) use ($totalSantriAktif, $selectedDate, $allSantriAktif) {
$absensis = $kegiatan->absensis; // sudah di-eager-load
$totalAbsensi = $absensis->count();
// ── FIX 1: Terlambat = hadir (masuk), bukan alpha ──────────────────
$hadirEfektif = $absensis->whereIn('status', ['Hadir', 'Terlambat'])->count();
$terlambat = $absensis->where('status', 'Terlambat')->count();
$izin = $absensis->where('status', 'Izin')->count();
$sakit = $absensis->where('status', 'Sakit')->count();
$alpa = $absensis->where('status', 'Alpa')->count();
// ── FIX 2: Denominator = jumlah santri yg seharusnya ikut kegiatan ini ──
if ($kegiatan->kelasKegiatan->isEmpty()) {
// Kegiatan Umum → semua santri aktif
$totalSantriKegiatan = $totalSantriAktif;
} else {
// Kegiatan Khusus → hitung santri yang terdaftar di kelas kegiatan
$kelasIds = $kegiatan->kelasKegiatan->pluck('id')->toArray();
$totalSantriKegiatan = $allSantriAktif->filter(function ($s) use ($kelasIds) {
return $s->kelasSantri->whereIn('id_kelas', $kelasIds)->count() > 0;
})->count();
// Fallback jika tidak ada santri terdaftar di kelas
if ($totalSantriKegiatan === 0) $totalSantriKegiatan = $totalSantriAktif;
}
// ── FIX 3: Persentase berdasarkan total santri kegiatan, bukan yg sudah absen ──
$persenKehadiran = $totalSantriKegiatan > 0
? round(($hadirEfektif / $totalSantriKegiatan) * 100)
: 0;
// ── FIX 4: Info per kelas — berapa kelas sudah/belum input ───────────
$infoPerKelas = collect();
if (!$kegiatan->kelasKegiatan->isEmpty()) {
$absensiByKelas = $absensis->groupBy(function ($ab) {
// group berdasarkan kelas santri yg hadir (ambil kelas pertama yg sesuai)
return $ab->santri->kelas_name ?? 'Tanpa Kelas';
});
foreach ($kegiatan->kelasKegiatan as $kls) {
$kelasId = $kls->id;
$santriDiKelas = $allSantriAktif->filter(function ($s) use ($kelasId) {
return $s->kelasSantri->where('id_kelas', $kelasId)->count() > 0;
})->count();
// Berapa dari kelas ini yang sudah diinput absensi hari ini
// Cek dari absensis: santri yg ada di kelas ini
$sudahInputKelas = 0; // akan diisi di blade via data yg dikirim
$infoPerKelas->push([
'nama' => $kls->nama_kelas,
'total_santri' => $santriDiKelas,
]);
}
}
// ── Status kegiatan (belum / berlangsung / selesai) ─────────────────
$now = Carbon::now(); $now = Carbon::now();
$waktuMulaiStr = is_string($kegiatan->waktu_mulai) ? $kegiatan->waktu_mulai : $kegiatan->waktu_mulai->format('H:i'); $waktuMulaiStr = is_string($kegiatan->waktu_mulai) ? $kegiatan->waktu_mulai : $kegiatan->waktu_mulai->format('H:i');
$waktuSelesaiStr = is_string($kegiatan->waktu_selesai) ? $kegiatan->waktu_selesai : $kegiatan->waktu_selesai->format('H:i'); $waktuSelesaiStr = is_string($kegiatan->waktu_selesai) ? $kegiatan->waktu_selesai : $kegiatan->waktu_selesai->format('H:i');
@ -78,10 +137,19 @@ public function index(Request $request)
$status = 'selesai'; $status = 'selesai';
} }
$kegiatan->total_hadir = $hadir; // Set semua property ke object kegiatan
$kegiatan->total_absensi = $totalAbsensi; $kegiatan->total_hadir = $hadirEfektif; // hadir + terlambat
$kegiatan->total_hadir_murni = $absensis->where('status', 'Hadir')->count();
$kegiatan->total_terlambat = $terlambat;
$kegiatan->total_izin = $izin;
$kegiatan->total_sakit = $sakit;
$kegiatan->total_alpa = $alpa;
$kegiatan->total_absensi = $totalAbsensi; // sudah diinput
$kegiatan->total_santri_kegiatan = $totalSantriKegiatan; // seharusnya hadir
$kegiatan->belum_absen = max(0, $totalSantriKegiatan - $totalAbsensi);
$kegiatan->persen_kehadiran = $persenKehadiran; $kegiatan->persen_kehadiran = $persenKehadiran;
$kegiatan->status_kegiatan = $status; $kegiatan->status_kegiatan = $status;
$kegiatan->info_per_kelas = $infoPerKelas;
}); });
$totalKegiatanHariIni = $kegiatanHariIni->count(); $totalKegiatanHariIni = $kegiatanHariIni->count();
@ -102,7 +170,9 @@ public function index(Request $request)
$abs = AbsensiKegiatan::where('kegiatan_id', $kg->kegiatan_id) $abs = AbsensiKegiatan::where('kegiatan_id', $kg->kegiatan_id)
->whereDate('tanggal', $lastWeekDate->format('Y-m-d'))->get(); ->whereDate('tanggal', $lastWeekDate->format('Y-m-d'))->get();
if ($abs->count() > 0) { if ($abs->count() > 0) {
$totalPersen += ($abs->where('status', 'Hadir')->count() / $abs->count()) * 100; // FIX: hitung hadir + terlambat, bukan hadir saja
$hadirCount = $abs->whereIn('status', ['Hadir', 'Terlambat'])->count();
$totalPersen += ($hadirCount / $abs->count()) * 100;
$count++; $count++;
} }
} }
@ -139,9 +209,10 @@ private function generateInsights($kegiatanHariIni, $totalSantriAktif, $selected
foreach ($kegiatanHariIni as $kegiatan) { foreach ($kegiatanHariIni as $kegiatan) {
if ($kegiatan->total_absensi > 0 && $kegiatan->persen_kehadiran < 70) { if ($kegiatan->total_absensi > 0 && $kegiatan->persen_kehadiran < 70) {
$insights[] = [ $insights[] = [
'type' => 'warning', 'icon' => 'exclamation-triangle', 'type' => 'warning',
'icon' => 'exclamation-triangle',
'message' => "Kegiatan {$kegiatan->nama_kegiatan} kehadiran rendah ({$kegiatan->persen_kehadiran}%)", 'message' => "Kegiatan {$kegiatan->nama_kegiatan} kehadiran rendah ({$kegiatan->persen_kehadiran}%)",
'detail' => "{$kegiatan->total_hadir} dari {$kegiatan->total_absensi} santri hadir", 'detail' => "{$kegiatan->total_hadir} hadir dari {$kegiatan->total_santri_kegiatan} santri",
'action_url' => route('admin.absensi-kegiatan.input', $kegiatan->kegiatan_id) . '?tanggal=' . $selectedDate->format('Y-m-d'), 'action_url' => route('admin.absensi-kegiatan.input', $kegiatan->kegiatan_id) . '?tanggal=' . $selectedDate->format('Y-m-d'),
'action_text' => 'Input Absensi', 'action_text' => 'Input Absensi',
]; ];
@ -151,9 +222,12 @@ private function generateInsights($kegiatanHariIni, $totalSantriAktif, $selected
foreach ($kegiatanHariIni as $kegiatan) { foreach ($kegiatanHariIni as $kegiatan) {
if ($kegiatan->persen_kehadiran == 100 && $kegiatan->total_absensi > 0) { if ($kegiatan->persen_kehadiran == 100 && $kegiatan->total_absensi > 0) {
$insights[] = [ $insights[] = [
'type' => 'success', 'icon' => 'check-circle', 'type' => 'success',
'icon' => 'check-circle',
'message' => "Perfect! {$kegiatan->nama_kegiatan} kehadiran 100%", 'message' => "Perfect! {$kegiatan->nama_kegiatan} kehadiran 100%",
'detail' => 'Semua santri hadir', 'action_url' => null, 'action_text' => null, 'detail' => "Semua {$kegiatan->total_santri_kegiatan} santri hadir",
'action_url' => null,
'action_text' => null,
]; ];
} }
} }
@ -161,9 +235,10 @@ private function generateInsights($kegiatanHariIni, $totalSantriAktif, $selected
$kegiatanLive = $kegiatanHariIni->where('status_kegiatan', 'berlangsung')->first(); $kegiatanLive = $kegiatanHariIni->where('status_kegiatan', 'berlangsung')->first();
if ($kegiatanLive) { if ($kegiatanLive) {
$insights[] = [ $insights[] = [
'type' => 'info', 'icon' => 'clock', 'type' => 'info',
'icon' => 'clock',
'message' => "Kegiatan {$kegiatanLive->nama_kegiatan} sedang berlangsung", 'message' => "Kegiatan {$kegiatanLive->nama_kegiatan} sedang berlangsung",
'detail' => "Progress absensi: {$kegiatanLive->persen_kehadiran}%", 'detail' => "Progress absensi: {$kegiatanLive->total_absensi}/{$kegiatanLive->total_santri_kegiatan} santri ({$kegiatanLive->persen_kehadiran}%)",
'action_url' => route('admin.absensi-kegiatan.input', $kegiatanLive->kegiatan_id) . '?tanggal=' . $selectedDate->format('Y-m-d'), 'action_url' => route('admin.absensi-kegiatan.input', $kegiatanLive->kegiatan_id) . '?tanggal=' . $selectedDate->format('Y-m-d'),
'action_text' => 'Input Absensi Sekarang', 'action_text' => 'Input Absensi Sekarang',
]; ];
@ -173,9 +248,10 @@ private function generateInsights($kegiatanHariIni, $totalSantriAktif, $selected
if ($kegiatan->status_kegiatan == 'selesai' && $kegiatan->total_absensi == 0) { if ($kegiatan->status_kegiatan == 'selesai' && $kegiatan->total_absensi == 0) {
$waktuSelesai = is_string($kegiatan->waktu_selesai) ? $kegiatan->waktu_selesai : $kegiatan->waktu_selesai->format('H:i'); $waktuSelesai = is_string($kegiatan->waktu_selesai) ? $kegiatan->waktu_selesai : $kegiatan->waktu_selesai->format('H:i');
$insights[] = [ $insights[] = [
'type' => 'danger', 'icon' => 'exclamation-circle', 'type' => 'danger',
'icon' => 'exclamation-circle',
'message' => "Kegiatan {$kegiatan->nama_kegiatan} belum input absensi", 'message' => "Kegiatan {$kegiatan->nama_kegiatan} belum input absensi",
'detail' => "Sudah selesai pukul {$waktuSelesai}", 'detail' => "Sudah selesai pukul {$waktuSelesai}, {$kegiatan->total_santri_kegiatan} santri belum diinput",
'action_url' => route('admin.absensi-kegiatan.input', $kegiatan->kegiatan_id) . '?tanggal=' . $selectedDate->format('Y-m-d'), 'action_url' => route('admin.absensi-kegiatan.input', $kegiatan->kegiatan_id) . '?tanggal=' . $selectedDate->format('Y-m-d'),
'action_text' => 'Input Sekarang', 'action_text' => 'Input Sekarang',
]; ];
@ -187,6 +263,7 @@ private function generateInsights($kegiatanHariIni, $totalSantriAktif, $selected
/** /**
* Generate Heatmap Data (30 hari terakhir) * Generate Heatmap Data (30 hari terakhir)
* FIX: hitung hadir + terlambat, bukan hadir saja
*/ */
private function generateHeatmapData() private function generateHeatmapData()
{ {
@ -199,7 +276,7 @@ private function generateHeatmapData()
$absensi = AbsensiKegiatan::whereDate('tanggal', $dateStr)->get(); $absensi = AbsensiKegiatan::whereDate('tanggal', $dateStr)->get();
$percentage = $absensi->count() > 0 $percentage = $absensi->count() > 0
? round(($absensi->where('status', 'Hadir')->count() / $absensi->count()) * 100, 1) ? round(($absensi->whereIn('status', ['Hadir', 'Terlambat'])->count() / $absensi->count()) * 100, 1)
: 0; : 0;
$heatmapData[] = [ $heatmapData[] = [
@ -225,6 +302,7 @@ private function getHeatmapLevel($percentage)
/** /**
* AJAX: Get Detail Kegiatan untuk Modal * AJAX: Get Detail Kegiatan untuk Modal
* FIX: persen_hadir juga ikut hitung Terlambat
*/ */
public function getDetailModal($kegiatan_id, Request $request) public function getDetailModal($kegiatan_id, Request $request)
{ {
@ -239,7 +317,7 @@ public function getDetailModal($kegiatan_id, Request $request)
$isUmum = $kegiatan->isForAllClasses(); $isUmum = $kegiatan->isForAllClasses();
// Grup absensi per kelas kegiatan (khusus) atau kelas_name (umum) // Grup absensi per kelas
if ($isUmum) { if ($isUmum) {
$absensiPerKelas = $absensis->groupBy(fn($item) => $item->santri->kelas_name ?? 'Belum Ada Kelas')->sortKeys(); $absensiPerKelas = $absensis->groupBy(fn($item) => $item->santri->kelas_name ?? 'Belum Ada Kelas')->sortKeys();
} else { } else {
@ -248,33 +326,75 @@ public function getDetailModal($kegiatan_id, Request $request)
$filtered = $absensis->filter(fn($item) => $item->santri->kelasSantri->contains('id_kelas', $kelas->id)); $filtered = $absensis->filter(fn($item) => $item->santri->kelasSantri->contains('id_kelas', $kelas->id));
if ($filtered->count() > 0) $absensiPerKelas[$kelas->nama_kelas] = $filtered; if ($filtered->count() > 0) $absensiPerKelas[$kelas->nama_kelas] = $filtered;
} }
// Sisanya yang tidak cocok kelas manapun
$placedIds = $absensiPerKelas->flatten()->pluck('id')->toArray(); $placedIds = $absensiPerKelas->flatten()->pluck('id')->toArray();
$lainnya = $absensis->filter(fn($item) => !$absensiPerKelas->flatten()->contains('id', $item->id)); $lainnya = $absensis->filter(fn($item) => !in_array($item->id, $placedIds));
if ($lainnya->count() > 0) $absensiPerKelas['Kelas Lain'] = $lainnya; if ($lainnya->count() > 0) $absensiPerKelas['Kelas Lain'] = $lainnya;
} }
// FIX: hadir efektif = Hadir + Terlambat
$hadirEfektif = $absensis->whereIn('status', ['Hadir', 'Terlambat'])->count();
// Total santri yang seharusnya hadir
if ($isUmum) {
$totalSantri = Santri::where('status', 'Aktif')->count();
} else {
$kelasIds = $kegiatan->kelasKegiatan->pluck('id')->toArray();
$totalSantri = Santri::where('status', 'Aktif')
->whereHas('kelasSantri', fn($q) => $q->whereIn('id_kelas', $kelasIds))
->count();
if ($totalSantri === 0) $totalSantri = Santri::where('status', 'Aktif')->count();
}
$stats = [ $stats = [
'hadir' => $absensis->where('status', 'Hadir')->count(), 'hadir' => $absensis->where('status', 'Hadir')->count(),
'terlambat' => $absensis->where('status', 'Terlambat')->count(), 'terlambat' => $absensis->where('status', 'Terlambat')->count(),
'hadir_efektif'=> $hadirEfektif, // hadir + terlambat
'izin' => $absensis->where('status', 'Izin')->count(), 'izin' => $absensis->where('status', 'Izin')->count(),
'sakit' => $absensis->where('status', 'Sakit')->count(), 'sakit' => $absensis->where('status', 'Sakit')->count(),
'alpa' => $absensis->where('status', 'Alpa')->count(), 'alpa' => $absensis->where('status', 'Alpa')->count(),
]; ];
$totalSantri = Santri::where('status', 'Aktif')->count();
$stats['belum_absen'] = max(0, $totalSantri - $absensis->count()); $stats['belum_absen'] = max(0, $totalSantri - $absensis->count());
$stats['sudah_absen'] = $absensis->count(); $stats['sudah_absen'] = $absensis->count();
$stats['total'] = $totalSantri; $stats['total'] = $totalSantri;
$stats['persen_hadir'] = $totalSantri > 0 ? round(($stats['hadir'] / $totalSantri) * 100, 1) : 0; // FIX: persen hadir pakai hadir_efektif bukan hadir saja
$stats['persen_hadir'] = $totalSantri > 0
? round(($hadirEfektif / $totalSantri) * 100, 1)
: 0;
// Daftar santri belum absen, di-group per kelas kegiatan (khusus) atau kelasPrimary (umum) // ── Info per kelas untuk modal: sudah/belum input ───────────────────────
$infoKelasModal = collect();
if (!$isUmum) {
$allSantriAktif = Santri::where('status', 'Aktif')->with('kelasSantri')->get();
foreach ($kegiatan->kelasKegiatan as $kls) {
$kelasId = $kls->id;
$santriDiKelas = $allSantriAktif->filter(fn($s) => $s->kelasSantri->where('id_kelas', $kelasId)->count() > 0)->count();
$sudahInputKelas = $absensis->filter(fn($ab) =>
$ab->santri->kelasSantri->contains('id_kelas', $kelasId)
)->count();
$infoKelasModal->push([
'nama' => $kls->nama_kelas,
'total_santri' => $santriDiKelas,
'sudah_input' => $sudahInputKelas,
'belum_input' => max(0, $santriDiKelas - $sudahInputKelas),
'sudah_semua' => $sudahInputKelas >= $santriDiKelas && $santriDiKelas > 0,
]);
}
}
// Daftar santri belum absen
$idSantriSudahAbsen = $absensis->pluck('id_santri')->toArray(); $idSantriSudahAbsen = $absensis->pluck('id_santri')->toArray();
$allBelumAbsen = Santri::where('status', 'Aktif') $belumQuery = Santri::where('status', 'Aktif')
->whereNotIn('id_santri', $idSantriSudahAbsen) ->whereNotIn('id_santri', $idSantriSudahAbsen)
->with(['kelasSantri.kelas', 'kelasPrimary.kelas']) ->with(['kelasSantri.kelas', 'kelasPrimary.kelas'])
->orderBy('nama_lengkap') ->orderBy('nama_lengkap');
->get();
if (!$isUmum) {
$kelasIds = $kegiatan->kelasKegiatan->pluck('id')->toArray();
$belumQuery->whereHas('kelasSantri', fn($q) => $q->whereIn('id_kelas', $kelasIds));
}
$allBelumAbsen = $belumQuery->get();
if ($isUmum) { if ($isUmum) {
$santriBelumAbsenPerKelas = $allBelumAbsen->groupBy(function($s) { $santriBelumAbsenPerKelas = $allBelumAbsen->groupBy(function($s) {
@ -295,9 +415,12 @@ public function getDetailModal($kegiatan_id, Request $request)
if ($lainnyaBelum->count() > 0) $santriBelumAbsenPerKelas['Kelas Lain'] = $lainnyaBelum; if ($lainnyaBelum->count() > 0) $santriBelumAbsenPerKelas['Kelas Lain'] = $lainnyaBelum;
} }
$santriBelumAbsen = $allBelumAbsen; // kept for count reference $santriBelumAbsen = $allBelumAbsen;
return view('admin.kegiatan.data.partials.detail-modal', compact('kegiatan', 'absensis', 'absensiPerKelas', 'stats', 'tanggal', 'santriBelumAbsen', 'santriBelumAbsenPerKelas')); return view('admin.kegiatan.data.partials.detail-modal', compact(
'kegiatan', 'absensis', 'absensiPerKelas', 'stats', 'tanggal',
'santriBelumAbsen', 'santriBelumAbsenPerKelas', 'infoKelasModal'
));
} }
/** /**
@ -421,12 +544,6 @@ public function edit(Kegiatan $kegiatan)
/** /**
* Update kegiatan smart multi-hari * Update kegiatan smart multi-hari
*
* Logika:
* - Cari semua kegiatan "saudara" = nama_kegiatan + kategori_id LAMA yang sama
* - Hari yang DIPILIH & sudah ada di saudara UPDATE kegiatan saudara tsb
* - Hari yang DIPILIH tapi belum ada di saudara BUAT kegiatan baru
* - Hari yang TIDAK DIPILIH tidak disentuh sama sekali
*/ */
public function update(Request $request, Kegiatan $kegiatan) public function update(Request $request, Kegiatan $kegiatan)
{ {
@ -451,28 +568,23 @@ public function update(Request $request, Kegiatan $kegiatan)
$hariDipilih = $validated['hari']; $hariDipilih = $validated['hari'];
$kelasIds = $request->input('kelas_ids', []); $kelasIds = $request->input('kelas_ids', []);
// Data dasar tanpa hari & kelas_ids
$baseData = collect($validated)->except(['hari', 'kelas_ids'])->toArray(); $baseData = collect($validated)->except(['hari', 'kelas_ids'])->toArray();
// Cari semua saudara berdasarkan nama + kategori LAMA (sebelum diubah)
$saudara = Kegiatan::where('nama_kegiatan', $kegiatan->nama_kegiatan) $saudara = Kegiatan::where('nama_kegiatan', $kegiatan->nama_kegiatan)
->where('kategori_id', $kegiatan->kategori_id) ->where('kategori_id', $kegiatan->kategori_id)
->get() ->get()
->keyBy('hari'); // ['Senin' => obj, 'Rabu' => obj, ...] ->keyBy('hari');
$updatedCount = 0; $updatedCount = 0;
$createdCount = 0; $createdCount = 0;
foreach ($hariDipilih as $hari) { foreach ($hariDipilih as $hari) {
if ($saudara->has($hari)) { if ($saudara->has($hari)) {
// Kegiatan di hari ini sudah ada → update
$target = $saudara->get($hari); $target = $saudara->get($hari);
$target->update(array_merge($baseData, ['hari' => $hari])); $target->update(array_merge($baseData, ['hari' => $hari]));
$target->assignKelas($kelasIds); $target->assignKelas($kelasIds);
$updatedCount++; $updatedCount++;
} else { } else {
// Belum ada kegiatan di hari ini → buat baru
$newKg = Kegiatan::create(array_merge($baseData, ['hari' => $hari])); $newKg = Kegiatan::create(array_merge($baseData, ['hari' => $hari]));
$newKg->assignKelas($kelasIds); $newKg->assignKelas($kelasIds);
$createdCount++; $createdCount++;

View File

@ -290,6 +290,10 @@ public function kenaikanProcess(Request $request)
$kelasAsal = Kelas::findOrFail($request->id_kelas_asal); $kelasAsal = Kelas::findOrFail($request->id_kelas_asal);
$kelasTujuan = Kelas::findOrFail($request->id_kelas_tujuan); $kelasTujuan = Kelas::findOrFail($request->id_kelas_tujuan);
// Ambil semua id kelas yang satu kelompok dengan kelas asal
$kelasSeKelompok = Kelas::where('id_kelompok', $kelasAsal->id_kelompok)
->pluck('id');
$santriIds = Santri::whereHas('kelasSantri', fn($q) => $q->where('id_kelas', $request->id_kelas_asal)) $santriIds = Santri::whereHas('kelasSantri', fn($q) => $q->where('id_kelas', $request->id_kelas_asal))
->where('status', 'Aktif') ->where('status', 'Aktif')
->pluck('id_santri'); ->pluck('id_santri');
@ -304,24 +308,23 @@ public function kenaikanProcess(Request $request)
DB::beginTransaction(); DB::beginTransaction();
try { try {
foreach ($santriIds as $idSantri) { foreach ($santriIds as $idSantri) {
$record = SantriKelas::where('id_santri', $idSantri) // Ambil record kelas asal
$recordAsal = SantriKelas::where('id_santri', $idSantri)
->where('id_kelas', $kelasAsal->id) ->where('id_kelas', $kelasAsal->id)
->orderBy('tahun_ajaran', 'desc') ->orderBy('tahun_ajaran', 'desc')
->first(); ->first();
if (!$record) continue; if (!$recordAsal) continue;
// Cek duplikasi: jika sudah ada di kelas tujuan + tahun_ajaran sama, hapus record lama // Hapus record lain milik santri ini yang satu kelompok dengan kelas asal
$sudahAda = SantriKelas::where('id_santri', $idSantri) // (kecuali record asal itu sendiri, karena akan kita update)
->where('id_kelas', $kelasTujuan->id) SantriKelas::where('id_santri', $idSantri)
->where('tahun_ajaran', $record->tahun_ajaran) ->whereIn('id_kelas', $kelasSeKelompok)
->exists(); ->where('id', '!=', $recordAsal->id)
->delete();
if ($sudahAda) { // Pindahkan record kelas asal ke kelas tujuan
$record->delete(); $recordAsal->update(['id_kelas' => $kelasTujuan->id]);
} else {
$record->update(['id_kelas' => $kelasTujuan->id]);
}
$processed++; $processed++;
} }
@ -353,29 +356,32 @@ public function kenaikanProcessSelected(Request $request)
$kelasAsal = Kelas::findOrFail($request->id_kelas_asal); $kelasAsal = Kelas::findOrFail($request->id_kelas_asal);
$kelasTujuan = Kelas::findOrFail($request->id_kelas_tujuan); $kelasTujuan = Kelas::findOrFail($request->id_kelas_tujuan);
// Ambil semua id kelas yang satu kelompok dengan kelas asal
$kelasSeKelompok = Kelas::where('id_kelompok', $kelasAsal->id_kelompok)
->pluck('id');
$processed = 0; $processed = 0;
DB::beginTransaction(); DB::beginTransaction();
try { try {
foreach ($request->santri_ids as $idSantri) { foreach ($request->santri_ids as $idSantri) {
$record = SantriKelas::where('id_santri', $idSantri) // Ambil record kelas asal
$recordAsal = SantriKelas::where('id_santri', $idSantri)
->where('id_kelas', $kelasAsal->id) ->where('id_kelas', $kelasAsal->id)
->orderBy('tahun_ajaran', 'desc') ->orderBy('tahun_ajaran', 'desc')
->first(); ->first();
if (!$record) continue; if (!$recordAsal) continue;
// Cek duplikasi: jika sudah ada di kelas tujuan + tahun_ajaran sama, hapus record lama // Hapus record lain milik santri ini yang satu kelompok dengan kelas asal
$sudahAda = SantriKelas::where('id_santri', $idSantri) // (kecuali record asal itu sendiri, karena akan kita update)
->where('id_kelas', $kelasTujuan->id) SantriKelas::where('id_santri', $idSantri)
->where('tahun_ajaran', $record->tahun_ajaran) ->whereIn('id_kelas', $kelasSeKelompok)
->exists(); ->where('id', '!=', $recordAsal->id)
->delete();
if ($sudahAda) { // Pindahkan record kelas asal ke kelas tujuan
$record->delete(); $recordAsal->update(['id_kelas' => $kelasTujuan->id]);
} else {
$record->update(['id_kelas' => $kelasTujuan->id]);
}
$processed++; $processed++;
} }

View File

@ -8,282 +8,321 @@
use App\Models\KategoriKegiatan; use App\Models\KategoriKegiatan;
use App\Models\Santri; use App\Models\Santri;
use App\Models\Kelas; use App\Models\Kelas;
use App\Models\KelompokKelas;
use App\Models\SantriKelas;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
class RiwayatKegiatanController extends Controller class RiwayatKegiatanController extends Controller
{ {
/** /**
* Halaman utama riwayat kegiatan & absensi * Halaman utama riwayat default: HARI INI
*
* Mode hari_ini flat list kegiatan (paginated cards)
* Mode minggu_ini / custom grouped by actual date, tiap tanggal = 1 tabel
*/ */
public function index(Request $request) public function index(Request $request)
{ {
// Query untuk mendapatkan kegiatan dengan statistik absensi $hariMap = [
$query = Kegiatan::with(['kategori', 'kelasKegiatan.kelompok']) 'Monday' => 'Senin', 'Tuesday' => 'Selasa', 'Wednesday' => 'Rabu',
->withCount(['absensis as total_absensi']) 'Thursday' => 'Kamis', 'Friday' => 'Jumat', 'Saturday' => 'Sabtu',
->withCount(['absensis as hadir' => function($q) { 'Sunday' => 'Ahad',
$q->where('status', 'Hadir');
}])
->withCount(['absensis as izin' => function($q) {
$q->where('status', 'Izin');
}])
->withCount(['absensis as sakit' => function($q) {
$q->where('status', 'Sakit');
}])
->withCount(['absensis as alpa' => function($q) {
$q->where('status', 'Alpa');
}]);
// Filter Kategori
if ($request->filled('kategori_id')) {
$query->where('kategori_id', $request->kategori_id);
}
// Filter Tanggal untuk absensi
if ($request->filled('tanggal_dari') || $request->filled('tanggal_sampai') || $request->filled('bulan')) {
$query->whereHas('absensis', function($q) use ($request) {
if ($request->filled('tanggal_dari')) {
$q->whereDate('tanggal', '>=', $request->tanggal_dari);
}
if ($request->filled('tanggal_sampai')) {
$q->whereDate('tanggal', '<=', $request->tanggal_sampai);
}
if ($request->filled('bulan')) {
$q->whereMonth('tanggal', date('m', strtotime($request->bulan)))
->whereYear('tanggal', date('Y', strtotime($request->bulan)));
}
});
}
$kegiatans = $query->orderBy('nama_kegiatan')
->paginate(15)
->appends(request()->query());
// Data untuk filter
$kategoris = KategoriKegiatan::select('kategori_id', 'nama_kategori')->get();
return view('admin.kegiatan.riwayat.index', compact('kegiatans', 'kategoris'));
}
/**
* Riwayat kehadiran per santri (detail)
*/
public function detailSantri($id_santri)
{
$santri = Santri::where('id_santri', $id_santri)->firstOrFail();
// Statistik per santri
$stats = AbsensiKegiatan::where('id_santri', $id_santri)
->select('status', DB::raw('count(*) as total'))
->groupBy('status')
->pluck('total', 'status')
->toArray();
// Total kehadiran per kategori
$statsByKategori = 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.nama_kategori',
DB::raw('SUM(CASE WHEN absensi_kegiatans.status = "Hadir" THEN 1 ELSE 0 END) as hadir'),
DB::raw('COUNT(*) as total')
)
->groupBy('kategori_kegiatans.nama_kategori')
->get();
// Riwayat 30 hari terakhir
$riwayat30Hari = AbsensiKegiatan::where('id_santri', $id_santri)
->whereDate('tanggal', '>=', now()->subDays(30))
->select(
DB::raw('DATE(tanggal) as tanggal'),
DB::raw('SUM(CASE WHEN status = "Hadir" THEN 1 ELSE 0 END) as hadir'),
DB::raw('COUNT(*) as total')
)
->groupBy('tanggal')
->orderBy('tanggal', 'asc')
->get();
// Riwayat lengkap
$riwayats = AbsensiKegiatan::with('kegiatan.kategori')
->where('id_santri', $id_santri)
->orderBy('tanggal', 'desc')
->paginate(15);
// Kehadiran per kelas santri
$statsByKelasSantri = $santri->kelasSantri()
->with('kelas.kelompok')
->get()
->map(function($sk) use ($id_santri) {
$kehadiran = AbsensiKegiatan::where('id_santri', $id_santri)
->whereHas('kegiatan', function($q) use ($sk) {
$q->whereHas('kelasKegiatan', function($q2) use ($sk) {
$q2->where('id_kelas', $sk->id_kelas);
});
})
->selectRaw('
COUNT(*) as total,
SUM(CASE WHEN status = "Hadir" THEN 1 ELSE 0 END) as hadir
')
->first();
return [
'kelas' => $sk->kelas->nama_kelas,
'kelompok' => $sk->kelas->kelompok->nama_kelompok,
'total' => $kehadiran->total ?? 0,
'hadir' => $kehadiran->hadir ?? 0,
'persen' => ($kehadiran->total ?? 0) > 0 ? round((($kehadiran->hadir ?? 0) / $kehadiran->total) * 100, 1) : 0,
]; ];
});
return view('admin.kegiatan.riwayat.detail-santri', compact( // ── Tentukan mode & rentang tanggal ───────────────────────────────────
'santri', $mode = $request->get('mode', 'hari_ini');
'stats',
'statsByKategori', if ($mode === 'minggu_ini') {
'riwayat30Hari', $dari = now()->startOfWeek(Carbon::MONDAY)->format('Y-m-d');
'riwayats', $sampai = now()->endOfWeek(Carbon::SUNDAY)->format('Y-m-d');
'statsByKelasSantri' $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'
)); ));
} }
/** /**
* Show detail riwayat per kegiatan * Detail riwayat per kegiatan santri per kelas + filter
*/ */
public function show($id, Request $request) public function show($id, Request $request)
{ {
$kegiatan = Kegiatan::with(['kategori', 'kelasKegiatan.kelompok']) $kegiatan = Kegiatan::with(['kategori', 'kelasKegiatan.kelompok'])
->findOrFail($id); ->findOrFail($id);
// Query riwayat absensi untuk kegiatan ini // ── 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']) $query = AbsensiKegiatan::with(['santri.kelasSantri.kelas.kelompok'])
->where('kegiatan_id', $kegiatan->kegiatan_id); ->where('kegiatan_id', $kegiatan->kegiatan_id)
->whereDate('tanggal', '>=', $dari)
->whereDate('tanggal', '<=', $sampai);
// Filter Santri if ($request->filled('id_santri')) $query->where('id_santri', $request->id_santri);
if ($request->filled('id_santri')) { if ($request->filled('id_kelas')) $query->whereHas('santri.kelasSantri', fn($q) => $q->where('id_kelas', $request->id_kelas));
$query->where('id_santri', $request->id_santri); if ($request->filled('status')) $query->where('status', $request->status);
} if ($request->filled('tanggal_spesifik')) $query->whereDate('tanggal', $request->tanggal_spesifik);
// Filter Kelas $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')) { if ($request->filled('id_kelas')) {
$query->whereHas('santri.kelasSantri', function($q) use ($request) { $statsQuery->whereHas('santri.kelasSantri', fn($q) => $q->where('id_kelas', $request->id_kelas));
$q->where('id_kelas', $request->id_kelas);
});
}
// Filter Status
if ($request->filled('status')) {
$query->where('status', $request->status);
}
// Filter Tanggal
if ($request->filled('tanggal_dari')) {
$query->whereDate('tanggal', '>=', $request->tanggal_dari);
}
if ($request->filled('tanggal_sampai')) {
$query->whereDate('tanggal', '<=', $request->tanggal_sampai);
}
if ($request->filled('bulan')) {
$query->whereMonth('tanggal', date('m', strtotime($request->bulan)))
->whereYear('tanggal', date('Y', strtotime($request->bulan)));
}
$riwayats = $query->orderBy('tanggal', 'desc')
->orderBy('waktu_absen', 'desc')
->paginate(20)
->appends(request()->query());
// Data untuk filter
$santris = Santri::where('status', 'Aktif')
->select('id_santri', 'nama_lengkap')
->orderBy('nama_lengkap')
->get();
$kelasList = Kelas::active()->ordered()->with('kelompok')->get();
// Statistik untuk kegiatan ini (sesuai filter)
$statsQuery = AbsensiKegiatan::where('kegiatan_id', $kegiatan->kegiatan_id);
if ($request->filled('tanggal_dari')) {
$statsQuery->whereDate('tanggal', '>=', $request->tanggal_dari);
}
if ($request->filled('tanggal_sampai')) {
$statsQuery->whereDate('tanggal', '<=', $request->tanggal_sampai);
}
if ($request->filled('bulan')) {
$statsQuery->whereMonth('tanggal', date('m', strtotime($request->bulan)))
->whereYear('tanggal', date('Y', strtotime($request->bulan)));
}
if ($request->filled('id_kelas')) {
$statsQuery->whereHas('santri.kelasSantri', function($q) use ($request) {
$q->where('id_kelas', $request->id_kelas);
});
} }
$stats = $statsQuery->select('status', DB::raw('count(*) as total')) $stats = $statsQuery->select('status', DB::raw('count(*) as total'))
->groupBy('status') ->groupBy('status')->pluck('total', 'status')->toArray();
->pluck('total', 'status')
->toArray();
// Hitung total SEMUA santri aktif // ── Total santri yang seharusnya hadir ────────────────────────────────
if ($kegiatan->kelasKegiatan->isEmpty()) {
$totalSantriEligible = Santri::where('status', 'Aktif')->count(); $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); $totalRecorded = array_sum($stats);
$hadirCount = ($stats['Hadir'] ?? 0) + ($stats['Terlambat'] ?? 0); $hadirCount = ($stats['Hadir'] ?? 0) + ($stats['Terlambat'] ?? 0);
$persenHadir = $totalSantriEligible > 0 ? round($hadirCount / $totalSantriEligible * 100, 1) : 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( return view('admin.kegiatan.riwayat.show', compact(
'kegiatan', 'kegiatan', 'riwayats', 'santris', 'kelasList', 'stats',
'riwayats', 'totalSantriEligible', 'totalRecorded', 'persenHadir',
'santris', 'mode', 'dari', 'sampai', 'tanggal', 'periodeLabel'
'kelasList',
'stats',
'totalSantriEligible',
'totalRecorded',
'persenHadir'
)); ));
} }
/** /**
* Edit riwayat absensi * 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) public function edit(AbsensiKegiatan $riwayat)
{ {
$riwayat->load(['santri', 'kegiatan']); $riwayat->load(['santri', 'kegiatan']);
return view('admin.kegiatan.riwayat.edit', compact('riwayat')); return view('admin.kegiatan.riwayat.edit', compact('riwayat'));
} }
/**
* Update riwayat absensi
*/
public function update(Request $request, AbsensiKegiatan $riwayat) public function update(Request $request, AbsensiKegiatan $riwayat)
{ {
$validated = $request->validate([ $validated = $request->validate([
'status' => 'required|in:Hadir,Izin,Sakit,Alpa', 'status' => 'required|in:Hadir,Izin,Sakit,Alpa,Terlambat,Pulang',
'waktu_absen' => 'nullable|date_format:H:i', 'waktu_absen' => 'nullable|date_format:H:i',
]); ]);
$riwayat->update($validated); $riwayat->update($validated);
return redirect()->route('admin.riwayat-kegiatan.index')->with('success', 'Riwayat absensi berhasil diperbarui.');
return redirect()->route('admin.riwayat-kegiatan.index')
->with('success', 'Riwayat absensi berhasil diperbarui.');
} }
/**
* Hapus riwayat absensi
*/
public function destroy(AbsensiKegiatan $riwayat) public function destroy(AbsensiKegiatan $riwayat)
{ {
$nama = $riwayat->santri->nama_lengkap; $nama = $riwayat->santri->nama_lengkap;
$riwayat->delete(); $riwayat->delete();
return redirect()->route('admin.riwayat-kegiatan.index')->with('success', "Riwayat absensi $nama berhasil dihapus.");
return redirect()->route('admin.riwayat-kegiatan.index')
->with('success', "Riwayat absensi $nama berhasil dihapus.");
}
/**
* Export/Cetak laporan (opsional - bisa dikembangkan)
*/
public function exportPdf(Request $request)
{
// Implementasi export PDF jika diperlukan
return response()->json(['message' => 'Fitur export sedang dikembangkan']);
} }
} }

View File

@ -19,7 +19,9 @@ class UserController extends Controller
*/ */
public function santriAccounts() public function santriAccounts()
{ {
$users = SantriAccount::where('role', 'santri')->with('santri')->get(); $users = SantriAccount::where('role', 'santri')
->with(['santri:id_santri,nama_lengkap,nis,nomor_hp_ortu'])
->get();
$santris_tanpa_akun = Santri::whereDoesntHave('santriAccount', function ($q) { $santris_tanpa_akun = Santri::whereDoesntHave('santriAccount', function ($q) {
$q->where('role', 'santri'); $q->where('role', 'santri');
@ -109,7 +111,9 @@ public function destroySantriAccount(string $id)
*/ */
public function waliAccounts() public function waliAccounts()
{ {
$users = SantriAccount::where('role', 'wali')->with('santri')->get(); $users = SantriAccount::where('role', 'wali')
->with(['santri:id_santri,nama_lengkap,nis,nama_orang_tua,nomor_hp_ortu'])
->get();
$santris_tanpa_wali = Santri::whereDoesntHave('santriAccount', function ($q) { $santris_tanpa_wali = Santri::whereDoesntHave('santriAccount', function ($q) {
$q->where('role', 'wali'); $q->where('role', 'wali');

View File

@ -2,39 +2,6 @@
/** /**
* EpposGLogParser.php versi 2 * EpposGLogParser.php versi 2
* app/Services/EpposGLogParser.php * app/Services/EpposGLogParser.php
*
* ═══════════════════════════════════════════════════════════════
* PERUBAHAN UTAMA dari versi 1:
* IOMd TIDAK lagi diabaikan. Setiap slot di shift mesin
* (JK1 Masuk, JK1 Pulang, JK2 Masuk, JK2 Pulang, Lb Masuk, Lb Pulang)
* bisa dipetakan ke kegiatan web yang BERBEDA.
*
* CONTOH MESIN SHOLAT:
* JK1 Masuk (IOMd=2) jam 04:00 Shubuh
* JK1 Pulang (IOMd=4) jam 05:00 Dhuhur
* JK2 Masuk (IOMd=2) jam 11:45 Ashar
* JK2 Pulang (IOMd=4) jam 12:20 Maghrib
* Lb Masuk (IOMd=2) jam 15:05 Isya
*
* CONTOH MESIN NGAJI:
* JK1 Masuk (IOMd=2) jam 05:00 Ngaji Shubuh
* JK1 Pulang (IOMd=4) jam 06:00 sekolah
* JK2 Masuk (IOMd=2) jam 13:00 Ngaji Siang
* JK2 Pulang (IOMd=4) jam 15:00 Ngaji Maghrib
* Lb Masuk (IOMd=2) jam 18:00 Ngaji Malam
*
* ═══════════════════════════════════════════════════════════════
* FORMAT GLOG.TXT (Tab-Separated):
* No | Mchn | EnNo | Name | Mode | IOMd | DateTime
* 000001 | 1 | 000000001 | helga faisa | 1 | 2 | 2026/02/28 04:05:00
*
* IOMd=2 scan MASUK (Check In)
* IOMd=4 scan PULANG (Check Out)
*
* FORMAT INFO.XLS:
* Sheet "Shift" No.Shift | JK1 Msuk | JK1 Kluar | JK2 Msuk | JK2 Kluar | Lb Msuk | Lb Kluar
* Sheet "Jadwal" No | Nama | Departemen | Shift
* ═══════════════════════════════════════════════════════════════
*/ */
namespace App\Services; namespace App\Services;
@ -44,22 +11,18 @@
class EpposGLogParser class EpposGLogParser
{ {
// IOMd values dari mesin Eppos
const IOMD_MASUK = 2; const IOMD_MASUK = 2;
const IOMD_PULANG = 4; const IOMD_PULANG = 4;
// 6 slot per shift (nama slot → key di array shift)
// Urutan ini penting untuk matching prioritas
const SLOT_KEYS = [ const SLOT_KEYS = [
'jk1_msuk', // JK1 Masuk (IOMd=2) 'jk1_msuk',
'jk1_kluar', // JK1 Pulang (IOMd=4) 'jk1_kluar',
'jk2_msuk', // JK2 Masuk (IOMd=2) 'jk2_msuk',
'jk2_kluar', // JK2 Pulang (IOMd=4) 'jk2_kluar',
'lb_msuk', // Lembur Masuk (IOMd=2) 'lb_msuk',
'lb_kluar', // Lembur Pulang (IOMd=4) 'lb_kluar',
]; ];
// Masing-masing slot → IOMd yang diharapkan
const SLOT_IOMD = [ const SLOT_IOMD = [
'jk1_msuk' => self::IOMD_MASUK, 'jk1_msuk' => self::IOMD_MASUK,
'jk1_kluar' => self::IOMD_PULANG, 'jk1_kluar' => self::IOMD_PULANG,
@ -73,25 +36,6 @@ class EpposGLogParser
// PARSE INFO.XLS // PARSE INFO.XLS
// ───────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────
/**
* Parse INFO.XLS konfigurasi shift dan daftar santri di mesin
*
* @return array [
* 'shifts' => [
* 1 => [
* 'jk1_msuk' => '04:00',
* 'jk1_kluar' => '05:00',
* 'jk2_msuk' => '11:45',
* 'jk2_kluar' => '12:20',
* 'lb_msuk' => '15:05',
* 'lb_kluar' => null, // null = slot tidak dipakai
* ],
* ],
* 'jadwal' => [
* '1' => ['nama'=>'helga faisa', 'dept'=>'Office', 'shift'=>1],
* ]
* ]
*/
public function parseInfoFile(string $path): array public function parseInfoFile(string $path): array
{ {
$spreadsheet = IOFactory::load($path); $spreadsheet = IOFactory::load($path);
@ -105,7 +49,6 @@ public function parseInfoFile(string $path): array
private function parseShifts($sheet): array private function parseShifts($sheet): array
{ {
$shifts = []; $shifts = [];
// Kolom: A=No, B=JK1 Msuk, C=JK1 Kluar, D=JK2 Msuk, E=JK2 Kluar, F=Lb Msuk, G=Lb Kluar
for ($row = 6; $row <= $sheet->getHighestRow(); $row++) { for ($row = 6; $row <= $sheet->getHighestRow(); $row++) {
$no = $sheet->getCell("A{$row}")->getValue(); $no = $sheet->getCell("A{$row}")->getValue();
if (!is_numeric($no)) continue; if (!is_numeric($no)) continue;
@ -119,7 +62,6 @@ private function parseShifts($sheet): array
'lb_kluar' => $this->readTime($sheet->getCell("G{$row}")->getValue()), 'lb_kluar' => $this->readTime($sheet->getCell("G{$row}")->getValue()),
]; ];
// Skip shift yang semua slot-nya kosong
$adaIsi = array_filter($s); $adaIsi = array_filter($s);
if (empty($adaIsi)) continue; if (empty($adaIsi)) continue;
@ -146,23 +88,9 @@ private function parseJadwal($sheet): array
} }
// ───────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────
// PARSE GLOG.TXT ← PERUBAHAN UTAMA: simpan IOMd per scan // PARSE GLOG.TXT
// ───────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────
/**
* Parse GLog.txt semua record scan, TERMASUK IOMd
*
* @return array [
* [
* 'id_mesin' => '1',
* 'nama_mesin' => 'helga faisa',
* 'tanggal' => '2026-02-28',
* 'jam' => '04:05',
* 'iomd' => 2, // ← BARU: 2=Masuk, 4=Pulang
* 'dt_raw' => '2026/02/28 04:05:00',
* ],
* ]
*/
public function parseGLog(string $path): array public function parseGLog(string $path): array
{ {
$content = file_get_contents($path); $content = file_get_contents($path);
@ -177,29 +105,26 @@ public function parseGLog(string $path): array
$cols = explode("\t", $line); $cols = explode("\t", $line);
$cols = array_values(array_filter(array_map('trim', $cols), fn($v) => $v !== '')); $cols = array_values(array_filter(array_map('trim', $cols), fn($v) => $v !== ''));
// Minimal 7 kolom: No | Mchn | EnNo | Name | Mode | IOMd | DateTime
if (count($cols) < 7) continue; if (count($cols) < 7) continue;
if ($cols[0] === 'No') continue; // header if ($cols[0] === 'No') continue;
$enno = $cols[2] ?? ''; $enno = $cols[2] ?? '';
$namaMesin = $cols[3] ?? ''; $namaMesin = $cols[3] ?? '';
$iomdRaw = $cols[5] ?? ''; // kolom ke-6 (index 5) $iomdRaw = $cols[5] ?? '';
$dtRaw = $cols[6] ?? ''; $dtRaw = $cols[6] ?? '';
if (!is_numeric(ltrim($enno, '0') ?: '0')) continue; if (!is_numeric(ltrim($enno, '0') ?: '0')) continue;
if (empty($dtRaw)) continue; if (empty($dtRaw)) continue;
// IOMd: harus 2 atau 4
$iomd = (int)$iomdRaw; $iomd = (int)$iomdRaw;
if (!in_array($iomd, [self::IOMD_MASUK, self::IOMD_PULANG])) continue; if (!in_array($iomd, [self::IOMD_MASUK, self::IOMD_PULANG])) continue;
// Parse DateTime
$dtRaw = preg_replace('/\s+/', ' ', trim($dtRaw)); $dtRaw = preg_replace('/\s+/', ' ', trim($dtRaw));
$parts = explode(' ', $dtRaw); $parts = explode(' ', $dtRaw);
if (count($parts) < 2) continue; if (count($parts) < 2) continue;
$tglStr = $parts[0]; // "2026/02/28" $tglStr = $parts[0];
$jamStr = substr($parts[1], 0, 5); // "04:05" $jamStr = substr($parts[1], 0, 5);
if (!preg_match('/^\d{4}\/\d{2}\/\d{2}$/', $tglStr)) continue; if (!preg_match('/^\d{4}\/\d{2}\/\d{2}$/', $tglStr)) continue;
if (!preg_match('/^\d{2}:\d{2}$/', $jamStr)) continue; if (!preg_match('/^\d{2}:\d{2}$/', $jamStr)) continue;
@ -212,7 +137,7 @@ public function parseGLog(string $path): array
'nama_mesin' => trim($namaMesin), 'nama_mesin' => trim($namaMesin),
'tanggal' => $tanggal, 'tanggal' => $tanggal,
'jam' => $jamStr, 'jam' => $jamStr,
'iomd' => $iomd, // ← BARU 'iomd' => $iomd,
'dt_raw' => $dtRaw, 'dt_raw' => $dtRaw,
]; ];
} }
@ -221,25 +146,9 @@ public function parseGLog(string $path): array
} }
// ───────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────
// GROUP BY DAY ← PERUBAHAN: scans sekarang simpan iomd // GROUP BY DAY
// ───────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────
/**
* Kelompokkan per (id_mesin + tanggal)
* scans sekarang array of ['jam'=>'04:05','iomd'=>2]
*
* @return array [
* '1_2026-02-28' => [
* 'id_mesin' => '1',
* 'nama_mesin' => 'helga faisa',
* 'tanggal' => '2026-02-28',
* 'scans' => [
* ['jam'=>'04:05','iomd'=>2],
* ['jam'=>'05:10','iomd'=>4],
* ],
* ],
* ]
*/
public function groupGLogByDay(array $records): array public function groupGLogByDay(array $records): array
{ {
$grouped = []; $grouped = [];
@ -256,7 +165,6 @@ public function groupGLogByDay(array $records): array
]; ];
} }
// Hindari duplikat jam+iomd yang persis sama
$duplikat = array_filter( $duplikat = array_filter(
$grouped[$key]['scans'], $grouped[$key]['scans'],
fn($s) => $s['jam'] === $r['jam'] && $s['iomd'] === $r['iomd'] fn($s) => $s['jam'] === $r['jam'] && $s['iomd'] === $r['iomd']
@ -269,7 +177,6 @@ public function groupGLogByDay(array $records): array
]; ];
} }
// Sort scan berurutan berdasarkan jam
foreach ($grouped as &$g) { foreach ($grouped as &$g) {
usort($g['scans'], fn($a, $b) => strcmp($a['jam'], $b['jam'])); usort($g['scans'], fn($a, $b) => strcmp($a['jam'], $b['jam']));
} }
@ -278,32 +185,27 @@ public function groupGLogByDay(array $records): array
} }
// ───────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────
// MATCH TO KEGIATAN ← PERUBAHAN UTAMA // MATCH TO KEGIATAN
// ───────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────
/** /**
* Cocokkan setiap scan ke kegiatan web. * Cocokkan setiap scan ke kegiatan web.
* *
* LOGIKA BARU (pakai IOMd): * STATUS Hadir / Terlambat ditentukan berdasarkan $tolSesudah:
* ────────────────────────────────────────────────────────── * ─────────────────────────────────────────────────────────────
* 1. Ambil shift santri dari infoData['jadwal'] * scan <= waktu_mulai + $tolSesudah Hadir
* 2. Buat "slot windows" dari shift tersebut: * scan > waktu_mulai + $tolSesudah Terlambat
* Setiap slot (jk1_msuk, jk1_kluar, dst) punya jam + IOMd
* 3. Untuk setiap scan (jam + iomd):
* a. Cari slot yang IOMd-nya cocok DAN jam scan masuk window ±toleransi
* b. Dari slot yang cocok, cari kegiatan web hari ini yang waktunya paling dekat
* 4. Hasilkan baris per kegiatan: Hadir / Terlambat / Alpa
* *
* FALLBACK (tanpa IOMd, jika infoData kosong): * Contoh: tolSesudah=30, kegiatan mulai 04:00
* Jika santri tidak ada di infoData (baru daftar, seperti firda), * Scan 04:07 (+7 menit) Hadir (7 30)
* cocokkan hanya berdasarkan jam (abaikan IOMd) dengan toleransi lebih sempit. * Scan 04:35 (+35 menit) Terlambat (35 > 30)
* ────────────────────────────────────────────────────────── * ─────────────────────────────────────────────────────────────
* *
* @param array $glogGrouped Output groupGLogByDay() * @param array $glogGrouped Output groupGLogByDay()
* @param array $infoData Output parseInfoFile() ['shifts'=>[...],'jadwal'=>[...]] * @param array $infoData Output parseInfoFile()
* @param array $kegiatans Dari DB: [['kegiatan_id','nama','hari','waktu_mulai','waktu_selesai'],...] * @param array $kegiatans Dari DB
* @param int $tolSebelum Menit toleransi SEBELUM waktu_mulai kegiatan * @param int $tolSebelum Menit toleransi SEBELUM waktu_mulai (window masuk)
* @param int $tolSesudah Menit toleransi SESUDAH waktu_selesai kegiatan * @param int $tolSesudah Menit toleransi SESUDAH waktu_mulai (Hadir/Terlambat cut-off)
*/ */
public function matchToKegiatan( public function matchToKegiatan(
array $glogGrouped, array $glogGrouped,
@ -317,31 +219,26 @@ public function matchToKegiatan(
foreach ($glogGrouped as $dayData) { foreach ($glogGrouped as $dayData) {
$tanggal = $dayData['tanggal']; $tanggal = $dayData['tanggal'];
$idMesin = $dayData['id_mesin']; $idMesin = $dayData['id_mesin'];
$scans = $dayData['scans']; // [['jam'=>'04:05','iomd'=>2], ...] $scans = $dayData['scans'];
$hari = $this->tanggalToHari($tanggal); $hari = $this->tanggalToHari($tanggal);
// Kegiatan hari ini dari web
$kegHariIni = array_values( $kegHariIni = array_values(
array_filter($kegiatans, fn($k) => $k['hari'] === $hari) array_filter($kegiatans, fn($k) => $k['hari'] === $hari)
); );
// Info shift santri ini dari INFO.XLS
$jadwalInfo = $infoData['jadwal'][$idMesin] ?? null; $jadwalInfo = $infoData['jadwal'][$idMesin] ?? null;
$nomorShift = $jadwalInfo ? ($jadwalInfo['shift'] ?? 1) : null; $nomorShift = $jadwalInfo ? ($jadwalInfo['shift'] ?? 1) : null;
$shiftData = ($nomorShift && isset($infoData['shifts'][$nomorShift])) $shiftData = ($nomorShift && isset($infoData['shifts'][$nomorShift]))
? $infoData['shifts'][$nomorShift] ? $infoData['shifts'][$nomorShift]
: null; : null;
// Build slot windows dari shift santri
// slotWindows: [ ['slot'=>'jk1_msuk','jam'=>'04:00','iomd'=>2], ... ]
$slotWindows = $shiftData $slotWindows = $shiftData
? $this->buildSlotWindows($shiftData) ? $this->buildSlotWindows($shiftData)
: []; : [];
// ── Matching ──────────────────────────────────────────── $matchedKg = [];
$matchedKg = []; // kegiatan_id → true (sudah dapat scan) $usedScans = [];
$usedScans = []; // index scan yang sudah dipakai $rowMap = [];
$rowMap = []; // kegiatan_id → result row
foreach ($scans as $idx => $scan) { foreach ($scans as $idx => $scan) {
$scanJam = $scan['jam']; $scanJam = $scan['jam'];
@ -353,11 +250,10 @@ public function matchToKegiatan(
$bestSlot = null; $bestSlot = null;
if (!empty($slotWindows)) { if (!empty($slotWindows)) {
// ── MODE UTAMA: pakai IOMd dari shift ────────────── // ── MODE UTAMA: cocokkan pakai IOMd dari shift ──────
// Langkah 1: cari slot yang IOMd-nya cocok DAN jam dalam window
foreach ($slotWindows as $sw) { foreach ($slotWindows as $sw) {
if ($sw['iomd'] !== $scanIomd) continue; // IOMd harus cocok if ($sw['iomd'] !== $scanIomd) continue;
if ($sw['jam'] === null) continue; // slot tidak diset if ($sw['jam'] === null) continue;
$slotMnt = $this->toMinutes($sw['jam']); $slotMnt = $this->toMinutes($sw['jam']);
$windowMulai = $slotMnt - $tolSebelum; $windowMulai = $slotMnt - $tolSebelum;
@ -365,7 +261,6 @@ public function matchToKegiatan(
if ($scanMnt < $windowMulai || $scanMnt > $windowAkhir) continue; if ($scanMnt < $windowMulai || $scanMnt > $windowAkhir) continue;
// Slot cocok — sekarang cari kegiatan web yang paling dekat
foreach ($kegHariIni as $kg) { foreach ($kegHariIni as $kg) {
if (isset($matchedKg[$kg['kegiatan_id']])) continue; if (isset($matchedKg[$kg['kegiatan_id']])) continue;
@ -374,7 +269,6 @@ public function matchToKegiatan(
$kgWindowMul = $kgMulaiMnt - $tolSebelum; $kgWindowMul = $kgMulaiMnt - $tolSebelum;
$kgWindowAkh = $kgSelesaiMnt + $tolSesudah; $kgWindowAkh = $kgSelesaiMnt + $tolSesudah;
// Jam slot harus masuk window kegiatan
if ($slotMnt < $kgWindowMul || $slotMnt > $kgWindowAkh) continue; if ($slotMnt < $kgWindowMul || $slotMnt > $kgWindowAkh) continue;
$selisih = abs($slotMnt - $kgMulaiMnt); $selisih = abs($slotMnt - $kgMulaiMnt);
@ -386,16 +280,12 @@ public function matchToKegiatan(
} }
} }
} else { } else {
// ── FALLBACK: shifts kosong, matching hanya berdasarkan jam ── // ── FALLBACK: shifts kosong, matching hanya berdasar jam ──
// Pakai toleransi penuh (bukan dikurangi)
// Cari kegiatan yang paling dekat jamnya dengan scan
foreach ($kegHariIni as $kg) { foreach ($kegHariIni as $kg) {
if (isset($matchedKg[$kg['kegiatan_id']])) continue; if (isset($matchedKg[$kg['kegiatan_id']])) continue;
$kgMulaiMnt = $this->toMinutes($kg['waktu_mulai']); $kgMulaiMnt = $this->toMinutes($kg['waktu_mulai']);
$kgSelesaiMnt = $this->toMinutes($kg['waktu_selesai'] ?: $kg['waktu_mulai']); $kgSelesaiMnt = $this->toMinutes($kg['waktu_selesai'] ?: $kg['waktu_mulai']);
// Window: tolSebelum menit sebelum mulai s/d tolSesudah menit setelah selesai
$kgWindowMul = $kgMulaiMnt - $tolSebelum; $kgWindowMul = $kgMulaiMnt - $tolSebelum;
$kgWindowAkh = $kgSelesaiMnt + $tolSesudah; $kgWindowAkh = $kgSelesaiMnt + $tolSesudah;
@ -409,15 +299,20 @@ public function matchToKegiatan(
} }
} }
// ── Simpan hasil match ────────────────────────────
if ($bestKg) { if ($bestKg) {
$kgMulaiMnt = $this->toMinutes($bestKg['waktu_mulai']); $kgMulaiMnt = $this->toMinutes($bestKg['waktu_mulai']);
// Grace period: scan sampai 5 menit setelah mulai → masih Hadir
// Lebih dari 5 menit → Terlambat
$graceMnt = 5;
$selisih = $scanMnt - $kgMulaiMnt; $selisih = $scanMnt - $kgMulaiMnt;
$status = $selisih <= $graceMnt ? 'Hadir' : 'Terlambat';
// ─────────────────────────────────────────────────────
// STATUS Hadir vs Terlambat:
// Hadir → scan tiba SEBELUM atau tepat waktu +$tolSesudah menit
// Terlambat → scan tiba LEBIH dari $tolSesudah menit setelah mulai
//
// Dengan begitu: toleransi dari form LANGSUNG menentukan batas
// Hadir/Terlambat — tidak ada nilai hardcode di sini.
// ─────────────────────────────────────────────────────
$status = $selisih <= $tolSesudah ? 'Hadir' : 'Terlambat';
$selisihTampil = $selisih > 0 ? $selisih : 0; // menit telat (hanya jika positif)
$matchedKg[$bestKg['kegiatan_id']] = true; $matchedKg[$bestKg['kegiatan_id']] = true;
$usedScans[] = $idx; $usedScans[] = $idx;
@ -430,13 +325,13 @@ public function matchToKegiatan(
'iomd_scan' => $scanIomd, 'iomd_scan' => $scanIomd,
'label_iomd' => $scanIomd === self::IOMD_MASUK ? 'Masuk' : 'Pulang', 'label_iomd' => $scanIomd === self::IOMD_MASUK ? 'Masuk' : 'Pulang',
'status' => $status, 'status' => $status,
'selisih_menit' => max(0, $selisih - $graceMnt), // hanya menit yg melebihi grace 'selisih_menit' => $selisihTampil,
'matched' => true, 'matched' => true,
]; ];
} }
} }
// ── Isi Alpa untuk kegiatan tanpa scan ─────────────── // ── Alpa untuk kegiatan tanpa scan ───────────────────
foreach ($kegHariIni as $kg) { foreach ($kegHariIni as $kg) {
if (!isset($rowMap[$kg['kegiatan_id']])) { if (!isset($rowMap[$kg['kegiatan_id']])) {
$rowMap[$kg['kegiatan_id']] = [ $rowMap[$kg['kegiatan_id']] = [
@ -453,11 +348,11 @@ public function matchToKegiatan(
} }
} }
// Scan yang tidak cocok ke kegiatan apapun
$unmatchedScans = []; $unmatchedScans = [];
foreach ($scans as $idx => $scan) { foreach ($scans as $idx => $scan) {
if (!in_array($idx, $usedScans)) { if (!in_array($idx, $usedScans)) {
$unmatchedScans[] = $scan['jam'] . ' (' . ($scan['iomd'] === 2 ? 'Masuk' : 'Pulang') . ')'; $unmatchedScans[] = $scan['jam']
. ' (' . ($scan['iomd'] === 2 ? 'Masuk' : 'Pulang') . ')';
} }
} }
@ -470,7 +365,7 @@ public function matchToKegiatan(
'hari' => $hari, 'hari' => $hari,
'all_scans' => $scans, 'all_scans' => $scans,
'unmatched_scans' => $unmatchedScans, 'unmatched_scans' => $unmatchedScans,
'shift_dipakai' => $nomorShift, // ← BARU: untuk debug di preview 'shift_dipakai' => $nomorShift,
'rows' => $rows, 'rows' => $rows,
]; ];
} }
@ -479,22 +374,9 @@ public function matchToKegiatan(
} }
// ───────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────
// BUILD SLOT WINDOWS dari data shift // BUILD SLOT WINDOWS
// ───────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────
/**
* Dari satu shift, buat array slot windows yang bisa dicocokkan dengan scan.
*
* @param array $shiftData ['jk1_msuk'=>'04:00','jk1_kluar'=>'05:00', ...]
* @return array [
* ['slot'=>'jk1_msuk', 'jam'=>'04:00', 'iomd'=>2],
* ['slot'=>'jk1_kluar', 'jam'=>'05:00', 'iomd'=>4],
* ['slot'=>'jk2_msuk', 'jam'=>'11:45', 'iomd'=>2],
* ['slot'=>'jk2_kluar', 'jam'=>'12:20', 'iomd'=>4],
* ['slot'=>'lb_msuk', 'jam'=>'15:05', 'iomd'=>2],
* ['slot'=>'lb_kluar', 'jam'=>null, 'iomd'=>4], // null = tidak dipakai
* ]
*/
private function buildSlotWindows(array $shiftData): array private function buildSlotWindows(array $shiftData): array
{ {
$windows = []; $windows = [];
@ -532,9 +414,6 @@ public function tanggalToHari(string $tanggal): string
][Carbon::parse($tanggal)->format('l')] ?? 'Senin'; ][Carbon::parse($tanggal)->format('l')] ?? 'Senin';
} }
/**
* Baca nilai jam dari Excel bisa berupa string "05:00" atau float (serial Excel)
*/
private function readTime($val): ?string private function readTime($val): ?string
{ {
if ($val === null || $val === '') return null; if ($val === null || $val === '') return null;

55
sim-pkpps/index.php Normal file
View File

@ -0,0 +1,55 @@
<?php
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Http\Request;
define('LARAVEL_START', microtime(true));
/*
|--------------------------------------------------------------------------
| Check If The Application Is Under Maintenance
|--------------------------------------------------------------------------
|
| If the application is in maintenance / demo mode via the "down" command
| we will load this file so that any pre-rendered content can be shown
| instead of starting the framework, which could cause an exception.
|
*/
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
require $maintenance;
}
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| this application. We just need to utilize it! We'll simply require it
| into the script here so we don't need to manually load our classes.
|
*/
require __DIR__.'/../vendor/autoload.php';
/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request using
| the application's HTTP kernel. Then, we will send the response back
| to this client's browser, allowing them to enjoy our application.
|
*/
$app = require_once __DIR__.'/../bootstrap/app.php';
$kernel = $app->make(Kernel::class);
$response = $kernel->handle(
$request = Request::capture()
)->send();
$kernel->terminate($request, $response);

BIN
sim-pkpps/laravel.zip Normal file

Binary file not shown.

BIN
sim-pkpps/public.zip Normal file

Binary file not shown.

View File

@ -461,7 +461,10 @@ .main-content-wrapper {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 100vh; min-height: 100vh;
min-width: 0;
max-width: 100%;
transition: margin-left 0.3s ease; transition: margin-left 0.3s ease;
overflow-x: hidden;
} }
.main-header { .main-header {
@ -497,8 +500,11 @@ .sidebar-toggle-btn:hover {
.main-content { .main-content {
padding: clamp(10px, 1.2vw, 16px); padding: clamp(10px, 1.2vw, 16px);
flex-grow: 1; flex-grow: 1;
min-width: 0;
max-width: 100%;
transition: opacity 0.3s ease-in; transition: opacity 0.3s ease-in;
opacity: 1; opacity: 1;
overflow-x: hidden;
} }
/* =================================== /* ===================================
@ -632,6 +638,9 @@ .content-box {
border-radius: var(--border-radius); border-radius: var(--border-radius);
box-shadow: var(--shadow-sm); box-shadow: var(--shadow-sm);
border: 1px solid var(--primary-light); border: 1px solid var(--primary-light);
min-width: 0;
max-width: 100%;
overflow: hidden;
} }
/* =================================== /* ===================================
@ -682,6 +691,10 @@ .alert {
display: flex; display: flex;
align-items: center; align-items: center;
animation: slideInDown 0.4s ease; animation: slideInDown 0.4s ease;
min-width: 0;
max-width: 100%;
overflow-wrap: break-word;
word-break: break-word;
} }
.alert-success { .alert-success {
@ -1056,6 +1069,7 @@ .table-wrapper {
overflow-x: auto; overflow-x: auto;
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
margin-bottom: 16px; margin-bottom: 16px;
max-width: 100%;
} }
.table-wrapper .data-table { .table-wrapper .data-table {
@ -2147,7 +2161,7 @@ @media (max-width: 480px) {
/* 5-column KPI row */ /* 5-column KPI row */
.row-cards-5 { .row-cards-5 {
display: grid; display: grid;
grid-template-columns: repeat(5, 1fr); grid-template-columns: repeat(auto-fit, minmax(min(140px, 100%), 1fr));
gap: 10px; gap: 10px;
margin-bottom: 16px; margin-bottom: 16px;
} }
@ -2165,6 +2179,7 @@ .dash-grid-2 {
grid-template-columns: 3fr 2fr; grid-template-columns: 3fr 2fr;
gap: 14px; gap: 14px;
margin-bottom: 16px; margin-bottom: 16px;
min-width: 0;
} }
/* Chart containers */ /* Chart containers */
@ -2184,6 +2199,8 @@ .chart-container {
position: relative; position: relative;
height: 200px; height: 200px;
width: 100%; width: 100%;
min-width: 0;
max-width: 100%;
} }
.chart-container-sm { .chart-container-sm {
@ -2330,15 +2347,24 @@ @media (max-width: 768px) {
.row-cards-5 { .row-cards-5 {
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
} }
.dash-fin-grid {
grid-template-columns: 1fr;
}
.chart-container {
height: 180px;
}
} }
@media (max-width: 480px) { @media (max-width: 480px) {
.row-cards-5 { .row-cards-5 {
grid-template-columns: repeat(2, 1fr); grid-template-columns: 1fr 1fr;
} }
.spp-summary { .spp-summary {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.chart-container {
height: 160px;
}
} }
/* =================================== /* ===================================

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 277 KiB

View File

@ -216,91 +216,6 @@
border-color:#6FBA9D; background:#fff; box-shadow:0 0 0 3px rgba(111,186,157,.1); border-color:#6FBA9D; background:#fff; box-shadow:0 0 0 3px rgba(111,186,157,.1);
} }
/* ── Demo Account Button ── */
.lg-demo-btn {
display:flex; align-items:center; justify-content:center; gap:8px;
margin-top:10px; padding:9px;
background:transparent; border:1.5px dashed #A8D8C6; border-radius:10px;
font-size:.76rem; font-weight:600; color:#8AADA0; cursor:pointer;
font-family:inherit; width:100%;
transition:all .2s;
}
.lg-demo-btn:hover { border-color:#6FBA9D; color:#3D8A6E; background:#EBF7F2; }
/* ── Modal Overlay ── */
.lg-modal-overlay {
position:fixed; inset:0; z-index:9999;
background:rgba(15,33,24,.45); backdrop-filter:blur(4px);
display:flex; align-items:center; justify-content:center;
opacity:0; pointer-events:none; transition:opacity .25s ease;
}
.lg-modal-overlay.open { opacity:1; pointer-events:all; }
/* ── Modal Box ── */
.lg-modal {
background:#fff; border-radius:20px; padding:32px 28px;
width:100%; max-width:380px; position:relative;
box-shadow:0 20px 60px rgba(15,33,24,.18);
transform:translateY(16px) scale(.97); transition:transform .25s ease;
}
.lg-modal-overlay.open .lg-modal { transform:translateY(0) scale(1); }
.lg-modal::before {
content:''; position:absolute; top:0; left:0; right:0; height:3px;
background:linear-gradient(90deg,#6FBA9D,#A8D8C6,#6FBA9D);
border-radius:20px 20px 0 0;
}
.lg-modal-close {
position:absolute; top:14px; right:16px;
background:none; border:none; font-size:1.1rem;
color:#B8D4C8; cursor:pointer; line-height:1;
transition:color .2s;
}
.lg-modal-close:hover { color:#3D8A6E; }
.lg-modal-ico {
width:44px; height:44px; border-radius:12px; background:#EBF7F2;
display:flex; align-items:center; justify-content:center;
color:#3D8A6E; font-size:1rem; margin-bottom:14px;
}
.lg-modal-title {
font-family:'DM Serif Display',serif;
font-size:1.35rem; color:#0F2118; margin-bottom:4px;
}
.lg-modal-sub { font-size:.75rem; color:#8AADA0; margin-bottom:20px; line-height:1.5; }
.lg-demo-table { width:100%; border-collapse:collapse; }
.lg-demo-table thead tr th {
font-size:.64rem; font-weight:700; letter-spacing:1.2px;
text-transform:uppercase; color:#8AADA0;
padding:0 10px 8px; text-align:left;
border-bottom:1px solid #EBF7F2;
}
.lg-demo-table tbody tr { transition:background .15s; }
.lg-demo-table tbody tr:hover { background:#F4FCF8; }
.lg-demo-table tbody tr td {
padding:10px 10px; font-size:.78rem; color:#2A4235;
border-bottom:1px solid #F0FAF5; vertical-align:middle;
}
.lg-demo-table tbody tr:last-child td { border-bottom:none; }
.lg-role-badge {
display:inline-block; padding:2px 8px;
border-radius:20px; font-size:.66rem; font-weight:700;
letter-spacing:.5px;
}
.badge-super { background:#FFF3E0; color:#E65100; }
.badge-akademik { background:#E3F2FD; color:#1565C0; }
.badge-pamong { background:#F3E5F5; color:#6A1B9A; }
.badge-santri { background:#E8F5E9; color:#2E7D32; }
.lg-copy-btn {
background:none; border:none; color:#A8D8C6; cursor:pointer;
font-size:.72rem; padding:2px 4px; border-radius:4px;
transition:color .2s;
}
.lg-copy-btn:hover { color:#3D8A6E; }
.lg-modal-note {
margin-top:16px; padding:10px 12px;
background:#FFFBF0; border-left:3px solid #FFD54F;
border-radius:8px; font-size:.72rem; color:#795548; line-height:1.6;
}
/* Responsive */ /* Responsive */
@media (max-width: 900px) { @media (max-width: 900px) {
.lg-layout { gap:48px; padding:32px 36px; } .lg-layout { gap:48px; padding:32px 36px; }
@ -444,11 +359,6 @@
<i class="fas fa-user-graduate"></i> Login sebagai Santri / Wali <i class="fas fa-user-graduate"></i> Login sebagai Santri / Wali
</a> </a>
{{-- ── Tombol Akun Demo (tambahan) ── --}}
<button type="button" class="lg-demo-btn" id="lgDemoBtn">
<i class="fas fa-info-circle"></i> Lihat Akun Demo untuk Pengujian
</button>
</form> </form>
</div> </div>
</div> </div>
@ -456,76 +366,6 @@
</div> </div>
</div> </div>
{{-- ── Modal Akun Demo ── --}}
<div class="lg-modal-overlay" id="lgDemoOverlay">
<div class="lg-modal">
<button class="lg-modal-close" id="lgModalClose" aria-label="Tutup">
<i class="fas fa-times"></i>
</button>
<div class="lg-modal-ico"><i class="fas fa-users"></i></div>
<div class="lg-modal-title">Akun Demo</div>
<table class="lg-demo-table">
<thead>
<tr>
<th>Role</th>
<th>Email / Username</th>
<th>Password</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="lg-role-badge badge-super">Superadmin</span></td>
<td style="font-size:.72rem;">helga.faisa06@gmail.com</td>
<td style="font-size:.72rem;">Admin123_</td>
<td>
<button class="lg-copy-btn" onclick="lgCopy('helga.faisa06@gmail.com','Admin123_')" title="Isi otomatis">
<i class="fas fa-arrow-right"></i>
</button>
</td>
</tr>
<tr>
<td><span class="lg-role-badge badge-akademik">Akademik</span></td>
<td style="font-size:.72rem;">akademik@test.com</td>
<td style="font-size:.72rem;">password123</td>
<td>
<button class="lg-copy-btn" onclick="lgCopy('akademik@test.com','password123')" title="Isi otomatis">
<i class="fas fa-arrow-right"></i>
</button>
</td>
</tr>
<tr>
<td><span class="lg-role-badge badge-pamong">Pamong</span></td>
<td style="font-size:.72rem;">pamong@test.com</td>
<td style="font-size:.72rem;">password123</td>
<td>
<button class="lg-copy-btn" onclick="lgCopy('pamong@test.com','password123')" title="Isi otomatis">
<i class="fas fa-arrow-right"></i>
</button>
</td>
</tr>
<tr>
<td><span class="lg-role-badge badge-santri">Santri</span></td>
<td style="font-size:.72rem;">Helga Faisa</td>
<td style="font-size:.72rem;">s001</td>
<td>
<button class="lg-copy-btn" onclick="lgCopy('Helga Faisa','s001')" title="Isi otomatis">
<i class="fas fa-arrow-right"></i>
</button>
</td>
</tr>
</tbody>
</table>
<div class="lg-modal-note">
<i class="fas fa-info-circle"></i>
Klik <i class="fas fa-arrow-right"></i> untuk mengisi form login otomatis.
Akun santri dapat digunakan di halaman login santri.
</div>
</div>
</div>
<script> <script>
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
// Toggle password // Toggle password
@ -581,33 +421,6 @@
if (e.key === 'Enter') { e.preventDefault(); p.focus(); } if (e.key === 'Enter') { e.preventDefault(); p.focus(); }
}); });
} }
// ── Demo Modal ──
const demoBtn = document.getElementById('lgDemoBtn');
const overlay = document.getElementById('lgDemoOverlay');
const modalClose = document.getElementById('lgModalClose');
function openModal() { overlay.classList.add('open'); }
function closeModal() { overlay.classList.remove('open'); }
if (demoBtn) demoBtn.addEventListener('click', openModal);
if (modalClose) modalClose.addEventListener('click', closeModal);
if (overlay) overlay.addEventListener('click', function(e) {
if (e.target === overlay) closeModal();
}); });
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') closeModal();
});
});
// Auto-fill form dari modal
function lgCopy(email, pass) {
const u = document.getElementById('username');
const p = document.getElementById('password');
if (u) u.value = email;
if (p) p.value = pass;
document.getElementById('lgDemoOverlay').classList.remove('open');
if (u) u.focus();
}
</script> </script>
@endsection @endsection

View File

@ -3,25 +3,102 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rapor Capaian - {{ $santri->nama_lengkap }} - {{ $semester->nama_semester }}</title> <title>Capaian Materi {{ $santri->nama_lengkap }}</title>
<style> <style>
* { margin: 0; padding: 0; box-sizing: border-box; } /* ── RESET & BASE ── */
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; color: #333; background: #fff; padding: 20px; font-size: 11pt; } *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
.rapor-header { text-align: center; padding-bottom: 20px; border-bottom: 3px double #6FBA9D; margin-bottom: 24px; } body {
.rapor-header h1 { font-size: 16pt; color: #2e7d32; margin-bottom: 4px; } font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
.rapor-header h2 { font-size: 12pt; color: #555; font-weight: 400; margin-bottom: 8px; } color: #222;
.rapor-header .subtitle { font-size: 10pt; color: #888; } background: #fff;
font-size: 10.5pt;
line-height: 1.5;
}
.info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0; margin-bottom: 24px; background: #f8faf9; border-radius: 8px; padding: 16px; border: 1px solid #e0e0e0; } /* ── SCREEN WRAPPER ── */
.info-item { padding: 4px 0; font-size: 10pt; } .page-wrap {
.info-item .label { color: #888; display: inline-block; width: 130px; } max-width: 210mm;
.info-item .value { font-weight: 600; color: #333; } margin: 0 auto;
padding: 16mm 14mm;
}
/* ── PRINT BUTTON (screen only) ── */
.print-btn {
position: fixed;
bottom: 24px;
right: 24px;
background: #6FBA9D;
color: #fff;
border: none;
padding: 11px 22px;
border-radius: 8px;
font-size: 10.5pt;
font-weight: 700;
cursor: pointer;
box-shadow: 0 4px 14px rgba(111,186,157,.45);
z-index: 999;
display: flex;
align-items: center;
gap: 7px;
}
.print-btn:hover { background: #5EA98C; }
/* ════════════════════════════
HEADER
════════════════════════════ */
.rapor-header {
text-align: center;
padding-bottom: 14px;
border-bottom: 3px double #6FBA9D;
margin-bottom: 18px;
break-inside: avoid;
page-break-inside: avoid;
}
.rapor-header h1 { font-size: 15pt; color: #2e7d32; margin-bottom: 3px; letter-spacing: .5px; }
.rapor-header h2 { font-size: 11pt; color: #555; font-weight: 400; margin-bottom: 6px; }
.rapor-header .subtitle { font-size: 9.5pt; color: #888; }
/* ════════════════════════════
INFO SANTRI
════════════════════════════ */
.info-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 3px 20px;
background: #f7faf8;
border: 1px solid #dde8e3;
border-radius: 7px;
padding: 12px 14px;
margin-bottom: 18px;
break-inside: avoid;
page-break-inside: avoid;
}
.info-item { font-size: 9.5pt; padding: 2px 0; }
.info-item .label { color: #888; display: inline-block; width: 124px; }
.info-item .value { font-weight: 600; color: #222; }
/* ════════════════════════════
SUMMARY BOXES
════════════════════════════ */
.summary-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
margin-bottom: 22px;
break-inside: avoid;
page-break-inside: avoid;
}
.summary-box {
text-align: center;
padding: 12px 8px;
border-radius: 7px;
border: 1px solid #e0e0e0;
}
.summary-box .sb-val { font-size: 17pt; font-weight: 800; line-height: 1.1; }
.summary-box .sb-label { font-size: 7.5pt; color: #888; text-transform: uppercase; letter-spacing: .5px; margin-top: 3px; }
.summary-box .sb-comp { font-size: 8pt; margin-top: 4px; }
.summary-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 24px; }
.summary-box { text-align: center; padding: 14px 10px; border-radius: 8px; border: 1px solid #e0e0e0; }
.summary-box .sb-val { font-size: 18pt; font-weight: 800; }
.summary-box .sb-label { font-size: 8pt; color: #888; text-transform: uppercase; letter-spacing: 0.5px; margin-top: 2px; }
.sb-green { border-color: #c8e6c9; background: #f1f8e9; } .sb-green { border-color: #c8e6c9; background: #f1f8e9; }
.sb-green .sb-val { color: #2e7d32; } .sb-green .sb-val { color: #2e7d32; }
.sb-blue { border-color: #bbdefb; background: #e3f2fd; } .sb-blue { border-color: #bbdefb; background: #e3f2fd; }
@ -31,82 +108,253 @@
.sb-red { border-color: #ffcdd2; background: #fbe9e7; } .sb-red { border-color: #ffcdd2; background: #fbe9e7; }
.sb-red .sb-val { color: #c62828; } .sb-red .sb-val { color: #c62828; }
h3 { font-size: 12pt; color: #2e7d32; margin-bottom: 12px; padding-bottom: 6px; border-bottom: 2px solid #e8f5e9; } .comp-up { color: #2e7d32; }
.comp-down { color: #c62828; }
.comp-same { color: #999; }
/* ════════════════════════════
SECTION HEADINGS
════════════════════════════ */
.section-title {
font-size: 11pt;
font-weight: 700;
color: #2e7d32;
padding: 6px 10px;
border-left: 4px solid #6FBA9D;
background: #f1f8e9;
border-radius: 0 5px 5px 0;
margin-bottom: 10px;
/* Judul selalu ikut tabel di bawahnya */
break-after: avoid;
page-break-after: avoid;
}
/* ════════════════════════════
TABLES
════════════════════════════ */
.tbl-wrap {
margin-bottom: 22px;
/* Bungkus tabel agar tidak terpotong (berlaku jika tabel kecil) */
}
table {
width: 100%;
border-collapse: collapse;
font-size: 9pt;
/* Header tabel muncul ulang di setiap halaman baru */
}
/* Header tabel muncul di setiap halaman */
thead { display: table-header-group; }
tfoot { display: table-footer-group; }
th {
background: #e8f5e9;
color: #1b5e20;
font-weight: 700;
padding: 7px 6px;
text-align: left;
border: 1px solid #c8e6c9;
font-size: 8pt;
text-transform: uppercase;
letter-spacing: .3px;
/* Judul kolom jangan terpotong */
page-break-inside: avoid;
break-inside: avoid;
}
td {
padding: 6px 6px;
border: 1px solid #e0e0e0;
vertical-align: middle;
}
table { width: 100%; border-collapse: collapse; margin-bottom: 24px; font-size: 9.5pt; }
th { background: #e8f5e9; color: #2e7d32; font-weight: 700; padding: 8px 6px; text-align: left; border: 1px solid #c8e6c9; font-size: 8.5pt; text-transform: uppercase; letter-spacing: 0.3px; }
td { padding: 7px 6px; border: 1px solid #e0e0e0; }
tbody tr:nth-child(even) { background: #fafafa; } tbody tr:nth-child(even) { background: #fafafa; }
tbody tr:hover { background: #f1f8e9; }
.progress-cell { width: 100px; } /* KUNCI: setiap baris tabel tidak terpotong di tengah */
.prog-bar-mini { height: 8px; background: #e8e8e8; border-radius: 4px; overflow: hidden; } tbody tr {
break-inside: avoid;
page-break-inside: avoid;
}
/* ── Progress bar mini ── */
.prog-bar-mini {
height: 7px;
background: #eee;
border-radius: 4px;
overflow: hidden;
min-width: 70px;
}
.prog-fill-mini { height: 100%; border-radius: 4px; } .prog-fill-mini { height: 100%; border-radius: 4px; }
.badge-sm { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 8pt; font-weight: 600; } /* ── Badges ── */
.badge-sm {
display: inline-block;
padding: 2px 7px;
border-radius: 10px;
font-size: 8pt;
font-weight: 600;
white-space: nowrap;
}
.badge-success { background: #e8f5e9; color: #2e7d32; } .badge-success { background: #e8f5e9; color: #2e7d32; }
.badge-warning { background: #fff8e1; color: #f57f17; } .badge-warning { background: #fff8e1; color: #f57f17; }
.badge-danger { background: #fbe9e7; color: #c62828; } .badge-danger { background: #fbe9e7; color: #c62828; }
.badge-info { background: #e3f2fd; color: #1565c0; } .badge-info { background: #e3f2fd; color: #1565c0; }
.comparison { font-size: 8.5pt; margin-top: 2px; } /* ════════════════════════════
.comp-up { color: #2e7d32; } .comp-down { color: #c62828; } .comp-same { color: #999; } CATATAN BOX
════════════════════════════ */
.catatan-section {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
margin-bottom: 22px;
break-inside: avoid;
page-break-inside: avoid;
}
.catatan-box {
background: #f7faf8;
border: 1px solid #dde8e3;
border-radius: 7px;
padding: 12px 14px;
break-inside: avoid;
page-break-inside: avoid;
}
.catatan-box h4 { font-size: 9pt; color: #555; margin-bottom: 8px; font-weight: 600; }
.catatan-line { border-bottom: 1px dotted #ccc; height: 22px; }
.kategori-section { margin-bottom: 20px; } /* ════════════════════════════
.kategori-header { display: flex; justify-content: space-between; align-items: center; padding: 8px 12px; border-radius: 6px; margin-bottom: 8px; } TANDA TANGAN
.kat-alquran { background: linear-gradient(90deg, #e8f5e9, #f1f8e9); } ════════════════════════════ */
.kat-hadist { background: linear-gradient(90deg, #e3f2fd, #e8f4fd); } .ttd-section {
.kat-tambahan { background: linear-gradient(90deg, #fffde7, #fff8e1); } display: flex;
justify-content: flex-end; /* dorong ke kanan */
margin-top: 24px;
break-inside: avoid;
page-break-inside: avoid;
}
.ttd-inner {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 32px;
min-width: 360px;
}
.ttd-col { text-align: center; }
.ttd-col .ttd-header {
display: flex;
justify-content: center;
align-items: baseline;
gap: 8px;
margin-bottom: 0;
}
.ttd-col .ttd-kota { font-size: 9pt; color: #555; }
.ttd-col .ttd-menget { font-size: 9pt; color: #555; }
.ttd-col .ttd-space { height: 56px; }
.ttd-col .ttd-line {
border-top: 1px solid #333;
display: block;
padding-top: 4px;
font-size: 9pt;
color: #555;
letter-spacing: .5px;
}
.catatan-box { background: #f5f8f6; border: 1px solid #e0e0e0; border-radius: 8px; padding: 16px; margin-bottom: 24px; } /* ════════════════════════════
.catatan-box h4 { font-size: 10pt; color: #555; margin-bottom: 8px; } FOOTER
.catatan-lines { min-height: 60px; } ════════════════════════════ */
.catatan-line { border-bottom: 1px dotted #ccc; height: 24px; } .rapor-footer {
text-align: center;
.footer { text-align: center; padding-top: 20px; border-top: 2px solid #e0e0e0; margin-top: 30px; font-size: 9pt; color: #999; } padding-top: 16px;
margin-top: 20px;
.print-btn { position: fixed; bottom: 20px; right: 20px; background: #6FBA9D; color: #fff; border: none; padding: 12px 24px; border-radius: 8px; font-size: 11pt; font-weight: 600; cursor: pointer; box-shadow: 0 4px 12px rgba(111,186,157,0.4); z-index: 999; } border-top: 1px solid #e0e0e0;
.print-btn:hover { background: #5EA98C; } font-size: 8.5pt;
color: #aaa;
break-inside: avoid;
page-break-inside: avoid;
}
/* ════════════════════════════
PRINT RULES
════════════════════════════ */
@media print { @media print {
body { padding: 10mm; } body { background: #fff; }
.print-btn { display: none !important; }
/*
* margin: 0 di @page menghilangkan area header/footer bawaan browser
* (tempat browser mencetak URL, judul, tanggal).
* Padding halaman ditangani oleh .page-wrap.
*/
@page {
size: A4 portrait;
margin: 0;
}
.page-wrap { padding: 10mm 12mm; max-width: 100%; }
.print-btn,
.no-print { display: none !important; } .no-print { display: none !important; }
@page { margin: 10mm; size: A4; }
/* Pastikan bagian-bagian penting tidak terpotong */
.rapor-header,
.info-grid,
.summary-row,
.section-title,
.catatan-section,
.catatan-box,
.ttd-section,
.rapor-footer { break-inside: avoid; page-break-inside: avoid; }
/* Tabel boleh melintasi halaman TAPI baris tidak boleh terpotong */
table { break-inside: auto; page-break-inside: auto; }
thead { display: table-header-group; }
tbody tr {
break-inside: avoid !important;
page-break-inside: avoid !important;
}
/* Judul section tidak boleh tertinggal sendirian di bawah halaman */
.section-title {
break-after: avoid !important;
page-break-after: avoid !important;
}
} }
</style> </style>
</head> </head>
<body> <body>
<button class="print-btn no-print" onclick="window.print()"> <button class="print-btn no-print" onclick="window.print()">
<i>🖨️</i> Cetak / Simpan PDF 🖨️ Cetak / Simpan PDF
</button> </button>
{{-- HEADER --}} <div class="page-wrap">
{{-- ── HEADER ── --}}
<div class="rapor-header"> <div class="rapor-header">
<h1>RAPOR CAPAIAN AL-QUR'AN & HADIST</h1> <h1>CAPAIAN MATERI</h1>
<h2>Pondok Pesantren PKPPS</h2> <h2>Pondok Pesantren Riyadlul Jannah</h2>
<div class="subtitle">{{ $semester->nama_semester }} Tahun Ajaran {{ $semester->tahun_ajaran }}</div> <div class="subtitle">{{ $semester->nama_semester }} Tahun Ajaran {{ $semester->tahun_ajaran }}</div>
</div> </div>
{{-- INFO SANTRI --}} {{-- ── INFO SANTRI ── --}}
<div class="info-grid"> <div class="info-grid">
<div class="info-item"><span class="label">Nama Lengkap</span><span class="value">{{ $santri->nama_lengkap }}</span></div> <div class="info-item"><span class="label">Nama Lengkap</span><span class="value">{{ $santri->nama_lengkap }}</span></div>
<div class="info-item"><span class="label">NIS</span><span class="value">{{ $santri->nis }}</span></div> <div class="info-item"><span class="label">NIS</span><span class="value">{{ $santri->nis }}</span></div>
<div class="info-item"><span class="label">Kelas</span><span class="value">{{ $santri->kelas }}</span></div> <div class="info-item"><span class="label">Kelas</span><span class="value">{{ $santri->kelas }}</span></div>
<div class="info-item"><span class="label">Status</span><span class="value">{{ $santri->status }}</span></div> <div class="info-item"><span class="label">Status</span><span class="value">{{ $santri->status }}</span></div>
<div class="info-item"><span class="label">Semester</span><span class="value">{{ $semester->nama_semester }}</span></div> <div class="info-item"><span class="label">Semester</span><span class="value">{{ $semester->nama_semester }}</span></div>
<div class="info-item"><span class="label">Tanggal Cetak</span> <span class="value">{{ now()->format('d F Y') }}</span></div> <div class="info-item"><span class="label">Tanggal Cetak</span><span class="value">{{ now()->translatedFormat('d F Y') }}</span></div>
</div> </div>
{{-- SUMMARY --}} {{-- ── SUMMARY ── --}}
<div class="summary-row"> <div class="summary-row">
<div class="summary-box sb-green"> <div class="summary-box sb-green">
<div class="sb-val">{{ number_format($avgProgress, 1) }}%</div> <div class="sb-val">{{ number_format($avgProgress, 1) }}%</div>
<div class="sb-label">Rata-rata Progress</div> <div class="sb-label">Rata-rata Progress</div>
@if($prevSemester) @if($prevSemester)
<div class="comparison {{ $avgProgress >= $avgPrev ? 'comp-up' : 'comp-down' }}"> @php $delta = $avgProgress - $avgPrev; @endphp
{{ $avgProgress >= $avgPrev ? '▲' : '▼' }} {{ number_format(abs($avgProgress - $avgPrev), 1) }}% dari {{ $prevSemester->nama_semester }} <div class="sb-comp {{ $delta >= 0 ? 'comp-up' : 'comp-down' }}">
{{ $delta >= 0 ? '▲' : '▼' }} {{ number_format(abs($delta), 1) }}%
<span style="font-size:7.5pt;color:#999;display:block;">dari {{ $prevSemester->nama_semester }}</span>
</div> </div>
@endif @endif
</div> </div>
@ -124,21 +372,23 @@
</div> </div>
</div> </div>
{{-- PROGRESS PER KATEGORI --}} {{-- ── RINGKASAN PER KATEGORI ── --}}
<h3>Ringkasan Per Kategori</h3> <div class="section-title">Ringkasan Per Kategori</div>
<div class="tbl-wrap">
<table> <table>
<thead> <thead>
<tr> <tr>
<th>Kategori</th> <th style="width:28%;">Kategori</th>
<th style="text-align:center;">Jumlah Materi</th> <th style="width:12%;text-align:center;">Jml Materi</th>
<th style="text-align:center;">Selesai</th> <th style="width:10%;text-align:center;">Selesai</th>
<th style="text-align:center;">Rata-rata Progress</th> <th style="width:18%;text-align:center;">Rata-rata Progress</th>
<th style="text-align:center;">Semester Lalu</th> <th style="width:15%;text-align:center;">Semester Lalu</th>
<th style="text-align:center;">Perubahan</th> <th style="width:17%;text-align:center;">Perubahan</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach($perKategori as $kat => $data) @foreach($perKategori as $kat => $data)
@php $change = $data['avg'] - $data['prev']; @endphp
<tr> <tr>
<td><strong>{{ $kat }}</strong></td> <td><strong>{{ $kat }}</strong></td>
<td style="text-align:center;">{{ $data['count'] }}</td> <td style="text-align:center;">{{ $data['count'] }}</td>
@ -150,7 +400,6 @@
</td> </td>
<td style="text-align:center;">{{ number_format($data['prev'], 1) }}%</td> <td style="text-align:center;">{{ number_format($data['prev'], 1) }}%</td>
<td style="text-align:center;"> <td style="text-align:center;">
@php $change = $data['avg'] - $data['prev']; @endphp
<span class="{{ $change > 0 ? 'comp-up' : ($change < 0 ? 'comp-down' : 'comp-same') }}"> <span class="{{ $change > 0 ? 'comp-up' : ($change < 0 ? 'comp-down' : 'comp-same') }}">
{{ $change > 0 ? '+' : '' }}{{ number_format($change, 1) }}% {{ $change > 0 ? '+' : '' }}{{ number_format($change, 1) }}%
</span> </span>
@ -159,20 +408,22 @@
@endforeach @endforeach
</tbody> </tbody>
</table> </table>
</div>
{{-- DETAIL PER MATERI --}} {{-- ── DETAIL PER MATERI ── --}}
<h3>Detail Progress Per Materi</h3> <div class="section-title">Detail Progress Per Materi</div>
<div class="tbl-wrap">
<table> <table>
<thead> <thead>
<tr> <tr>
<th style="width:5%;">No</th> <th style="width:4%;text-align:center;">No</th>
<th style="width:25%;">Nama Materi</th> <th style="width:24%;">Nama Materi</th>
<th style="width:12%;">Kategori</th> <th style="width:13%;">Kategori</th>
<th style="width:10%;">Halaman</th> <th style="width:9%;text-align:center;">Halaman</th>
<th class="progress-cell" style="width:15%;">Progress</th> <th style="width:14%;">Progress</th>
<th style="width:10%;">Persentase</th> <th style="width:9%;text-align:center;">%</th>
<th style="width:10%;">Sem. Lalu</th> <th style="width:12%;text-align:center;">Sem. Lalu</th>
<th style="width:13%;">Catatan</th> <th style="width:15%;">Catatan</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -181,85 +432,74 @@
$prevCap = $prevCapaians->where('id_materi', $cap->id_materi)->first(); $prevCap = $prevCapaians->where('id_materi', $cap->id_materi)->first();
$prevPct = $prevCap ? floatval($prevCap->persentase) : 0; $prevPct = $prevCap ? floatval($prevCap->persentase) : 0;
$changePct = floatval($cap->persentase) - $prevPct; $changePct = floatval($cap->persentase) - $prevPct;
$pct = min(floatval($cap->persentase), 100);
$barColor = $pct >= 80 ? '#66bb6a' : ($pct >= 50 ? '#ffa726' : '#ef5350');
$pctColor = $pct >= 100 ? '#2e7d32' : ($pct >= 50 ? '#f57f17' : '#c62828');
@endphp @endphp
<tr> <tr>
<td style="text-align:center;">{{ $idx + 1 }}</td> <td style="text-align:center;">{{ $idx + 1 }}</td>
<td><strong>{{ $cap->materi->nama_kitab }}</strong></td> <td><strong>{{ $cap->materi->nama_kitab }}</strong></td>
<td> <td>
<span class="badge-sm {{ $cap->materi->kategori == 'Al-Qur\'an' ? 'badge-success' : ($cap->materi->kategori == 'Hadist' ? 'badge-info' : 'badge-warning') }}"> <span class="badge-sm {{ $cap->materi->kategori === "Al-Qur'an" ? 'badge-success' : ($cap->materi->kategori === 'Hadist' ? 'badge-info' : 'badge-warning') }}">
{{ $cap->materi->kategori }} {{ $cap->materi->kategori }}
</span> </span>
</td> </td>
<td style="font-size:8.5pt;">{{ $cap->halaman_selesai ?: '-' }}</td> <td style="text-align:center;font-size:8.5pt;">{{ $cap->halaman_selesai ?: '' }}</td>
<td> <td>
<div class="prog-bar-mini"> <div class="prog-bar-mini">
<div class="prog-fill-mini" style="width:{{ min($cap->persentase, 100) }}%;background:{{ $cap->persentase >= 80 ? '#66bb6a' : ($cap->persentase >= 50 ? '#ffa726' : '#ef5350') }};"></div> <div class="prog-fill-mini" style="width:{{ $pct }}%;background:{{ $barColor }};"></div>
</div> </div>
</td> </td>
<td style="text-align:center;"> <td style="text-align:center;">
<strong style="color:{{ $cap->persentase >= 100 ? '#2e7d32' : ($cap->persentase >= 50 ? '#f57f17' : '#c62828') }};"> <strong style="color:{{ $pctColor }};">{{ number_format($cap->persentase, 1) }}%</strong>
{{ number_format($cap->persentase, 1) }}%
</strong>
</td> </td>
<td style="text-align:center;"> <td style="text-align:center;">
{{ number_format($prevPct, 1) }}% {{ number_format($prevPct, 1) }}%
<div class="{{ $changePct > 0 ? 'comp-up' : ($changePct < 0 ? 'comp-down' : 'comp-same') }}" style="font-size:8pt;"> <div class="{{ $changePct > 0 ? 'comp-up' : ($changePct < 0 ? 'comp-down' : 'comp-same') }}" style="font-size:7.5pt;">
{{ $changePct > 0 ? '+' : '' }}{{ number_format($changePct, 1) }}% {{ $changePct > 0 ? '+' : '' }}{{ number_format($changePct, 1) }}%
</div> </div>
</td> </td>
<td style="font-size:8pt;">{{ $cap->catatan ?: '-' }}</td> <td style="font-size:8pt;color:#555;">{{ $cap->catatan ?: '' }}</td>
</tr> </tr>
@empty @empty
<tr> <tr>
<td colspan="8" style="text-align:center;color:#999;padding:20px;">Belum ada data capaian untuk semester ini</td> <td colspan="8" style="text-align:center;color:#999;padding:18px;">
Belum ada data capaian untuk semester ini.
</td>
</tr> </tr>
@endforelse @endforelse
</tbody> </tbody>
</table> </table>
</div>
{{-- CATATAN & REKOMENDASI --}} {{-- ── CATATAN & TARGET ── --}}
<div class="catatan-section">
<div class="catatan-box"> <div class="catatan-box">
<h4>Catatan / Rekomendasi Ustadz:</h4> <h4>Catatan / Rekomendasi Ustadz:</h4>
<div class="catatan-lines">
<div class="catatan-line"></div> <div class="catatan-line"></div>
<div class="catatan-line"></div> <div class="catatan-line"></div>
<div class="catatan-line"></div> <div class="catatan-line"></div>
</div> </div>
</div>
{{-- TARGET SEMESTER DEPAN --}}
<div class="catatan-box"> <div class="catatan-box">
<h4>Target Semester Depan:</h4> <h4>Target Semester Depan:</h4>
<div class="catatan-lines"> <div class="catatan-line"></div>
<div class="catatan-line"></div> <div class="catatan-line"></div>
<div class="catatan-line"></div> <div class="catatan-line"></div>
</div> </div>
</div> </div>
{{-- TANDA TANGAN --}} {{-- ── TANDA TANGAN ── --}}
<div style="display:grid;grid-template-columns:1fr 1fr;gap:40px;margin-top:30px;"> <div class="ttd-section">
<div style="text-align:center;"> <div style="display:flex; justify-content:flex-end;">
<div style="font-size:9pt;color:#555;">Mengetahui,</div> <div class="ttd-col">
<div style="font-size:10pt;font-weight:600;margin-top:4px;">Pimpinan Pondok</div> <div style="font-size:9pt;color:#555;">Mengetahui, ...............................</div>
<div style="height:60px;"></div> <div class="ttd-space"></div>
<div style="border-top:1px solid #333;display:inline-block;padding-top:4px;min-width:180px;font-size:9.5pt;"> <div class=>( ................................................ )</div>
(.................................)
</div>
</div>
<div style="text-align:center;">
<div style="font-size:9pt;color:#555;">{{ now()->format('d F Y') }}</div>
<div style="font-size:10pt;font-weight:600;margin-top:4px;">Ustadz Pengampu</div>
<div style="height:60px;"></div>
<div style="border-top:1px solid #333;display:inline-block;padding-top:4px;min-width:180px;font-size:9.5pt;">
(.................................)
</div> </div>
</div> </div>
</div> </div>
{{-- FOOTER --}} </div>{{-- /page-wrap --}}
<div class="footer">
Rapor ini dicetak secara otomatis oleh Sistem Informasi Manajemen PKPPS pada {{ now()->format('d F Y H:i') }}
</div>
</body> </body>
</html> </html>

View File

@ -30,7 +30,7 @@
</div> </div>
{{-- 2 panel grid --}} {{-- 2 panel grid --}}
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-bottom:16px;"> <div class="dash-fin-grid">
{{-- ── Panel Kiri: Status SPP ── --}} {{-- ── Panel Kiri: Status SPP ── --}}
<div class="content-box" style="display:flex;flex-direction:column;gap:0;"> <div class="content-box" style="display:flex;flex-direction:column;gap:0;">
@ -93,15 +93,15 @@
{{-- Quick links --}} {{-- Quick links --}}
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-top:auto;"> <div style="display:flex;gap:6px;flex-wrap:wrap;margin-top:auto;">
<a href="{{ route('admin.pembayaran-spp.index', ['tab'=>'belum-bayar','bulan'=>date('n'),'tahun'=>date('Y')]) }}" <a href="{{ route('admin.pembayaran-spp.index', ['tab'=>'belum-bayar','bulan'=>date('n'),'tahun'=>date('Y')]) }}"
class="btn btn-danger btn-sm" style="flex:1;justify-content:center;"> class="btn btn-danger btn-sm" style="flex:1 1 0;min-width:0;justify-content:center;">
<i class="fas fa-exclamation-circle"></i> Belum ({{ $spp['belum'] ?? 0 }}) <i class="fas fa-exclamation-circle"></i> Belum ({{ $spp['belum'] ?? 0 }})
</a> </a>
<a href="{{ route('admin.pembayaran-spp.generate') }}" <a href="{{ route('admin.pembayaran-spp.generate') }}"
class="btn btn-warning btn-sm" style="flex:1;justify-content:center;"> class="btn btn-warning btn-sm" style="flex:1 1 0;min-width:0;justify-content:center;">
<i class="fas fa-cogs"></i> Generate <i class="fas fa-cogs"></i> Generate
</a> </a>
<a href="{{ route('admin.pembayaran-spp.index', ['tab'=>'sudah-bayar','bulan'=>date('n'),'tahun'=>date('Y')]) }}" <a href="{{ route('admin.pembayaran-spp.index', ['tab'=>'sudah-bayar','bulan'=>date('n'),'tahun'=>date('Y')]) }}"
class="btn btn-success btn-sm" style="flex:1;justify-content:center;"> class="btn btn-success btn-sm" style="flex:1 1 0;min-width:0;justify-content:center;">
<i class="fas fa-check-circle"></i> Lunas ({{ $spp['lunas'] ?? 0 }}) <i class="fas fa-check-circle"></i> Lunas ({{ $spp['lunas'] ?? 0 }})
</a> </a>
</div> </div>
@ -178,13 +178,13 @@ class="btn btn-success btn-sm" style="flex:1;justify-content:center;">
<div style="padding:11px 14px;border-radius:var(--border-radius-sm);margin-bottom:14px; <div style="padding:11px 14px;border-radius:var(--border-radius-sm);margin-bottom:14px;
background:{{ $sisaKas >= 0 ? 'linear-gradient(135deg,#E8F7F2,#D4F1E3)' : 'linear-gradient(135deg,#FFE8EA,#FFD5D8)' }}; background:{{ $sisaKas >= 0 ? 'linear-gradient(135deg,#E8F7F2,#D4F1E3)' : 'linear-gradient(135deg,#FFE8EA,#FFD5D8)' }};
border-left:4px solid {{ $sisaKas >= 0 ? 'var(--success-color)' : 'var(--danger-color)' }}; border-left:4px solid {{ $sisaKas >= 0 ? 'var(--success-color)' : 'var(--danger-color)' }};
display:flex;justify-content:space-between;align-items:center;"> display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:6px;">
<span style="font-size:.75rem;font-weight:700;color:var(--text-color);display:flex;align-items:center;gap:6px;"> <span style="font-size:.75rem;font-weight:700;color:var(--text-color);display:flex;align-items:center;gap:6px;">
<i class="fas fa-{{ $sisaKas >= 0 ? 'piggy-bank' : 'exclamation-triangle' }}" <i class="fas fa-{{ $sisaKas >= 0 ? 'piggy-bank' : 'exclamation-triangle' }}"
style="color:{{ $sisaKas >= 0 ? 'var(--success-color)' : 'var(--danger-color)' }};"></i> style="color:{{ $sisaKas >= 0 ? 'var(--success-color)' : 'var(--danger-color)' }};"></i>
Sisa Kas Bulan Ini Sisa Kas Bulan Ini
</span> </span>
<strong style="font-size:1rem;font-weight:800;color:{{ $sisaKas >= 0 ? 'var(--success-color)' : 'var(--danger-color)' }};"> <strong style="font-size:1rem;font-weight:800;color:{{ $sisaKas >= 0 ? 'var(--success-color)' : 'var(--danger-color)' }};word-break:break-all;">
{{ $sisaKas >= 0 ? '+' : '' }}Rp {{ number_format($sisaKas,0,',','.') }} {{ $sisaKas >= 0 ? '+' : '' }}Rp {{ number_format($sisaKas,0,',','.') }}
</strong> </strong>
</div> </div>
@ -192,11 +192,11 @@ class="btn btn-success btn-sm" style="flex:1;justify-content:center;">
{{-- Quick links --}} {{-- Quick links --}}
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-top:auto;"> <div style="display:flex;gap:6px;flex-wrap:wrap;margin-top:auto;">
<a href="{{ route('admin.keuangan.index') }}" <a href="{{ route('admin.keuangan.index') }}"
class="btn btn-info btn-sm" style="flex:1;justify-content:center;"> class="btn btn-info btn-sm" style="flex:1 1 0;min-width:0;justify-content:center;">
<i class="fas fa-book-open"></i> Buku Kas <i class="fas fa-book-open"></i> Buku Kas
</a> </a>
<a href="{{ route('admin.keuangan.laporan', ['bulan'=>date('n'),'tahun'=>date('Y')]) }}" <a href="{{ route('admin.keuangan.laporan', ['bulan'=>date('n'),'tahun'=>date('Y')]) }}"
class="btn btn-warning btn-sm" style="flex:1;justify-content:center;"> class="btn btn-warning btn-sm" style="flex:1 1 0;min-width:0;justify-content:center;">
<i class="fas fa-chart-bar"></i> Laporan <i class="fas fa-chart-bar"></i> Laporan
</a> </a>
</div> </div>

View File

@ -42,16 +42,11 @@
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
gap: 14px; gap: 14px;
margin-bottom: 16px; margin-bottom: 16px;
min-width: 0;
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.dash-fin-grid { grid-template-columns: 1fr; } .dash-fin-grid { grid-template-columns: 1fr; }
} }
@media (max-width: 1024px) {
.row-cards-5 { grid-template-columns: repeat(3,1fr); }
}
@media (max-width: 640px) {
.row-cards-5 { grid-template-columns: repeat(2,1fr); }
}
</style> </style>
{{-- ───────── 1. KPI CARDS ───────── --}} {{-- ───────── 1. KPI CARDS ───────── --}}

View File

@ -99,7 +99,7 @@ class="btn btn-sm btn-success"
</div> </div>
{{-- ============================================================ --}} {{-- ============================================================ --}}
{{-- 2. DAY TABS (Senin - Ahad) --}} {{-- 2. DAY TABS --}}
{{-- ============================================================ --}} {{-- ============================================================ --}}
<div class="content-box"> <div class="content-box">
<div class="day-tabs"> <div class="day-tabs">
@ -122,9 +122,7 @@ class="day-tab {{ $isActive ? 'active' : '' }} {{ $isToday ? 'today-tab' : '' }}
@endforeach @endforeach
</div> </div>
{{-- ======================================================== --}} {{-- FILTER BAR --}}
{{-- 3. FILTER BAR (Tanggal + Kategori + Kelas + Aksi) --}}
{{-- ======================================================== --}}
<form method="GET" action="{{ route('admin.kegiatan.index') }}" id="filterForm" class="filter-form-inline" style="margin-top: 10px;"> <form method="GET" action="{{ route('admin.kegiatan.index') }}" id="filterForm" class="filter-form-inline" style="margin-top: 10px;">
<input type="hidden" name="kelas" id="kelasInput" value="{{ $selectedKelasId }}"> <input type="hidden" name="kelas" id="kelasInput" value="{{ $selectedKelasId }}">
@ -179,20 +177,11 @@ class="day-tab {{ $isActive ? 'active' : '' }} {{ $isToday ? 'today-tab' : '' }}
<button type="button" class="btn btn-sm btn-secondary" onclick="nextDay()"> <button type="button" class="btn btn-sm btn-secondary" onclick="nextDay()">
<i class="fas fa-chevron-right"></i> <i class="fas fa-chevron-right"></i>
</button> </button>
{{-- <div style="margin-left: auto; display: flex; gap: 8px;">
<a href="{{ route('admin.kategori-kegiatan.index') }}" class="btn btn-info btn-sm">
<i class="fas fa-tags"></i> Kategori
</a>
<a href="{{ route('admin.kegiatan.jadwal') }}" class="btn btn-info btn-sm">
<i class="fas fa-list"></i> Semua Jadwal
</a>
</div> --}}
</form> </form>
</div> </div>
{{-- ============================================================ --}} {{-- ============================================================ --}}
{{-- 4. INSIGHTS PANEL --}} {{-- 3. INSIGHTS PANEL --}}
{{-- ============================================================ --}} {{-- ============================================================ --}}
@if(count($insights) > 0) @if(count($insights) > 0)
<div class="content-box" style="margin-top: 14px;"> <div class="content-box" style="margin-top: 14px;">
@ -218,7 +207,7 @@ class="day-tab {{ $isActive ? 'active' : '' }} {{ $isToday ? 'today-tab' : '' }}
@endif @endif
{{-- ============================================================ --}} {{-- ============================================================ --}}
{{-- 5. MAIN LAYOUT: Kegiatan Cards (2/3) + Heatmap (1/3) --}} {{-- 4. MAIN LAYOUT: Kegiatan Cards + Heatmap --}}
{{-- ============================================================ --}} {{-- ============================================================ --}}
<div class="layout-kegiatan" style="margin-top: 14px;"> <div class="layout-kegiatan" style="margin-top: 14px;">
@ -227,6 +216,21 @@ class="day-tab {{ $isActive ? 'active' : '' }} {{ $isToday ? 'today-tab' : '' }}
@if($kegiatanHariIni->count() > 0) @if($kegiatanHariIni->count() > 0)
<div class="kegiatan-list"> <div class="kegiatan-list">
@foreach($kegiatanHariIni as $kegiatan) @foreach($kegiatanHariIni as $kegiatan)
@php
$persen = $kegiatan->persen_kehadiran;
$totalSantri = $kegiatan->total_santri_kegiatan;
$totalHadir = $kegiatan->total_hadir; // hadir + terlambat
$totalInput = $kegiatan->total_absensi; // sudah diinput (semua status)
$belumAbsen = $kegiatan->belum_absen; // belum diinput sama sekali
$terlambat = $kegiatan->total_terlambat;
$isUmum = $kegiatan->kelasKegiatan->isEmpty();
// Warna progress bar
$pClass = $persen >= 85 ? 'p-success' : ($persen >= 70 ? 'p-warning' : ($persen >= 50 ? 'p-orange' : 'p-danger'));
// Hitung per kelas: sudah input berapa
$infoPerKelas = $kegiatan->info_per_kelas ?? collect();
@endphp
<div class="kegiatan-card"> <div class="kegiatan-card">
<div class="kegiatan-card-header"> <div class="kegiatan-card-header">
<div class="kegiatan-info"> <div class="kegiatan-info">
@ -252,7 +256,7 @@ class="day-tab {{ $isActive ? 'active' : '' }} {{ $isToday ? 'today-tab' : '' }}
@endif @endif
<span> <span>
<i class="fas fa-layer-group"></i> <i class="fas fa-layer-group"></i>
@if($kegiatan->kelasKegiatan->isEmpty()) @if($isUmum)
<span class="badge badge-secondary">Kegiatan Umum</span> <span class="badge badge-secondary">Kegiatan Umum</span>
@else @else
{{ $kegiatan->kelasKegiatan->pluck('nama_kelas')->implode(', ') }} {{ $kegiatan->kelasKegiatan->pluck('nama_kelas')->implode(', ') }}
@ -271,29 +275,147 @@ class="day-tab {{ $isActive ? 'active' : '' }} {{ $isToday ? 'today-tab' : '' }}
</span> </span>
</div> </div>
{{-- Progress Bar --}} {{-- ============================================ --}}
@php {{-- PROGRESS KEHADIRAN DIPERBAIKI --}}
$persen = $kegiatan->persen_kehadiran; {{-- ============================================ --}}
$pClass = $persen >= 85 ? 'p-success' : ($persen >= 70 ? 'p-warning' : ($persen >= 50 ? 'p-orange' : 'p-danger'));
$denominator = $kegiatan->total_absensi > 0 ? $kegiatan->total_absensi : $totalSantriAktif;
@endphp
<div class="kegiatan-progress"> <div class="kegiatan-progress">
<div class="kegiatan-progress-header">
{{-- Baris judul + angka utama --}}
<div class="kegiatan-progress-header" style="margin-bottom: 4px;">
<span style="font-weight: 500;"> <span style="font-weight: 500;">
<i class="fas fa-users"></i> Kehadiran <i class="fas fa-users"></i> Kehadiran
{{-- Keterangan terlambat = hadir --}}
@if($terlambat > 0)
<span style="font-size: 0.78rem; color: #FF9800; font-weight: 400; margin-left: 4px;">
(termasuk {{ $terlambat }} terlambat)
</span> </span>
<span style="font-weight: 700;"> @endif
{{ $kegiatan->total_hadir }}/{{ $denominator }} </span>
({{ $persen }}%) <span style="font-weight: 700; font-size: 1rem; color: {{ $persen >= 85 ? '#059669' : ($persen >= 70 ? '#d97706' : '#dc2626') }};">
{{ $totalHadir }}/{{ $totalSantri }} santri
&nbsp;<span style="font-size: 0.85rem;">({{ $persen }}%)</span>
</span> </span>
</div> </div>
<div class="kegiatan-progress-bar">
<div class="kegiatan-progress-fill {{ $pClass }}" {{-- Sub-info: sudah diinput vs belum --}}
data-width="{{ $persen }}"> <div style="display: flex; gap: 12px; margin-bottom: 6px; font-size: 0.78rem; flex-wrap: wrap;">
{{ $persen }}% <span style="color: #059669;">
</div> <i class="fas fa-check"></i>
Sudah diinput: <strong>{{ $totalInput }}</strong> santri
</span>
@if($belumAbsen > 0)
<span style="color: #dc2626;">
<i class="fas fa-hourglass-half"></i>
Belum absen: <strong>{{ $belumAbsen }}</strong> santri
</span>
@else
<span style="color: #059669;">
<i class="fas fa-check-double"></i>
Semua sudah diinput
</span>
@endif
</div>
{{-- Progress bar multi-warna --}}
@php
$hadirMurni = $kegiatan->total_hadir_murni ?? ($totalHadir - $terlambat);
$alpa = $kegiatan->total_alpa ?? 0;
$izin = $kegiatan->total_izin ?? 0;
$sakit = $kegiatan->total_sakit ?? 0;
$pctHadir = $totalSantri > 0 ? round($hadirMurni / $totalSantri * 100) : 0;
$pctTlmbat = $totalSantri > 0 ? round($terlambat / $totalSantri * 100) : 0;
$pctIzin = $totalSantri > 0 ? round($izin / $totalSantri * 100) : 0;
$pctSakit = $totalSantri > 0 ? round($sakit / $totalSantri * 100) : 0;
$pctAlpa = $totalSantri > 0 ? round($alpa / $totalSantri * 100) : 0;
$pctBelum = $totalSantri > 0 ? round($belumAbsen / $totalSantri * 100) : 0;
@endphp
<div style="height: 22px; background: #f3f4f6; border-radius: 11px; overflow: hidden; display: flex; margin-bottom: 6px;">
@if($pctHadir > 0)
<div style="width:{{ $pctHadir }}%; background:#22c55e; display:flex; align-items:center; justify-content:center; color:white; font-size:0.7rem; font-weight:700;"
title="Hadir: {{ $hadirMurni }}">{{ $hadirMurni > 0 && $pctHadir > 5 ? $hadirMurni : '' }}</div>
@endif
@if($pctTlmbat > 0)
<div style="width:{{ $pctTlmbat }}%; background:#FF9800; display:flex; align-items:center; justify-content:center; color:white; font-size:0.7rem; font-weight:700;"
title="Terlambat : {{ $terlambat }}">{{ $terlambat > 0 && $pctTlmbat > 5 ? $terlambat : '' }}</div>
@endif
@if($pctIzin > 0)
<div style="width:{{ $pctIzin }}%; background:#f59e0b; display:flex; align-items:center; justify-content:center; color:white; font-size:0.7rem; font-weight:700;"
title="Izin: {{ $izin }}">{{ $izin > 0 && $pctIzin > 5 ? $izin : '' }}</div>
@endif
@if($pctSakit > 0)
<div style="width:{{ $pctSakit }}%; background:#3b82f6; display:flex; align-items:center; justify-content:center; color:white; font-size:0.7rem; font-weight:700;"
title="Sakit: {{ $sakit }}">{{ $sakit > 0 && $pctSakit > 5 ? $sakit : '' }}</div>
@endif
@if($pctAlpa > 0)
<div style="width:{{ $pctAlpa }}%; background:#ef4444; display:flex; align-items:center; justify-content:center; color:white; font-size:0.7rem; font-weight:700;"
title="Alpa: {{ $alpa }}">{{ $alpa > 0 && $pctAlpa > 5 ? $alpa : '' }}</div>
@endif
@if($pctBelum > 0)
<div style="width:{{ $pctBelum }}%; background:#d1d5db; display:flex; align-items:center; justify-content:center; color:#6b7280; font-size:0.7rem; font-weight:700;"
title="Belum absen: {{ $belumAbsen }}">{{ $belumAbsen > 0 && $pctBelum > 5 ? $belumAbsen : '' }}</div>
@endif
</div>
{{-- Legend bar --}}
<div style="display:flex; gap:10px; flex-wrap:wrap; font-size:0.72rem; color:#6b7280; margin-bottom: 6px;">
@if($hadirMurni > 0)
<span><span style="display:inline-block;width:8px;height:8px;border-radius:2px;background:#22c55e;margin-right:2px;"></span>Hadir</span>
@endif
@if($terlambat > 0)
<span><span style="display:inline-block;width:8px;height:8px;border-radius:2px;background:#FF9800;margin-right:2px;"></span>Terlambat</span>
@endif
@if($izin > 0)
<span><span style="display:inline-block;width:8px;height:8px;border-radius:2px;background:#f59e0b;margin-right:2px;"></span>Izin</span>
@endif
@if($sakit > 0)
<span><span style="display:inline-block;width:8px;height:8px;border-radius:2px;background:#3b82f6;margin-right:2px;"></span>Sakit</span>
@endif
@if($alpa > 0)
<span><span style="display:inline-block;width:8px;height:8px;border-radius:2px;background:#ef4444;margin-right:2px;"></span>Alpa</span>
@endif
@if($belumAbsen > 0)
<span><span style="display:inline-block;width:8px;height:8px;border-radius:2px;background:#d1d5db;margin-right:2px;"></span>Belum absen</span>
@endif
</div>
{{-- Info per kelas (khusus kegiatan dengan beberapa kelas) --}}
@if(!$isUmum && $infoPerKelas->count() > 1)
<div style="margin-top: 8px; padding: 8px 10px; background: #f8fafc; border-radius: 8px; border: 1px solid #e2e8f0;">
<div style="font-size: 0.75rem; font-weight: 600; color: #475569; margin-bottom: 5px;">
<i class="fas fa-school"></i> Status per Kelas:
</div>
<div style="display: flex; flex-wrap: wrap; gap: 6px;">
@foreach($infoPerKelas as $infoKls)
@php
// Hitung santri kelas ini yg sudah diinput dari data absensis
$sudahKelas = $kegiatan->absensis->filter(function($ab) use ($infoKls) {
return ($ab->santri->kelas_name ?? '') === $infoKls['nama'];
})->count();
$totalKls = $infoKls['total_santri'];
$belumKls = max(0, $totalKls - $sudahKelas);
$sudahSemua = $belumKls === 0 && $totalKls > 0;
@endphp
<div style="display: flex; align-items: center; gap: 4px; padding: 3px 8px;
background: {{ $sudahSemua ? '#dcfce7' : ($sudahKelas > 0 ? '#fef9c3' : '#f1f5f9') }};
border: 1px solid {{ $sudahSemua ? '#86efac' : ($sudahKelas > 0 ? '#fde68a' : '#e2e8f0') }};
border-radius: 6px; font-size: 0.72rem;">
<i class="fas fa-{{ $sudahSemua ? 'check-circle' : ($sudahKelas > 0 ? 'minus-circle' : 'circle') }}"
style="color: {{ $sudahSemua ? '#16a34a' : ($sudahKelas > 0 ? '#ca8a04' : '#94a3b8') }};"></i>
<span style="font-weight: 600;">{{ $infoKls['nama'] }}</span>
<span style="color: #64748b;">
{{ $sudahKelas }}/{{ $totalKls }}
@if(!$sudahSemua && $belumKls > 0)
<span style="color: #dc2626;">({{ $belumKls }} belum)</span>
@endif
</span>
</div>
@endforeach
</div> </div>
</div> </div>
@endif
</div>{{-- end kegiatan-progress --}}
{{-- Actions --}} {{-- Actions --}}
<div class="kegiatan-actions"> <div class="kegiatan-actions">
@ -338,7 +460,6 @@ class="btn btn-sm btn-secondary">
<span>Kalender Kehadiran</span> <span>Kalender Kehadiran</span>
</div> </div>
{{-- Month/Year Selector --}}
<div class="filter-form-inline" style="margin-bottom: 12px;"> <div class="filter-form-inline" style="margin-bottom: 12px;">
<button type="button" class="btn btn-sm btn-secondary" style="padding: 4px 8px;" <button type="button" class="btn btn-sm btn-secondary" style="padding: 4px 8px;"
onclick="changeHeatmapMonth(-1)"> onclick="changeHeatmapMonth(-1)">
@ -418,7 +539,7 @@ class="btn btn-sm btn-secondary">
</div> </div>
{{-- ============================================================ --}} {{-- ============================================================ --}}
{{-- 6. MODAL DETAIL ABSENSI (AJAX) --}} {{-- 5. MODAL DETAIL ABSENSI (AJAX) --}}
{{-- ============================================================ --}} {{-- ============================================================ --}}
<div id="detailModal" class="modal-kegiatan"> <div id="detailModal" class="modal-kegiatan">
<div class="modal-kegiatan-panel"> <div class="modal-kegiatan-panel">
@ -439,14 +560,12 @@ class="btn btn-sm btn-secondary">
{{-- JAVASCRIPT --}} {{-- JAVASCRIPT --}}
{{-- ============================================================ --}} {{-- ============================================================ --}}
<script> <script>
// -- Date Navigation --
function setToday() { function setToday() {
var dateInput = document.querySelector('input[name="tanggal"]');
var now = new Date(); var now = new Date();
var y = now.getFullYear(); var y = now.getFullYear();
var m = ('0' + (now.getMonth() + 1)).slice(-2); var m = ('0' + (now.getMonth() + 1)).slice(-2);
var d = ('0' + now.getDate()).slice(-2); var d = ('0' + now.getDate()).slice(-2);
dateInput.value = y + '-' + m + '-' + d; document.querySelector('input[name="tanggal"]').value = y + '-' + m + '-' + d;
document.getElementById('filterForm').submit(); document.getElementById('filterForm').submit();
} }
@ -469,7 +588,6 @@ function goToDate(date) {
document.getElementById('filterForm').submit(); document.getElementById('filterForm').submit();
} }
// -- Show Detail Modal (AJAX) --
function showDetailModal(kegiatanId, tanggal) { function showDetailModal(kegiatanId, tanggal) {
var modal = document.getElementById('detailModal'); var modal = document.getElementById('detailModal');
var modalBody = document.getElementById('modalBody'); var modalBody = document.getElementById('modalBody');
@ -479,7 +597,7 @@ function showDetailModal(kegiatanId, tanggal) {
var url = baseUrl.replace(':id', kegiatanId) + '?tanggal=' + tanggal; var url = baseUrl.replace(':id', kegiatanId) + '?tanggal=' + tanggal;
fetch(url) fetch(url)
.then(function(response) { return response.text(); }) .then(function(r) { return r.text(); })
.then(function(html) { modalBody.innerHTML = html; }) .then(function(html) { modalBody.innerHTML = html; })
.catch(function() { .catch(function() {
modalBody.innerHTML = modalBody.innerHTML =
@ -496,7 +614,6 @@ function closeModal() {
document.getElementById('detailModal').classList.remove('active'); document.getElementById('detailModal').classList.remove('active');
} }
// -- Close modal on backdrop / Escape --
window.onclick = function(event) { window.onclick = function(event) {
var modal = document.getElementById('detailModal'); var modal = document.getElementById('detailModal');
if (event.target === modal) { closeModal(); } if (event.target === modal) { closeModal(); }
@ -505,73 +622,55 @@ function closeModal() {
if (event.key === 'Escape') { closeModal(); } if (event.key === 'Escape') { closeModal(); }
}); });
// -- Progress bar width animation --
document.querySelectorAll('.kegiatan-progress-fill[data-width]').forEach(function(el) {
el.style.width = el.getAttribute('data-width') + '%';
});
// -- Heatmap: delegated click for cells --
document.getElementById('heatmapGrid').addEventListener('click', function(e) { document.getElementById('heatmapGrid').addEventListener('click', function(e) {
var cell = e.target.closest('.heatmap-cell'); var cell = e.target.closest('.heatmap-cell');
if (cell && cell.dataset.date) { if (cell && cell.dataset.date) { goToDate(cell.dataset.date); }
goToDate(cell.dataset.date);
}
}); });
// -- Heatmap: month navigation --
function changeHeatmapMonth(delta) { function changeHeatmapMonth(delta) {
var monthSelect = document.getElementById('heatmapMonth'); var monthSelect = document.getElementById('heatmapMonth');
var yearSelect = document.getElementById('heatmapYear'); var yearSelect = document.getElementById('heatmapYear');
var month = parseInt(monthSelect.value) + delta; var month = parseInt(monthSelect.value) + delta;
var year = parseInt(yearSelect.value); var year = parseInt(yearSelect.value);
if (month > 12) { month = 1; year++; } if (month > 12) { month = 1; year++; }
else if (month < 1) { month = 12; year--; } else if (month < 1) { month = 12; year--; }
monthSelect.value = month; monthSelect.value = month;
yearSelect.value = year; yearSelect.value = year;
updateHeatmap(); updateHeatmap();
} }
// -- Heatmap: AJAX reload --
function updateHeatmap() { function updateHeatmap() {
var month = document.getElementById('heatmapMonth').value; var month = document.getElementById('heatmapMonth').value;
var year = document.getElementById('heatmapYear').value; var year = document.getElementById('heatmapYear').value;
var kelasId = document.getElementById('kelasInput').value; var kelasId = document.getElementById('kelasInput').value;
var monthNames = [ var monthNames = ['Januari','Februari','Maret','April','Mei','Juni',
'Januari','Februari','Maret','April','Mei','Juni', 'Juli','Agustus','September','Oktober','November','Desember'];
'Juli','Agustus','September','Oktober','November','Desember'
];
document.getElementById('heatmapMonthName').textContent = monthNames[month - 1] + ' ' + year; document.getElementById('heatmapMonthName').textContent = monthNames[month - 1] + ' ' + year;
var url = '{{ route("admin.kegiatan.index") }}' + var url = '{{ route("admin.kegiatan.index") }}' +
'?heatmap=1&month=' + month + '&year=' + year + '&kelas=' + kelasId; '?heatmap=1&month=' + month + '&year=' + year + '&kelas=' + kelasId;
fetch(url) fetch(url)
.then(function(response) { return response.json(); }) .then(function(r) { return r.json(); })
.then(function(data) { .then(function(data) {
var grid = document.getElementById('heatmapGrid'); var grid = document.getElementById('heatmapGrid');
grid.innerHTML = ''; grid.innerHTML = '';
// -- Empty cells for first week alignment --
var firstDay = new Date(year, month - 1, 1).getDay(); var firstDay = new Date(year, month - 1, 1).getDay();
var startDay = firstDay === 0 ? 6 : firstDay - 1; var startDay = firstDay === 0 ? 6 : firstDay - 1;
var i; for (var i = 0; i < startDay; i++) {
for (i = 0; i < startDay; i++) {
var empty = document.createElement('div'); var empty = document.createElement('div');
empty.className = 'heatmap-cell'; empty.className = 'heatmap-cell';
empty.style.visibility = 'hidden'; empty.style.visibility = 'hidden';
grid.appendChild(empty); grid.appendChild(empty);
} }
// -- Render calendar cells --
data.heatmapData.forEach(function(day) { data.heatmapData.forEach(function(day) {
var cell = document.createElement('div'); var cell = document.createElement('div');
var date = new Date(day.date); var date = new Date(day.date);
var today = new Date(); var today = new Date();
var isToday = date.toDateString() === today.toDateString(); var isToday = date.toDateString() === today.toDateString();
cell.className = 'heatmap-cell heatmap-level-' + day.level + (isToday ? ' today' : ''); cell.className = 'heatmap-cell heatmap-level-' + day.level + (isToday ? ' today' : '');
cell.setAttribute('data-date', day.date); cell.setAttribute('data-date', day.date);
cell.setAttribute('data-percentage', day.percentage); cell.setAttribute('data-percentage', day.percentage);
@ -581,9 +680,7 @@ function updateHeatmap() {
grid.appendChild(cell); grid.appendChild(cell);
}); });
}) })
.catch(function(err) { .catch(function(err) { console.error('Error loading heatmap:', err); });
console.error('Error loading heatmap:', err);
});
} }
</script> </script>
@endsection @endsection

View File

@ -1,233 +0,0 @@
@extends('layouts.app')
@section('content')
<style>
.chart-box { background: #fff; border-radius: 12px; padding: 14px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); margin-bottom: 14px; }
.chart-box h4 { margin: 0 0 16px; color: var(--primary-dark); font-size: 1rem; }
.mini-kpi { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin-bottom: 14px; }
.mini-kpi-card { padding: 16px; border-radius: 10px; text-align: center; }
.mini-kpi-card.hadir { background: #ECFDF5; color: #065F46; }
.mini-kpi-card.izin { background: #FFFBEB; color: #92400E; }
.mini-kpi-card.sakit { background: #EFF6FF; color: #1E40AF; }
.mini-kpi-card.alpa { background: #FEF2F2; color: #991B1B; }
.mini-kpi-val { font-size: 1.6rem; font-weight: 700; }
.mini-kpi-label { font-size: 0.78rem; margin-top: 4px; }
.progress-bar-lg { background: #e9ecef; border-radius: 10px; height: 24px; overflow: hidden; margin: 12px 0; }
.progress-bar-lg .fill { height: 100%; border-radius: 10px; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 0.82rem; font-weight: 600; }
.insight-box { padding: 12px 16px; border-radius: 8px; margin-bottom: 8px; display: flex; align-items: flex-start; gap: 10px; font-size: 0.85rem; }
.insight-box.i-success { background: #ECFDF5; color: #065F46; }
.insight-box.i-warning { background: #FFFBEB; color: #92400E; }
.insight-box.i-danger { background: #FEF2F2; color: #991B1B; }
.insight-box.i-info { background: #EFF6FF; color: #1E40AF; }
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
@media(max-width:768px){ .two-col { grid-template-columns: 1fr; } }
.text-center { text-align: center; }
.progress-inline { display: flex; align-items: center; gap: 8px; }
.progress-bar-mini { flex: 1; background: #e9ecef; border-radius: 8px; height: 8px; overflow: hidden; max-width: 120px; }
.progress-bar-mini .fill { height: 100%; border-radius: 8px; }
</style>
<div class="page-header">
<h2><i class="fas fa-search-plus"></i> Analisis Kegiatan</h2>
<a href="{{ route('admin.laporan-kegiatan.index') }}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
{{-- Header Kegiatan --}}
<div class="content-box" style="margin-bottom: 14px;">
<div style="display:flex; justify-content:space-between; align-items:flex-start; flex-wrap:wrap; gap:12px;">
<div>
<h3 style="margin:0 0 6px; color:var(--primary-dark);">{{ $kegiatan->nama_kegiatan }}</h3>
<p style="margin:0; font-size:0.85rem; color:var(--text-light);">
<span class="badge badge-info">{{ $kegiatan->kategori->nama_kategori ?? '-' }}</span>
<i class="fas fa-clock" style="margin-left:12px;"></i> {{ $kegiatan->waktu_lengkap }}
<i class="fas fa-calendar" style="margin-left:12px;"></i> {{ $kegiatan->hari }}
</p>
@if(!$kegiatan->isForAllClasses())
<p style="margin:4px 0 0; font-size:0.82rem;">
<i class="fas fa-school"></i> Kelas:
@foreach($kegiatan->kelasKegiatan as $kk)
<span class="badge badge-success">{{ $kk->nama_kelas }}</span>
@endforeach
</p>
@else
<p style="margin:4px 0 0; font-size:0.82rem;"><i class="fas fa-globe"></i> Kegiatan Umum (Semua Kelas)</p>
@endif
</div>
<div style="text-align:right;">
<p style="margin:0; font-size:0.82rem; color:var(--text-light);">Periode: <strong>{{ $periodeLabel }}</strong></p>
</div>
</div>
</div>
{{-- Mini KPI --}}
<div class="mini-kpi">
<div class="mini-kpi-card hadir">
<div class="mini-kpi-val">{{ $stats->hadir ?? 0 }}</div>
<div class="mini-kpi-label"><i class="fas fa-check"></i> Hadir</div>
</div>
<div class="mini-kpi-card izin">
<div class="mini-kpi-val">{{ $stats->izin ?? 0 }}</div>
<div class="mini-kpi-label"><i class="fas fa-info-circle"></i> Izin</div>
</div>
<div class="mini-kpi-card sakit">
<div class="mini-kpi-val">{{ $stats->sakit ?? 0 }}</div>
<div class="mini-kpi-label"><i class="fas fa-heartbeat"></i> Sakit</div>
</div>
<div class="mini-kpi-card alpa">
<div class="mini-kpi-val">{{ $stats->alpa ?? 0 }}</div>
<div class="mini-kpi-label"><i class="fas fa-times"></i> Alpa</div>
</div>
</div>
{{-- Overall Progress --}}
<div class="content-box" style="margin-bottom: 14px;">
<h4 style="margin:0 0 8px;"><i class="fas fa-percentage"></i> Rata-rata Kehadiran</h4>
@php $statsPersen = $stats->persen ?? 0; @endphp
<div class="progress-bar-lg">
<div class="fill" style="width:{{ $statsPersen }}%; background:{{ $statsPersen >= 85 ? '#10B981' : ($statsPersen >= 70 ? '#FBBF24' : '#EF4444') }};">
{{ $statsPersen }}%
</div>
</div>
</div>
<div class="two-col">
{{-- Trend Chart --}}
<div class="chart-box">
<h4><i class="fas fa-chart-line"></i> Trend 4 Minggu Terakhir</h4>
<div style="height:250px;">
<canvas id="kegiatanTrendChart"></canvas>
</div>
</div>
{{-- Punctuality --}}
<div class="chart-box">
<h4><i class="fas fa-stopwatch"></i> Ketepatan Waktu (RFID)</h4>
@if($punctuality && $punctuality->total > 0)
<div style="height:250px;">
<canvas id="punctualityChart"></canvas>
</div>
<div style="margin-top:12px; font-size:0.82rem; color:var(--text-light); text-align:center;">
{{ $punctuality->tepat_waktu ?? 0 }} tepat waktu, {{ $punctuality->terlambat ?? 0 }} terlambat dari {{ $punctuality->total }} total
</div>
@else
<div class="insight-box i-info"><i class="fas fa-info-circle"></i> Belum ada data RFID untuk analisis ketepatan waktu.</div>
@endif
</div>
</div>
{{-- Breakdown Per Kelas --}}
@if(!empty($breakdownPerKelas) && count($breakdownPerKelas) > 0)
<div class="chart-box">
<h4><i class="fas fa-school"></i> Breakdown Per Kelas</h4>
<div class="table-wrapper">
<table class="data-table" style="font-size:0.85rem;">
<thead><tr><th>Kelas</th><th class="text-center">Total</th><th class="text-center">Hadir</th><th class="text-center" style="min-width:180px;">% Kehadiran</th></tr></thead>
<tbody>
@foreach($breakdownPerKelas as $bk)
<tr style="{{ $bk['persen'] < 70 ? 'background:#FEF2F2;' : '' }}">
<td><strong>{{ $bk['kelas'] }}</strong></td>
<td class="text-center">{{ $bk['total'] }}</td>
<td class="text-center"><span class="badge badge-success">{{ $bk['hadir'] }}</span></td>
<td class="text-center">
<div class="progress-inline" style="justify-content:center;">
<div class="progress-bar-mini"><div class="fill" style="width:{{ $bk['persen'] }}%; background:{{ $bk['persen'] >= 85 ? '#10B981' : ($bk['persen'] >= 70 ? '#FBBF24' : '#EF4444') }};"></div></div>
<strong>{{ $bk['persen'] }}%</strong>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endif
{{-- Santri Tidak Pernah Hadir --}}
@if($santriTidakPernahHadir && $santriTidakPernahHadir->count() > 0)
<div class="chart-box">
<h4><i class="fas fa-user-times" style="color:#EF4444;"></i> Santri Tidak Pernah Hadir</h4>
<div style="display:flex; flex-wrap:wrap; gap:8px;">
@foreach($santriTidakPernahHadir as $sth)
<a href="{{ route('admin.laporan-kegiatan.detail-santri', $sth->id_santri) }}" class="badge badge-danger" style="padding:6px 12px; font-size:0.82rem; text-decoration:none;">
{{ $sth->santri->nama_lengkap ?? $sth->id_santri }}
</a>
@endforeach
</div>
</div>
@endif
{{-- Insights & Rekomendasi --}}
@if(!empty($insights))
<div class="chart-box">
<h4><i class="fas fa-lightbulb"></i> Insight & Rekomendasi</h4>
@foreach($insights as $insight)
<div class="insight-box i-{{ $insight['type'] }}">
<i class="{{ $insight['icon'] }}"></i>
{{ $insight['text'] }}
</div>
@endforeach
</div>
@endif
{{-- Actions --}}
<div class="content-box" style="display:flex; gap:8px; flex-wrap:wrap;">
<a href="{{ route('admin.absensi-kegiatan.rekap', $kegiatan->kegiatan_id) }}" class="btn btn-info">
<i class="fas fa-list"></i> Rekap Absensi
</a>
<button onclick="window.print()" class="btn btn-secondary"><i class="fas fa-print"></i> Cetak</button>
<a href="{{ route('admin.laporan-kegiatan.index') }}" class="btn btn-secondary"><i class="fas fa-arrow-left"></i> Kembali</a>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
<script>
// Trend Chart
const trend = @json($trend);
new Chart(document.getElementById('kegiatanTrendChart'), {
type: 'line',
data: {
labels: trend.map(t => t.label),
datasets: [{
label: '% Kehadiran',
data: trend.map(t => t.persen),
borderColor: '#3B82F6',
backgroundColor: 'rgba(59,130,246,0.1)',
tension: 0.4, fill: true, pointRadius: 6,
pointBackgroundColor: trend.map(t => t.persen >= 85 ? '#10B981' : (t.persen >= 70 ? '#FBBF24' : '#EF4444')),
}]
},
options: {
responsive: true, maintainAspectRatio: false,
plugins: { legend: { display: false }, tooltip: { callbacks: { label: ctx => ctx.raw + '%' } } },
scales: { y: { min: 0, max: 100, ticks: { callback: v => v + '%' } }, x: { grid: { display: false } } }
}
});
// Punctuality Pie
@if($punctuality && $punctuality->total > 0)
new Chart(document.getElementById('punctualityChart'), {
type: 'doughnut',
data: {
labels: ['Tepat Waktu', 'Terlambat'],
datasets: [{
data: [{{ $punctuality->tepat_waktu ?? 0 }}, {{ $punctuality->terlambat ?? 0 }}],
backgroundColor: ['#10B981', '#EF4444'],
borderWidth: 2, hoverOffset: 8
}]
},
options: {
responsive: true, maintainAspectRatio: false,
plugins: { legend: { position: 'bottom', labels: { usePointStyle: true } } }
}
});
@endif
</script>
<style>
@media print {
.btn, button { display: none !important; }
.chart-box, .content-box { box-shadow: none !important; border: 1px solid #e2e8f0; page-break-inside: avoid; }
}
</style>
@endsection

View File

@ -1,234 +0,0 @@
@extends('layouts.app')
@section('content')
<style>
.detail-header { display: flex; gap: 20px; align-items: flex-start; margin-bottom: 14px; }
.detail-avatar { width: 80px; height: 80px; border-radius: 50%; background: linear-gradient(135deg, #10B981, #34D399); display: flex; align-items: center; justify-content: center; color: #fff; font-size: 2rem; font-weight: 700; flex-shrink: 0; }
.detail-info h3 { margin: 0 0 4px; color: var(--primary-dark); }
.detail-info p { margin: 0; font-size: 0.85rem; color: var(--text-light); }
.mini-kpi { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin-bottom: 14px; }
.mini-kpi-card { padding: 16px; border-radius: 10px; text-align: center; }
.mini-kpi-card.hadir { background: #ECFDF5; color: #065F46; }
.mini-kpi-card.izin { background: #FFFBEB; color: #92400E; }
.mini-kpi-card.sakit { background: #EFF6FF; color: #1E40AF; }
.mini-kpi-card.alpa { background: #FEF2F2; color: #991B1B; }
.mini-kpi-val { font-size: 1.6rem; font-weight: 700; }
.mini-kpi-label { font-size: 0.78rem; margin-top: 4px; }
.chart-box { background: #fff; border-radius: 12px; padding: 14px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); margin-bottom: 14px; }
.chart-box h4 { margin: 0 0 16px; color: var(--primary-dark); font-size: 1rem; }
.progress-bar-lg { background: #e9ecef; border-radius: 10px; height: 24px; overflow: hidden; margin: 12px 0; }
.progress-bar-lg .fill { height: 100%; border-radius: 10px; transition: width 0.5s; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 0.82rem; font-weight: 600; }
.insight-box { padding: 12px 16px; border-radius: 8px; margin-bottom: 8px; display: flex; align-items: flex-start; gap: 10px; font-size: 0.85rem; }
.insight-box.i-success { background: #ECFDF5; color: #065F46; }
.insight-box.i-warning { background: #FFFBEB; color: #92400E; }
.insight-box.i-danger { background: #FEF2F2; color: #991B1B; }
.insight-box.i-info { background: #EFF6FF; color: #1E40AF; }
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
@media(max-width:768px){ .two-col { grid-template-columns: 1fr; } }
.progress-inline { display: flex; align-items: center; gap: 8px; }
.progress-bar-mini { flex: 1; background: #e9ecef; border-radius: 8px; height: 8px; overflow: hidden; max-width: 120px; }
.progress-bar-mini .fill { height: 100%; border-radius: 8px; }
.text-center { text-align: center; }
</style>
<div class="page-header">
<h2><i class="fas fa-user-chart"></i> Detail Kehadiran Santri</h2>
<a href="{{ route('admin.laporan-kegiatan.index', request()->query()) }}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
{{-- Header --}}
<div class="content-box" style="margin-bottom: 14px;">
<div class="detail-header">
<div class="detail-avatar">{{ strtoupper(substr($santri->nama_lengkap, 0, 1)) }}</div>
<div class="detail-info">
<h3>{{ $santri->nama_lengkap }}</h3>
<p><i class="fas fa-id-card"></i> {{ $santri->id_santri }}</p>
@if($santri->kelasSantri && $santri->kelasSantri->count() > 0)
<p><i class="fas fa-school"></i>
@foreach($santri->kelasSantri as $ks)
<span class="badge badge-info">{{ $ks->kelas->nama_kelas ?? '-' }}</span>
@endforeach
</p>
@endif
<p style="margin-top:4px;"><i class="fas fa-calendar"></i> Periode: <strong>{{ $periodeLabel }}</strong></p>
</div>
</div>
</div>
{{-- Mini KPI --}}
<div class="mini-kpi">
<div class="mini-kpi-card hadir">
<div class="mini-kpi-val">{{ $stats->hadir ?? 0 }}</div>
<div class="mini-kpi-label"><i class="fas fa-check"></i> Hadir</div>
</div>
<div class="mini-kpi-card izin">
<div class="mini-kpi-val">{{ $stats->izin ?? 0 }}</div>
<div class="mini-kpi-label"><i class="fas fa-info-circle"></i> Izin</div>
</div>
<div class="mini-kpi-card sakit">
<div class="mini-kpi-val">{{ $stats->sakit ?? 0 }}</div>
<div class="mini-kpi-label"><i class="fas fa-heartbeat"></i> Sakit</div>
</div>
<div class="mini-kpi-card alpa">
<div class="mini-kpi-val">{{ $stats->alpa ?? 0 }}</div>
<div class="mini-kpi-label"><i class="fas fa-times"></i> Alpa</div>
</div>
</div>
{{-- Overall Progress --}}
<div class="content-box" style="margin-bottom: 14px;">
<h4 style="margin:0 0 8px; font-size:0.95rem;"><i class="fas fa-chart-bar"></i> Kehadiran Keseluruhan</h4>
<div class="progress-bar-lg">
<div class="fill" style="width:{{ $persenKehadiran }}%; background:{{ $persenKehadiran >= 85 ? '#10B981' : ($persenKehadiran >= 70 ? '#FBBF24' : '#EF4444') }};">
{{ $persenKehadiran }}%
</div>
</div>
@if($persenKehadiran >= 85)
<div class="insight-box i-success"><i class="fas fa-star"></i> Kehadiran sangat baik. Pertahankan!</div>
@elseif($persenKehadiran >= 70)
<div class="insight-box i-warning"><i class="fas fa-exclamation-triangle"></i> Kehadiran cukup, perlu ditingkatkan.</div>
@else
<div class="insight-box i-danger"><i class="fas fa-times-circle"></i> Kehadiran di bawah standar. Perlu perhatian khusus.</div>
@endif
</div>
<div class="two-col">
{{-- Trend 4 Minggu --}}
<div class="chart-box">
<h4><i class="fas fa-chart-line"></i> Trend 4 Minggu Terakhir</h4>
<div style="height:220px;">
<canvas id="santriTrendChart"></canvas>
</div>
</div>
{{-- Insights --}}
<div class="chart-box">
<h4><i class="fas fa-lightbulb"></i> Insight</h4>
@if($kegiatanBolos)
<div class="insight-box i-danger">
<i class="fas fa-user-times"></i>
Paling sering Alpa di kegiatan: <strong>{{ $kegiatanBolos->kegiatan->nama_kegiatan ?? '-' }}</strong> ({{ $kegiatanBolos->total_alpa }}x)
</div>
@endif
@if($streak > 0)
<div class="insight-box i-success">
<i class="fas fa-fire"></i>
Streak kehadiran beruntun: <strong>{{ $streak }} kegiatan</strong> 🔥
</div>
@endif
@if(($stats->total ?? 0) > 0)
<div class="insight-box i-info">
<i class="fas fa-calculator"></i>
Total tercatat: {{ $stats->total }} absensi ({{ $stats->hadir }} hadir, {{ $stats->alpa }} alpa)
</div>
@endif
</div>
</div>
{{-- Kehadiran Per Kegiatan --}}
<div class="chart-box">
<h4><i class="fas fa-tasks"></i> Kehadiran Per Kegiatan</h4>
@if($perKegiatan->count() > 0)
<div class="table-wrapper">
<table class="data-table" style="font-size:0.85rem;">
<thead>
<tr>
<th>No</th><th>Kegiatan</th>
<th class="text-center">Hadir</th><th class="text-center">Izin</th>
<th class="text-center">Sakit</th><th class="text-center">Alpa</th>
<th class="text-center" style="min-width:180px;">% Kehadiran</th>
</tr>
</thead>
<tbody>
@foreach($perKegiatan as $i => $kg)
<tr style="{{ $kg->persen < 70 ? 'background:#FEF2F2;' : '' }}">
<td>{{ $i + 1 }}</td>
<td><strong>{{ $kg->nama_kegiatan }}</strong></td>
<td class="text-center"><span class="badge badge-success">{{ $kg->hadir }}</span></td>
<td class="text-center"><span class="badge badge-warning">{{ $kg->izin }}</span></td>
<td class="text-center"><span class="badge badge-info">{{ $kg->sakit }}</span></td>
<td class="text-center"><span class="badge badge-danger">{{ $kg->alpa }}</span></td>
<td class="text-center">
<div class="progress-inline" style="justify-content:center;">
<div class="progress-bar-mini"><div class="fill" style="width:{{ $kg->persen }}%; background:{{ $kg->persen >= 85 ? '#10B981' : ($kg->persen >= 70 ? '#FBBF24' : '#EF4444') }};"></div></div>
<strong style="color:{{ $kg->persen >= 85 ? '#10B981' : ($kg->persen >= 70 ? '#92400E' : '#EF4444') }};">{{ $kg->persen }}%</strong>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@else
<p style="color:var(--text-light); font-size:0.85rem;">Belum ada data kehadiran per kegiatan.</p>
@endif
</div>
{{-- Riwayat Terbaru --}}
<div class="chart-box">
<h4><i class="fas fa-history"></i> Riwayat Absensi Terbaru</h4>
@if($riwayatTerbaru->count() > 0)
<div class="table-wrapper">
<table class="data-table" style="font-size:0.85rem;">
<thead><tr><th>Tanggal</th><th>Kegiatan</th><th>Kategori</th><th class="text-center">Status</th></tr></thead>
<tbody>
@foreach($riwayatTerbaru as $r)
<tr>
<td>{{ $r->tanggal->format('d/m/Y') }}</td>
<td>{{ $r->kegiatan->nama_kegiatan ?? '-' }}</td>
<td>{{ $r->kegiatan->kategori->nama_kategori ?? '-' }}</td>
<td class="text-center">{!! $r->status_badge !!}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@else
<p style="color:var(--text-light);">Belum ada riwayat.</p>
@endif
</div>
{{-- Actions --}}
<div class="content-box" style="display:flex; gap:8px; flex-wrap:wrap;">
<a href="{{ route('admin.riwayat-kegiatan.detail-santri', $santri->id_santri) }}" class="btn btn-info">
<i class="fas fa-history"></i> Riwayat Lengkap
</a>
<button onclick="window.print()" class="btn btn-secondary"><i class="fas fa-print"></i> Cetak Laporan</button>
<a href="{{ route('admin.laporan-kegiatan.index') }}" class="btn btn-secondary"><i class="fas fa-arrow-left"></i> Kembali ke Laporan</a>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
<script>
const trend = @json($trend);
new Chart(document.getElementById('santriTrendChart'), {
type: 'line',
data: {
labels: trend.map(t => t.label),
datasets: [{
label: '% Kehadiran',
data: trend.map(t => t.persen),
borderColor: '#3B82F6',
backgroundColor: 'rgba(59,130,246,0.1)',
tension: 0.4,
fill: true,
pointRadius: 6,
pointBackgroundColor: trend.map(t => t.persen >= 85 ? '#10B981' : (t.persen >= 70 ? '#FBBF24' : '#EF4444')),
}]
},
options: {
responsive: true, maintainAspectRatio: false,
plugins: { legend: { display: false }, tooltip: { callbacks: { label: ctx => ctx.raw + '%' } } },
scales: { y: { min: 0, max: 100, ticks: { callback: v => v + '%' } }, x: { grid: { display: false } } }
}
});
</script>
<style>
@media print {
.btn, button, .page-header .btn { display: none !important; }
.chart-box, .content-box { box-shadow: none !important; border: 1px solid #e2e8f0; page-break-inside: avoid; }
}
</style>
@endsection

View File

@ -10,14 +10,24 @@
<div class="page-header"> <div class="page-header">
<h2><i class="fas fa-user-clock"></i> Santri Perlu Perhatian</h2> <h2><i class="fas fa-user-clock"></i> Santri Perlu Perhatian</h2>
<a href="{{ route('admin.laporan-kegiatan.index') }}" class="btn btn-secondary"> <a href="{{ route('admin.laporan-kegiatan.index', request()->only('periode','tanggal_dari','tanggal_sampai')) }}"
class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali <i class="fas fa-arrow-left"></i> Kembali
</a> </a>
</div> </div>
{{-- Konteks header --}}
<div class="content-box" style="margin-bottom:14px;"> <div class="content-box" style="margin-bottom:14px;">
<p style="margin:0; color:var(--text-light); font-size:0.85rem;"> <p style="margin:0;font-size:.88rem;color:var(--text-light);">
<i class="fas fa-info-circle"></i> Daftar santri dengan kehadiran &lt;70% dalam periode <strong>{{ $periodeLabel }}</strong> <i class="fas fa-info-circle"></i>
Menampilkan <strong>{{ $santris->total() }} santri</strong>
dari <strong>{{ $totalSantriAktif }} santri aktif</strong>
yang kehadiran efektifnya &lt;70%
dalam periode <strong>{{ $periodeLabel }}</strong>.
<br>
<span style="font-size:.8rem;opacity:.8;">
<i class="fas fa-clock"></i> Terlambat dihitung sebagai Hadir efektif.
</span>
</p> </p>
</div> </div>
@ -25,13 +35,15 @@
<div class="content-box" style="margin-bottom:14px;"> <div class="content-box" style="margin-bottom:14px;">
<form method="GET" style="display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;"> <form method="GET" style="display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;">
<input type="hidden" name="periode" value="{{ request('periode','bulan_ini') }}"> <input type="hidden" name="periode" value="{{ request('periode','bulan_ini') }}">
<input type="hidden" name="tanggal_dari" value="{{ request('tanggal_dari') }}">
<input type="hidden" name="tanggal_sampai" value="{{ request('tanggal_sampai') }}">
<div class="form-group" style="margin:0;"> <div class="form-group" style="margin:0;">
<label style="font-size:0.82rem;">Filter Kelas</label> <label style="font-size:.82rem;">Filter Kelas</label>
<select name="id_kelas" class="form-control" style="min-width:180px;"> <select name="id_kelas" class="form-control" style="min-width:180px;">
<option value="">-- Semua Kelas --</option> <option value="">-- Semua Kelas --</option>
@foreach($kelasList as $k) @foreach($kelasList as $k)
<option value="{{ $k->id }}" {{ request('id_kelas')==$k->id?'selected':'' }}> <option value="{{ $k->id }}" {{ request('id_kelas')==$k->id?'selected':'' }}>
{{ $k->kelompok->nama_kelompok ?? '' }} - {{ $k->nama_kelas }} {{ $k->kelompok->nama_kelompok ?? '' }} {{ $k->nama_kelas }}
</option> </option>
@endforeach @endforeach
</select> </select>
@ -43,18 +55,24 @@
<div class="content-box"> <div class="content-box">
@if($santris->count() > 0) @if($santris->count() > 0)
<div class="table-wrapper"> <div class="table-wrapper">
<table class="data-table" style="font-size:0.85rem;"> <table class="data-table" style="font-size:.84rem;">
<thead> <thead>
<tr> <tr>
<th>No</th> <th>No</th>
<th>ID Santri</th>
<th>Nama</th> <th>Nama</th>
<th class="text-center">Total</th> <th class="text-center">Total Sesi</th>
<th class="text-center">Hadir</th> <th class="text-center">
Hadir Efektif
<span style="display:block;font-weight:400;font-size:.73rem;color:#9CA3AF;">(Hadir+Terlambat)</span>
</th>
<th class="text-center">Terlambat</th>
<th class="text-center">Alpa</th> <th class="text-center">Alpa</th>
<th class="text-center">Izin</th> <th class="text-center">Izin</th>
<th class="text-center">Sakit</th> <th class="text-center">Sakit</th>
<th class="text-center" style="min-width:180px;">% Kehadiran</th> <th class="text-center" style="min-width:180px;">
% Kehadiran
<span style="display:block;font-weight:400;font-size:.73rem;color:#9CA3AF;">(hadir / total sesi)</span>
</th>
<th>Aksi</th> <th>Aksi</th>
</tr> </tr>
</thead> </thead>
@ -62,22 +80,48 @@
@foreach($santris as $i => $s) @foreach($santris as $i => $s)
<tr> <tr>
<td>{{ $santris->firstItem() + $i }}</td> <td>{{ $santris->firstItem() + $i }}</td>
<td><code>{{ $s->id_santri }}</code></td> <td>
<td><strong>{{ $s->nama_lengkap }}</strong></td> <strong>{{ $s->nama_lengkap }}</strong>
<div style="font-size:.75rem;color:#9CA3AF;"><code>{{ $s->id_santri }}</code></div>
</td>
<td class="text-center">{{ $s->total }}</td> <td class="text-center">{{ $s->total }}</td>
<td class="text-center"><span class="badge badge-success">{{ $s->hadir }}</span></td> <td class="text-center">
<td class="text-center"><span class="badge badge-danger">{{ $s->alpa }}</span></td> <span class="badge badge-success">{{ $s->hadir }}</span>
<td class="text-center"><span class="badge badge-warning">{{ $s->izin }}</span></td> </td>
<td class="text-center"><span class="badge badge-info">{{ $s->sakit }}</span></td> <td class="text-center">
@if(($s->terlambat ?? 0) > 0)
<span class="badge badge-warning">{{ $s->terlambat }}</span>
@else
<span style="color:#9CA3AF;">0</span>
@endif
</td>
<td class="text-center">
<span class="badge badge-danger">{{ $s->alpa }}</span>
</td>
<td class="text-center">
<span class="badge badge-warning">{{ $s->izin }}</span>
</td>
<td class="text-center">
<span class="badge badge-info">{{ $s->sakit }}</span>
</td>
<td class="text-center"> <td class="text-center">
<div class="progress-inline" style="justify-content:center;"> <div class="progress-inline" style="justify-content:center;">
<div class="progress-bar-mini"><div class="fill" style="width:{{ $s->persen }}%; background:#EF4444;"></div></div> <div class="progress-bar-mini">
<div class="fill" style="width:{{ $s->persen }}%;background:#EF4444;"></div>
</div>
<div>
<strong style="color:#EF4444;">{{ $s->persen }}%</strong> <strong style="color:#EF4444;">{{ $s->persen }}%</strong>
{{-- Konteks X dari Y --}}
<div style="font-size:.72rem;color:#9CA3AF;">
{{ $s->hadir }} dari {{ $s->total }}
</div>
</div>
</div> </div>
</td> </td>
<td> <td>
<a href="{{ route('admin.laporan-kegiatan.detail-santri', $s->id_santri) }}" class="btn btn-sm btn-info" title="Detail"> <a href="{{ route('admin.riwayat-kegiatan.detail-santri', $s->id_santri) }}"
<i class="fas fa-eye"></i> class="btn btn-sm btn-info" title="Lihat Riwayat Lengkap">
<i class="fas fa-history"></i> Riwayat
</a> </a>
</td> </td>
</tr> </tr>
@ -85,13 +129,10 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<div style="margin-top:16px;">{{ $santris->links() }}</div>
<div style="margin-top:16px;">
{{ $santris->links() }}
</div>
@else @else
<div class="empty-state"> <div class="empty-state">
<i class="fas fa-check-circle" style="color:#10B981;"></i> <i class="fas fa-check-circle" style="color:#10B981;font-size:2rem;"></i>
<h3>Alhamdulillah!</h3> <h3>Alhamdulillah!</h3>
<p>Tidak ada santri dengan kehadiran di bawah 70%.</p> <p>Tidak ada santri dengan kehadiran di bawah 70%.</p>
</div> </div>

View File

@ -0,0 +1,104 @@
{{-- resources/views/admin/kegiatan/riwayat/_card.blade.php --}}
{{-- Diinclude dari index.blade.php --}}
@php
$totalSantri = $kegiatan->total_absensi;
$hdr = $kegiatan->hadir ?? 0;
$tlb = $kegiatan->terlambat ?? 0;
$izn = $kegiatan->izin ?? 0;
$skt = $kegiatan->sakit ?? 0;
$alp = $kegiatan->alpa ?? 0;
$plg = $kegiatan->pulang ?? 0;
$tot = $kegiatan->total_absensi ?? 0;
$pct = fn($n) => $tot > 0 ? round($n / $tot * 100) : 0;
$isUmum = $kegiatan->kelasKegiatan->isEmpty();
@endphp
<div class="rw-card">
{{-- Header --}}
<div class="rw-card-head">
<div style="flex: 1; min-width: 0;">
<div class="rw-card-title">
<i class="fas fa-clipboard-list"></i>
{{ $kegiatan->nama_kegiatan }}
</div>
<div class="rw-card-meta">
<span><i class="fas fa-clock"></i>
{{ date('H:i', strtotime($kegiatan->waktu_mulai)) }}{{ date('H:i', strtotime($kegiatan->waktu_selesai)) }}
</span>
<span class="rw-kat-tag"><i class="fas fa-tag"></i> {{ $kegiatan->kategori->nama_kategori }}</span>
@if($isUmum)
<span class="rw-umum-tag"><i class="fas fa-globe"></i> Umum</span>
@else
@foreach($kegiatan->kelasKegiatan->take(3) as $kls)
<span class="rw-kelas-tag">{{ $kls->nama_kelas }}</span>
@endforeach
@if($kegiatan->kelasKegiatan->count() > 3)
<span class="rw-umum-tag">+{{ $kegiatan->kelasKegiatan->count() - 3 }} kelas</span>
@endif
@endif
</div>
</div>
{{-- Hari badge (jika mode hari ini) --}}
@if(isset($passParams) && $passParams['mode'] === 'hari_ini')
<div style="font-size: 0.75rem; color: var(--primary-color); font-weight: 700;
background: #f0fdf4; padding: 4px 10px; border-radius: 20px; border: 1px solid #bbf7d0;
white-space: nowrap; flex-shrink: 0;">
<i class="fas fa-calendar-day"></i> {{ $kegiatan->hari }}
</div>
@endif
</div>
{{-- Body: stats --}}
<div class="rw-card-body">
@if($tot > 0)
{{-- Chips --}}
<div class="rw-stats-row">
@if($hdr > 0) <span class="rw-chip hadir"><i class="fas fa-check"></i> {{ $hdr }} Hadir</span> @endif
@if($tlb > 0) <span class="rw-chip terlambat"><i class="fas fa-clock"></i> {{ $tlb }} Terlambat</span> @endif
@if($izn > 0) <span class="rw-chip izin"><i class="fas fa-envelope"></i> {{ $izn }} Izin</span> @endif
@if($skt > 0) <span class="rw-chip sakit"><i class="fas fa-heartbeat"></i> {{ $skt }} Sakit</span> @endif
@if($alp > 0) <span class="rw-chip alpa"><i class="fas fa-times"></i> {{ $alp }} Alpa</span> @endif
@if($plg > 0) <span class="rw-chip pulang"><i class="fas fa-home"></i> {{ $plg }} Pulang</span> @endif
</div>
{{-- Progress bar --}}
<div class="rw-progress-wrap">
@if($hdr > 0) <div class="rw-prog-hadir" style="width:{{ $pct($hdr) }}%;" title="Hadir {{ $hdr }}"></div> @endif
@if($tlb > 0) <div class="rw-prog-terlambat" style="width:{{ $pct($tlb) }}%;" title="Terlambat {{ $tlb }}"></div> @endif
@if($izn > 0) <div class="rw-prog-izin" style="width:{{ $pct($izn) }}%;" title="Izin {{ $izn }}"></div> @endif
@if($skt > 0) <div class="rw-prog-sakit" style="width:{{ $pct($skt) }}%;" title="Sakit {{ $skt }}"></div> @endif
@if($alp > 0) <div class="rw-prog-alpa" style="width:{{ $pct($alp) }}%;" title="Alpa {{ $alp }}"></div> @endif
@if($plg > 0) <div class="rw-prog-pulang" style="width:{{ $pct($plg) }}%;" title="Pulang {{ $plg }}"></div> @endif
</div>
<div style="font-size: 0.74rem; color: #94a3b8;">
Total tercatat: <strong style="color:#374151;">{{ $tot }}</strong> santri
</div>
@else
<span class="rw-chip none"><i class="fas fa-inbox"></i> Belum ada data absensi</span>
@endif
</div>
{{-- Footer --}}
<div class="rw-card-foot">
<div class="rw-total-txt">
@if($tot > 0)
<i class="fas fa-users" style="color:var(--primary-color);"></i>
<strong>{{ $hdr + $tlb }}</strong> hadir dari <strong>{{ $tot }}</strong> tercatat
@else
<span style="color:#cbd5e1;"><i class="fas fa-info-circle"></i> Belum ada absensi diinput</span>
@endif
</div>
@php
$detailParams = array_merge($passParams ?? [], ['kategori_id' => request('kategori_id')]);
@endphp
<a href="{{ route('admin.riwayat-kegiatan.show', $kegiatan->id) }}?{{ http_build_query($detailParams) }}"
class="btn-rw-detail">
<i class="fas fa-users"></i> Lihat Santri
</a>
</div>
</div>

View File

@ -2,228 +2,406 @@
@extends('layouts.app') @extends('layouts.app')
@section('content') @section('content')
<div class="page-header"> <style>
<h2><i class="fas fa-user-clock"></i> Riwayat Kehadiran: {{ $santri->nama_lengkap }}</h2> /* =====================================================
</div> DETAIL SANTRI Riwayat Kehadiran
===================================================== */
<!-- Info Santri --> .ds-header { display:flex; justify-content:space-between; align-items:flex-start; gap:12px;
<div class="content-box" style="margin-bottom: 14px;"> margin-bottom:18px; flex-wrap:wrap; }
<div style="display: flex; justify-content: space-between; align-items: center;"> .ds-header h2 { margin:0; font-size:1.3rem; color:var(--primary-dark); display:flex; align-items:center; gap:9px; }
<div>
<h3 style="margin: 0; color: var(--primary-color);">{{ $santri->nama_lengkap }}</h3> /* Info santri */
<p style="margin: 5px 0 0 0; color: var(--text-light);"> .ds-info-box { background:#fff; border-radius:12px; padding:16px 20px; margin-bottom:14px;
ID: <strong>{{ $santri->id_santri }}</strong> | box-shadow:0 2px 10px rgba(0,0,0,0.06); display:flex; justify-content:space-between;
Kelas: <strong>{{ $santri->kelas }}</strong> | align-items:center; flex-wrap:wrap; gap:12px; }
Status: <span class="badge badge-success">{{ $santri->status }}</span> .ds-info-box h3 { margin:0 0 5px; color:var(--primary-color); font-size:1.1rem; }
</p> .ds-info-meta { font-size:0.83rem; color:#64748b; display:flex; flex-wrap:wrap; gap:10px; }
</div> .ds-info-meta span { display:inline-flex; align-items:center; gap:4px; }
<a href="{{ route('admin.riwayat-kegiatan.index') }}" class="btn btn-secondary">
/* KPI cards */
.ds-kpi-grid { display:grid; grid-template-columns:repeat(5,1fr); gap:10px; margin-bottom:14px; }
@media(max-width:900px) { .ds-kpi-grid { grid-template-columns:repeat(3,1fr); } }
@media(max-width:540px) { .ds-kpi-grid { grid-template-columns:repeat(2,1fr); } }
.ds-kpi { background:#fff; border-radius:10px; padding:12px 14px;
box-shadow:0 2px 8px rgba(0,0,0,0.06); display:flex; align-items:center; gap:10px; }
.ds-kpi .ico { width:36px; height:36px; border-radius:9px; display:flex; align-items:center;
justify-content:center; font-size:1.1rem; flex-shrink:0; }
.ds-kpi.hadir .ico { background:#d1fae5; color:#065f46; }
.ds-kpi.terlambat .ico { background:#fff3e0; color:#e65100; }
.ds-kpi.izin .ico { background:#fef3c7; color:#92400e; }
.ds-kpi.sakit .ico { background:#dbeafe; color:#1e40af; }
.ds-kpi.alpa .ico { background:#fee2e2; color:#991b1b; }
.ds-kpi .cnt { font-size:1.4rem; font-weight:800; color:var(--primary-dark); line-height:1; }
.ds-kpi .lbl { font-size:0.74rem; color:#94a3b8; margin-top:2px; }
/* Terlambat note */
.ds-terlambat-note { font-size:0.76rem; color:#6b7280; background:#fff7ed; border:1px solid #fed7aa;
border-radius:8px; padding:6px 12px; margin-bottom:14px;
display:flex; align-items:center; gap:6px; }
.ds-terlambat-note i { color:#ea580c; }
/* Tren chart box */
.ds-chart-box { background:#fff; border-radius:12px; padding:16px 18px; margin-bottom:14px;
box-shadow:0 2px 10px rgba(0,0,0,0.06); }
.ds-chart-box h4 { margin:0 0 14px; color:var(--primary-color); font-size:0.95rem;
display:flex; align-items:center; gap:7px; }
/* Riwayat lengkap dengan tabs */
.ds-riwayat-box { background:#fff; border-radius:12px; overflow:hidden; margin-bottom:14px;
box-shadow:0 2px 10px rgba(0,0,0,0.06); }
.ds-riwayat-head { padding:14px 18px 0; border-bottom:2px solid #f1f5f9; }
.ds-riwayat-head h4 { margin:0 0 12px; color:var(--primary-dark); font-size:0.95rem;
display:flex; align-items:center; gap:7px; }
/* Tabs */
.ds-tabs { display:flex; gap:0; overflow-x:auto; -webkit-overflow-scrolling:touch; }
.ds-tabs::-webkit-scrollbar { height:0; }
.ds-tab { padding:9px 16px; font-size:0.82rem; font-weight:600; border:none; background:transparent;
cursor:pointer; white-space:nowrap; color:#64748b; border-bottom:3px solid transparent;
transition:all 0.15s; text-decoration:none; display:inline-flex; align-items:center; gap:6px; }
.ds-tab:hover { color:var(--primary-color); background:#f0fdf4; }
.ds-tab.active { color:var(--primary-color); border-bottom-color:var(--primary-color); background:#f0fdf4; }
.ds-tab .tab-cnt { background:#e8f7f2; color:var(--primary-color); padding:1px 7px; border-radius:10px;
font-size:0.72rem; font-weight:700; }
.ds-tab.active .tab-cnt { background:var(--primary-color); color:#fff; }
.ds-tab .tab-hadir { background:#d1fae5; color:#065f46; padding:1px 7px; border-radius:10px;
font-size:0.7rem; font-weight:700; }
/* Per-page toolbar */
.ds-toolbar { display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap;
gap:8px; padding:10px 18px; background:#fafafa; border-bottom:1px solid #f1f5f9; }
.ds-toolbar-left { font-size:0.8rem; color:#64748b; }
.ds-toolbar-right { display:flex; align-items:center; gap:8px; font-size:0.8rem; color:#64748b; }
.ds-perpage-group { display:flex; gap:4px; }
.ds-pp-btn { padding:4px 10px; border:1.5px solid #e2e8f0; border-radius:6px; background:#fff;
font-size:0.78rem; font-weight:600; color:#64748b; cursor:pointer;
text-decoration:none; transition:all 0.15s; }
.ds-pp-btn:hover { border-color:var(--primary-color); color:var(--primary-color); }
.ds-pp-btn.active { background:var(--primary-color); color:#fff; border-color:var(--primary-color); }
/* Table */
.ds-table-wrap { overflow-x:auto; }
.ds-table { width:100%; border-collapse:collapse; min-width:540px; }
.ds-table thead th { padding:9px 14px; text-align:left; font-size:0.78rem; font-weight:600;
color:#64748b; background:#f8fafc; border-bottom:1px solid #e2e8f0; }
.ds-table tbody td { padding:9px 14px; font-size:0.83rem; border-bottom:1px solid #f8fafc; vertical-align:middle; }
.ds-table tbody tr:last-child td { border-bottom:none; }
.ds-table tbody tr:hover { background:#f8fafc; }
/* Status badges (inline fallback jika status_badge tidak ada) */
.s-hadir { background:#d1fae5; color:#065f46; padding:3px 9px; border-radius:9px; font-size:0.74rem; font-weight:700; }
.s-terlambat { background:#fff3e0; color:#e65100; padding:3px 9px; border-radius:9px; font-size:0.74rem; font-weight:700; }
.s-izin { background:#fef3c7; color:#92400e; padding:3px 9px; border-radius:9px; font-size:0.74rem; font-weight:700; }
.s-sakit { background:#dbeafe; color:#1e40af; padding:3px 9px; border-radius:9px; font-size:0.74rem; font-weight:700; }
.s-alpa { background:#fee2e2; color:#991b1b; padding:3px 9px; border-radius:9px; font-size:0.74rem; font-weight:700; }
.s-pulang { background:#f3e8ff; color:#6b21a8; padding:3px 9px; border-radius:9px; font-size:0.74rem; font-weight:700; }
/* Button back */
.btn-ds-back { padding:8px 16px; background:#6b7280; color:#fff; border-radius:8px; font-size:0.82rem;
font-weight:600; text-decoration:none; display:inline-flex; align-items:center; gap:6px;
transition:background 0.18s; }
.btn-ds-back:hover { background:#4b5563; color:#fff; }
/* Empty */
.ds-empty { text-align:center; padding:30px; color:#94a3b8; }
.ds-empty i { font-size:2.5rem; display:block; margin-bottom:10px; opacity:0.35; }
</style>
@php
$totalHadirEfektif = $stats['_hadir_efektif'] ?? 0;
$totalHadir = $stats['Hadir'] ?? 0;
$totalTerlambat = $stats['Terlambat'] ?? 0;
$totalIzin = $stats['Izin'] ?? 0;
$totalSakit = $stats['Sakit'] ?? 0;
$totalAlpa = $stats['Alpa'] ?? 0;
$persenHadir = ($totalHadirEfektif + $totalIzin + $totalSakit + $totalAlpa) > 0
? round($totalHadirEfektif / ($totalHadirEfektif + $totalIzin + $totalSakit + $totalAlpa) * 100, 1)
: 0;
@endphp
{{-- Header --}}
<div class="ds-header">
<h2><i class="fas fa-user-clock" style="color:var(--primary-color);"></i>
Riwayat Kehadiran: {{ $santri->nama_lengkap }}
</h2>
<a href="{{ route('admin.riwayat-kegiatan.index') }}" class="btn-ds-back">
<i class="fas fa-arrow-left"></i> Kembali <i class="fas fa-arrow-left"></i> Kembali
</a> </a>
</div> </div>
</div>
<!-- Statistik Cards --> {{-- Info Santri --}}
<div class="row-cards"> <div class="ds-info-box">
<div class="card card-success"> <div>
<h3>Total Hadir</h3> <h3>{{ $santri->nama_lengkap }}</h3>
<div class="card-value">{{ $stats['Hadir'] ?? 0 }}</div> <div class="ds-info-meta">
<i class="fas fa-check-circle card-icon"></i> <span><i class="fas fa-id-card"></i> <strong>{{ $santri->id_santri }}</strong></span>
<span><i class="fas fa-school"></i> {{ $santri->kelas }}</span>
<span><i class="fas fa-circle" style="font-size:0.5rem; color:#22c55e;"></i>
<span class="badge badge-success" style="font-size:0.76rem;">{{ $santri->status }}</span>
</span>
@if($persenHadir > 0)
<span style="font-weight:700; color:{{ $persenHadir >= 85 ? '#059669' : ($persenHadir >= 70 ? '#d97706' : '#dc2626') }};">
<i class="fas fa-chart-pie"></i> Kehadiran {{ $persenHadir }}%
</span>
@endif
</div> </div>
<div class="card card-warning">
<h3>Total Izin</h3>
<div class="card-value">{{ $stats['Izin'] ?? 0 }}</div>
<i class="fas fa-info-circle card-icon"></i>
</div>
<div class="card card-info">
<h3>Total Sakit</h3>
<div class="card-value">{{ $stats['Sakit'] ?? 0 }}</div>
<i class="fas fa-heartbeat card-icon"></i>
</div>
<div class="card card-danger">
<h3>Total Alpa</h3>
<div class="card-value">{{ $stats['Alpa'] ?? 0 }}</div>
<i class="fas fa-times-circle card-icon"></i>
</div> </div>
</div> </div>
<!-- Grafik Kehadiran Per Kategori --> {{-- Catatan logika Terlambat --}}
@if($statsByKategori->count() > 0) @if($totalTerlambat > 0)
<div class="content-box" style="margin-bottom: 14px;"> <div class="ds-terlambat-note">
<h3 style="margin: 0 0 20px 0; color: var(--primary-color);"> <i class="fas fa-info-circle"></i>
<i class="fas fa-chart-bar"></i> Kehadiran Per Kategori <strong>{{ $totalTerlambat }}x Terlambat</strong> dihitung sebagai <strong>Hadir</strong> (bukan Alpa).
</h3> Total hadir efektif: <strong>{{ $totalHadirEfektif }}</strong> kali
<canvas id="chartKategori" style="max-height: 300px;"></canvas> ({{ $totalHadir }} hadir tepat waktu + {{ $totalTerlambat }} terlambat).
</div> </div>
@endif @endif
<!-- Grafik Tren 30 Hari --> {{-- KPI Cards --}}
<div class="ds-kpi-grid">
<div class="ds-kpi hadir">
<div class="ico"><i class="fas fa-check-circle"></i></div>
<div>
<div class="cnt">{{ $totalHadirEfektif }}</div>
<div class="lbl">Hadir Efektif</div>
@if($totalTerlambat > 0)
<div style="font-size:0.68rem; color:#94a3b8;">{{ $totalHadir }}+{{ $totalTerlambat }}tl</div>
@endif
</div>
</div>
<div class="ds-kpi terlambat">
<div class="ico"><i class="fas fa-clock"></i></div>
<div><div class="cnt">{{ $totalTerlambat }}</div><div class="lbl">Terlambat</div></div>
</div>
<div class="ds-kpi izin">
<div class="ico"><i class="fas fa-envelope"></i></div>
<div><div class="cnt">{{ $totalIzin }}</div><div class="lbl">Izin</div></div>
</div>
<div class="ds-kpi sakit">
<div class="ico"><i class="fas fa-heartbeat"></i></div>
<div><div class="cnt">{{ $totalSakit }}</div><div class="lbl">Sakit</div></div>
</div>
<div class="ds-kpi alpa">
<div class="ico"><i class="fas fa-times-circle"></i></div>
<div><div class="cnt">{{ $totalAlpa }}</div><div class="lbl">Alpa</div></div>
</div>
</div>
{{-- Tren 30 Hari --}}
@if($riwayat30Hari->count() > 0) @if($riwayat30Hari->count() > 0)
<div class="content-box" style="margin-bottom: 14px;"> <div class="ds-chart-box">
<h3 style="margin: 0 0 20px 0; color: var(--primary-color);"> <h4><i class="fas fa-chart-line"></i> Tren Kehadiran 30 Hari Terakhir
<i class="fas fa-chart-line"></i> Tren Kehadiran 30 Hari Terakhir <span style="font-size:0.76rem; font-weight:400; color:#94a3b8; margin-left:4px;">
</h3> (Hadir + Terlambat)
<canvas id="chartTren" style="max-height: 250px;"></canvas> </span>
</h4>
<canvas id="chartTren" style="max-height:220px;"></canvas>
</div> </div>
@endif @endif
<!-- Kehadiran Per Kelas Santri --> {{-- ── RIWAYAT LENGKAP (Tabbed per Kategori) ──────────────────────────────── --}}
@if($statsByKelasSantri->count() > 0) <div class="ds-riwayat-box">
<div class="content-box" style="margin-bottom: 14px;"> <div class="ds-riwayat-head">
<h3 style="margin: 0 0 20px 0; color: var(--primary-color);"> <h4><i class="fas fa-list-alt" style="color:var(--primary-color);"></i> Riwayat Lengkap per Kategori</h4>
<i class="fas fa-layer-group"></i> Kehadiran Per Kelas
</h3> @if($kategoriList->count() > 0)
<div class="table-wrapper"> {{-- Tab list --}}
<table class="data-table"> <div class="ds-tabs" role="tablist">
@foreach($kategoriList as $kat)
@php
$tabParams = array_merge(request()->query(), [
'tab_kat' => $kat->kategori_id,
'per_page' => $perPage,
'page' => 1,
]);
$isActive = ($activeKategori == $kat->kategori_id);
$pctKat = $kat->total > 0 ? round($kat->hadir_efektif / $kat->total * 100) : 0;
@endphp
<a href="{{ route('admin.riwayat-kegiatan.detail-santri', $santri->id_santri) }}?{{ http_build_query($tabParams) }}"
class="ds-tab {{ $isActive ? 'active' : '' }}"
role="tab">
<i class="fas fa-tag" style="font-size:0.72rem;"></i>
{{ $kat->nama_kategori }}
<span class="tab-cnt">{{ $kat->total }}</span>
@if($kat->hadir_efektif > 0)
<span class="tab-hadir" title="Hadir efektif">{{ $pctKat }}%</span>
@endif
</a>
@endforeach
</div>
@endif
</div>
@if($riwayats->count() > 0)
{{-- Toolbar: info + per-page --}}
<div class="ds-toolbar">
<div class="ds-toolbar-left">
@if(!$showAll)
Menampilkan
<strong>{{ $riwayats->firstItem() }}{{ $riwayats->lastItem() }}</strong>
dari <strong>{{ $riwayats->total() }}</strong> riwayat
@else
Menampilkan <strong>semua {{ $riwayats->total() }}</strong> riwayat
@endif
@php $activeKat = $kategoriList->firstWhere('kategori_id', $activeKategori); @endphp
@if($activeKat)
&mdash; <span style="color:var(--primary-color); font-weight:600;">{{ $activeKat->nama_kategori }}</span>
@endif
</div>
<div class="ds-toolbar-right">
Tampilkan:
<div class="ds-perpage-group">
@foreach([15, 50, 100] as $pp)
@php $ppParams = array_merge(request()->query(), ['per_page' => $pp, 'page' => 1]); @endphp
<a href="{{ route('admin.riwayat-kegiatan.detail-santri', $santri->id_santri) }}?{{ http_build_query($ppParams) }}"
class="ds-pp-btn {{ (!$showAll && $perPage == $pp) ? 'active' : '' }}">
{{ $pp }}
</a>
@endforeach
{{-- Semua --}}
@php $allParams = array_merge(request()->query(), ['per_page' => 'all', 'page' => 1]); @endphp
<a href="{{ route('admin.riwayat-kegiatan.detail-santri', $santri->id_santri) }}?{{ http_build_query($allParams) }}"
class="ds-pp-btn {{ $showAll ? 'active' : '' }}"
title="Tampilkan semua data sekaligus (bisa lambat jika data banyak)">
Semua
</a>
</div>
</div>
</div>
{{-- Table --}}
<div class="ds-table-wrap">
<table class="ds-table">
<thead> <thead>
<tr> <tr>
<th>Kelompok</th> <th style="width:50px;">No</th>
<th>Kelas</th> <th style="width:110px;">Tanggal</th>
<th style="width: 120px; text-align: center;">Total Kegiatan</th> <th>Nama Kegiatan</th>
<th style="width: 120px; text-align: center;">Hadir</th> <th style="width:115px; text-align:center;">Status</th>
<th style="width: 150px; text-align: center;">Persentase</th> <th style="width:90px; text-align:center;">Waktu</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach($statsByKelasSantri as $stat) @foreach($riwayats as $idx => $riwayat)
<tr> <tr>
<td><span class="badge badge-info">{{ $stat['kelompok'] }}</span></td> <td style="color:#94a3b8; font-size:0.78rem;">{{ $riwayats->firstItem() + $idx }}</td>
<td><strong>{{ $stat['kelas'] }}</strong></td> <td style="font-size:0.81rem; color:#64748b;">
<td class="text-center">{{ $stat['total'] }}</td> {{ $riwayat->tanggal->format('d/m/Y') }}
<td class="text-center"><strong>{{ $stat['hadir'] }}</strong></td> <div style="font-size:0.71rem; color:#94a3b8;">
<td class="text-center"> {{ $riwayat->tanggal->locale('id')->isoFormat('ddd') }}
<div style="display: flex; align-items: center; gap: 10px;">
<div style="flex: 1; background: #e9ecef; border-radius: 10px; height: 20px; overflow: hidden;">
<div style="background:
@if($stat['persen'] >= 85) var(--success-color)
@elseif($stat['persen'] >= 70) var(--warning-color)
@else var(--danger-color)
@endif;
height: 100%; width: {{ $stat['persen'] }}%;
transition: width 0.3s ease;">
</div> </div>
</td>
<td>
<strong style="font-size:0.85rem;">{{ $riwayat->kegiatan->nama_kegiatan }}</strong>
<div style="font-size:0.74rem; color:#94a3b8; margin-top:1px;">
<i class="fas fa-clock"></i>
{{ date('H:i', strtotime($riwayat->kegiatan->waktu_mulai)) }}{{ date('H:i', strtotime($riwayat->kegiatan->waktu_selesai)) }}
</div> </div>
<strong style="min-width: 45px;">{{ $stat['persen'] }}%</strong> </td>
</div> <td style="text-align:center;">
@if(method_exists($riwayat, 'getStatusBadgeAttribute') || isset($riwayat->status_badge))
{!! $riwayat->status_badge !!}
@else
@php $st = $riwayat->status; @endphp
<span class="s-{{ strtolower($st) }}">{{ $st }}</span>
@endif
</td>
<td style="text-align:center; font-size:0.81rem; color:#64748b;">
{{ $riwayat->waktu_absen ? date('H:i', strtotime($riwayat->waktu_absen)) : '' }}
</td> </td>
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
@endif
<!-- Riwayat Lengkap --> {{-- Pagination (disembunyikan jika mode Semua) --}}
<div class="content-box"> @if(!$showAll && $riwayats->lastPage() > 1)
<h3 style="margin: 0 0 20px 0; color: var(--primary-color);"> <div style="padding:12px 16px;">
<i class="fas fa-list"></i> Riwayat Lengkap
</h3>
@if($riwayats->count() > 0)
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">No</th>
<th style="width: 120px;">Tanggal</th>
<th>Kegiatan</th>
<th style="width: 150px;">Kategori</th>
<th style="width: 130px; text-align: center;">Status</th>
<th style="width: 100px;">Waktu</th>
</tr>
</thead>
<tbody>
@foreach($riwayats as $index => $riwayat)
<tr>
<td>{{ $riwayats->firstItem() + $index }}</td>
<td>{{ $riwayat->tanggal->format('d/m/Y') }}</td>
<td>{{ $riwayat->kegiatan->nama_kegiatan }}</td>
<td>{{ $riwayat->kegiatan->kategori->nama_kategori }}</td>
<td class="text-center">{!! $riwayat->status_badge !!}</td>
<td>{{ $riwayat->waktu_absen ? date('H:i', strtotime($riwayat->waktu_absen)) : '-' }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div style="margin-top: 14px;">
{{ $riwayats->links() }} {{ $riwayats->links() }}
</div> </div>
@else @elseif($showAll)
<div class="empty-state"> <div style="padding:10px 16px; font-size:0.78rem; color:#94a3b8; background:#fafafa; border-top:1px solid #f1f5f9;">
<i class="fas fa-info-circle"></i> Semua <strong>{{ $riwayats->total() }}</strong> data ditampilkan.
&nbsp;
@php $backPaged = array_merge(request()->query(), ['per_page' => 15, 'page' => 1]); @endphp
<a href="{{ route('admin.riwayat-kegiatan.detail-santri', $santri->id_santri) }}?{{ http_build_query($backPaged) }}"
style="color:var(--primary-color);">Kembali ke paginasi</a>
</div>
@endif
@elseif($kategoriList->count() > 0)
<div class="ds-empty">
<i class="fas fa-inbox"></i> <i class="fas fa-inbox"></i>
<h3>Belum Ada Riwayat</h3> <p>Belum ada riwayat untuk kategori ini.</p>
<p>Santri ini belum memiliki riwayat kehadiran.</p> </div>
@else
<div class="ds-empty">
<i class="fas fa-inbox"></i>
<p>Santri ini belum memiliki riwayat kehadiran apapun.</p>
</div> </div>
@endif @endif
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> {{-- ── CHART JS ─────────────────────────────────────────────────────────────── --}}
@if($statsByKategori->count() > 0)
<script>
// Chart Kehadiran Per Kategori
const ctxKategori = document.getElementById('chartKategori');
new Chart(ctxKategori, {
type: 'bar',
data: {
labels: {!! json_encode($statsByKategori->pluck('nama_kategori')) !!},
datasets: [{
label: 'Hadir',
data: {!! json_encode($statsByKategori->pluck('hadir')) !!},
backgroundColor: '#6FBA9D',
borderWidth: 0
}, {
label: 'Total Kegiatan',
data: {!! json_encode($statsByKategori->pluck('total')) !!},
backgroundColor: '#E0F0EC',
borderWidth: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: { position: 'bottom' }
},
scales: {
y: { beginAtZero: true, ticks: { stepSize: 1 } }
}
}
});
</script>
@endif
@if($riwayat30Hari->count() > 0) @if($riwayat30Hari->count() > 0)
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script> <script>
// Chart Tren 30 Hari (function() {
const ctxTren = document.getElementById('chartTren'); var ctx = document.getElementById('chartTren');
new Chart(ctxTren, { if (!ctx) return;
var labels = {!! json_encode($riwayat30Hari->pluck('tanggal')->map(fn($d) => date('d/m', strtotime($d)))) !!};
var hadir = {!! json_encode($riwayat30Hari->pluck('hadir')) !!};
var total = {!! json_encode($riwayat30Hari->pluck('total')) !!};
new Chart(ctx, {
type: 'line', type: 'line',
data: { data: {
labels: {!! json_encode($riwayat30Hari->pluck('tanggal')->map(fn($d) => date('d/m', strtotime($d)))) !!}, labels: labels,
datasets: [{ datasets: [
label: 'Hadir', {
data: {!! json_encode($riwayat30Hari->pluck('hadir')) !!}, label: 'Hadir (termasuk terlambat)',
data: hadir,
borderColor: '#6FBA9D', borderColor: '#6FBA9D',
backgroundColor: 'rgba(111, 186, 157, 0.1)', backgroundColor: 'rgba(111,186,157,0.12)',
tension: 0.4, tension: 0.4,
fill: true fill: true,
}] pointRadius: 4,
pointBackgroundColor: '#6FBA9D',
},
{
label: 'Total Kegiatan',
data: total,
borderColor: '#cbd5e1',
backgroundColor: 'transparent',
borderDash: [5, 5],
tension: 0.4,
fill: false,
pointRadius: 0,
}
]
}, },
options: { options: {
responsive: true, responsive: true,
maintainAspectRatio: true, maintainAspectRatio: true,
interaction: { mode: 'index', intersect: false },
plugins: { plugins: {
legend: { display: false } legend: { position: 'bottom', labels: { boxWidth: 12, font: { size: 11 } } }
}, },
scales: { scales: {
y: { beginAtZero: true, ticks: { stepSize: 1 } } y: { beginAtZero: true, ticks: { stepSize: 1 }, grid: { color: '#f1f5f9' } },
x: { grid: { display: false }, ticks: { font: { size: 10 } } }
} }
} }
}); });
})();
</script> </script>
@endif @endif
@endsection @endsection

View File

@ -3,292 +3,459 @@
@section('content') @section('content')
<style> <style>
.day-group { margin-bottom: 18px; background: #fff; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); overflow: hidden; } /* ============================================================
.day-header { background: linear-gradient(135deg, #f0fdf4 0%, #E8F7F2 100%); padding: 13px 18px; display: flex; justify-content: space-between; align-items: center; border-bottom: 2px solid #E8F7F2; cursor: pointer; transition: background 0.2s; user-select: none; } RIWAYAT KEGIATAN INDEX (v3)
.day-header:hover{ background: linear-gradient(135deg, #E8F7F2 0%, #d1f2e8 100%); } ============================================================ */
.day-title { font-weight: 700; font-size: 1rem; color: var(--primary-dark); display: flex; align-items: center; gap: 8px; }
.day-title i { color: var(--primary-color); }
.day-meta { display: flex; gap: 10px; align-items: center; }
.day-count { background: var(--primary-color); color: #fff; padding: 3px 10px; border-radius: 20px; font-size: 0.78rem; font-weight: 600; }
.toggle-icon { transition: transform 0.3s; font-size: 0.85rem; color: #94a3b8; }
.toggle-icon.collapsed { transform: rotate(-90deg); }
.day-body { overflow: hidden; }
.day-body table { width: 100%; border-collapse: collapse; }
.day-body thead { background: #f8fafc; }
.day-body th { padding: 9px 14px; text-align: left; font-weight: 600; font-size: 0.8rem; color: #64748b; border-bottom: 1px solid #e2e8f0; }
.day-body td { padding: 10px 14px; font-size: 0.85rem; border-bottom: 1px solid #f1f5f9; vertical-align: middle; }
.day-body tbody tr:last-child td { border-bottom: none; }
.day-body tbody tr:hover { background: #f8fafc; }
.stat-chips { display: flex; gap: 5px; flex-wrap: wrap; } .rw-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:16px; flex-wrap:wrap; gap:10px; }
.chip { padding: 2px 8px; border-radius: 10px; font-size: 0.74rem; font-weight: 600; display: inline-flex; align-items: center; gap: 3px; } .rw-header h2 { margin:0; font-size:1.35rem; color:var(--primary-dark); display:flex; align-items:center; gap:9px; }
.chip-hadir { background: #D1FAE5; color: #065F46; } .rw-header h2 i { color:var(--primary-color); }
.chip-terlambat { background: #FFF3E0; color: #E65100; }
.chip-izin { background: #FEF3C7; color: #92400E; }
.chip-sakit { background: #DBEAFE; color: #1E40AF; }
.chip-alpa { background: #FEE2E2; color: #991B1B; }
.chip-pulang { background: #F3E8FF; color: #6B21A8; }
.chip-none { background: #F1F5F9; color: #94a3b8; }
.kelas-tag { display: inline-block; background: #E8F7F2; color: var(--primary-dark); padding: 2px 7px; border-radius: 8px; font-size: 0.74rem; margin: 2px 2px 0 0; }
.umum-tag { display: inline-block; background: #F1F5F9; color: #64748b; padding: 2px 7px; border-radius: 8px; font-size: 0.74rem; }
.btn-detail { padding: 5px 12px; background: var(--primary-color); color: #fff; border: none; border-radius: 6px; font-size: 0.8rem; text-decoration: none; display: inline-flex; align-items: center; gap: 4px; transition: all 0.2s; }
.btn-detail:hover { background: #059669; color: #fff; transform: translateY(-1px); }
.filter-box { background: #fff; padding: 14px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); margin-bottom: 14px; } /* Filter */
.filter-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 11px; } .rw-filter { background:#fff; border-radius:12px; box-shadow:0 2px 10px rgba(0,0,0,.06); padding:14px 18px; margin-bottom:14px; }
.form-group { margin: 0; } .rw-mode-tabs { display:flex; gap:6px; margin-bottom:14px; flex-wrap:wrap; }
.form-group label { display: block; font-size: 0.85rem; margin-bottom: 5px; color: var(--text-light); font-weight: 500; } .rw-tab { padding:7px 18px; border-radius:22px; border:1.5px solid #e2e8f0; background:#fff;
.form-control { width: 100%; padding: 8px 12px; border: 1px solid #e2e8f0; border-radius: 8px; font-size: 0.85rem; } font-size:0.82rem; font-weight:600; cursor:pointer; text-decoration:none;
.btn-filter { background: var(--primary-color); color: #fff; border: none; padding: 9px 16px; border-radius: 8px; cursor: pointer; font-size: 0.85rem; display: inline-flex; align-items: center; gap: 6px; transition: all 0.2s; } color:#64748b; transition:all .18s; display:inline-flex; align-items:center; gap:6px; }
.btn-filter:hover { background: #059669; transform: translateY(-1px); } .rw-tab:hover { border-color:var(--primary-color); color:var(--primary-color); background:#f0fdf4; }
.btn-reset { background: #6B7280; color: #fff; border: none; padding: 9px 12px; border-radius: 8px; cursor: pointer; font-size: 0.85rem; display: inline-flex; align-items: center; gap: 6px; text-decoration: none; } .rw-tab.active { background:var(--primary-color); color:#fff; border-color:var(--primary-color); box-shadow:0 2px 8px rgba(16,185,129,.25); }
.btn-reset:hover { background: #4B5563; } .rw-filter-row { display:flex; gap:10px; align-items:flex-end; flex-wrap:wrap; }
.rw-fg { display:flex; flex-direction:column; gap:4px; }
.rw-fg label { font-size:0.78rem; font-weight:600; color:#64748b; }
.rw-fg .form-control { padding:7px 11px; font-size:0.84rem; border:1.5px solid #e2e8f0; border-radius:8px; }
.rw-fg .form-control:focus { border-color:var(--primary-color); outline:none; }
.btn-rw-apply { background:var(--primary-color); color:#fff; border:none; padding:8px 18px; border-radius:8px;
font-size:0.84rem; font-weight:600; cursor:pointer; display:inline-flex; align-items:center; gap:6px;
align-self:flex-end; white-space:nowrap; }
.btn-rw-apply:hover { background:#059669; }
.btn-rw-reset { background:#f1f5f9; color:#64748b; border:1.5px solid #e2e8f0; padding:8px 12px; border-radius:8px;
font-size:0.84rem; font-weight:600; text-decoration:none;
display:inline-flex; align-items:center; gap:6px; align-self:flex-end; }
.btn-rw-reset:hover { background:#e2e8f0; }
.period-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; } /* Periode label */
.period-tab { padding: 5px 14px; border-radius: 20px; border: 1px solid #e2e8f0; background: #fff; font-size: 0.82rem; cursor: pointer; text-decoration: none; color: var(--text-dark); transition: all 0.2s; display: inline-flex; align-items: center; gap: 5px; } .rw-periode { background:linear-gradient(90deg,#f0fdf4,#e8f7f2); border-left:3px solid var(--primary-color);
.period-tab:hover, .period-tab.active { background: var(--primary-color); color: #fff; border-color: var(--primary-color); } border-radius:8px; padding:9px 14px; margin-bottom:14px; font-size:0.84rem; color:#374151;
display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.rw-periode i { color:var(--primary-color); }
.periode-info { font-size: 0.82rem; color: var(--text-light); margin-bottom: 12px; padding: 8px 12px; background: #f0fdf4; border-radius: 8px; border-left: 3px solid var(--primary-color); } /* KPI strip */
.periode-info strong { color: var(--primary-color); } .rw-kpi-strip { display:grid; grid-template-columns:repeat(auto-fit,minmax(105px,1fr)); gap:8px; margin-bottom:14px; }
.rw-kpi { background:#fff; border-radius:10px; padding:11px 14px; box-shadow:0 2px 8px rgba(0,0,0,.05); text-align:center; }
.rw-kpi-val { font-size:1.45rem; font-weight:800; line-height:1; }
.rw-kpi-lbl { font-size:0.73rem; color:#94a3b8; margin-top:4px; font-weight:500; }
.rw-kpi-sub { font-size:0.68rem; color:#cbd5e1; margin-top:2px; }
.empty-state { text-align: center; padding: 44px 14px; color: var(--text-light); background: #fff; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); } /* Per-date block */
.empty-state i { font-size: 3.5rem; margin-bottom: 14px; opacity: 0.3; display: block; } .rw-date-block { margin-bottom:20px; }
.empty-state h3 { margin: 0 0 6px; } .rw-date-header { display:flex; align-items:center; gap:10px; padding:10px 16px; flex-wrap:wrap;
background:linear-gradient(90deg,var(--primary-color),#0ea574);
border-radius:10px 10px 0 0; color:#fff; }
.rw-date-today { background:linear-gradient(90deg,#0ea574,#059669); }
.dh-date { font-size:1rem; font-weight:700; }
.dh-hari { background:rgba(255,255,255,.22); padding:2px 10px; border-radius:12px; font-size:0.78rem; font-weight:600; }
.dh-count { margin-left:auto; font-size:0.78rem; background:rgba(255,255,255,.2); padding:3px 10px; border-radius:12px; }
@media (max-width: 768px) { /* Table */
.day-header { flex-direction: column; align-items: flex-start; gap: 6px; } .rw-tbl-wrap { background:#fff; border-radius:0 0 10px 10px; box-shadow:0 3px 12px rgba(0,0,0,.07); overflow-x:auto; }
.day-body th:nth-child(3), .day-body td:nth-child(3), .rw-table { width:100%; border-collapse:collapse; min-width:680px; }
.day-body th:nth-child(4), .day-body td:nth-child(4) { display: none; } .rw-table thead th { padding:9px 13px; text-align:left; font-size:0.78rem; font-weight:700;
color:#475569; background:#f8fafc; border-bottom:1.5px solid #e2e8f0; white-space:nowrap; }
.rw-table tbody td { padding:9px 13px; font-size:0.83rem; border-bottom:1px solid #f8fafc; vertical-align:middle; }
.rw-table tbody tr:last-child td { border-bottom:none; }
.rw-table tbody tr:hover { background:#f8fafc; }
.rw-table tfoot td { padding:8px 13px; }
/* Tags */
.rw-kelas-tag { background:#e8f7f2; color:var(--primary-dark); padding:2px 7px; border-radius:6px; font-size:.72rem; font-weight:600; margin-right:2px; display:inline-block; }
.rw-umum-tag { background:#f1f5f9; color:#64748b; padding:2px 7px; border-radius:6px; font-size:.72rem; font-weight:600; display:inline-block; }
.rw-kat-tag { background:#dbeafe; color:#1e40af; padding:2px 7px; border-radius:6px; font-size:.72rem; font-weight:600; display:inline-block; }
/* Mini progress */
.rw-mini-prog { height:6px; background:#f1f5f9; border-radius:3px; overflow:hidden; display:flex; min-width:70px; }
/* Button table */
.btn-tbl-detail { padding:5px 11px; background:var(--primary-color); color:#fff; border:none; border-radius:6px;
font-size:0.76rem; font-weight:600; text-decoration:none; display:inline-flex; align-items:center; gap:4px; white-space:nowrap; }
.btn-tbl-detail:hover { background:#059669; color:#fff; }
/* Cards (hari_ini) */
.rw-card { background:#fff; border-radius:12px; box-shadow:0 2px 10px rgba(0,0,0,.06); border:1px solid #f0f0f0; overflow:hidden; margin-bottom:10px; }
.rw-card:hover { box-shadow:0 4px 18px rgba(0,0,0,.1); }
.rw-card-head { display:flex; align-items:flex-start; justify-content:space-between; gap:12px; padding:14px 18px 10px; border-bottom:1px solid #f1f5f9; flex-wrap:wrap; }
.rw-card-title { font-size:1rem; font-weight:700; color:var(--primary-dark); margin:0 0 5px; display:flex; align-items:center; gap:8px; }
.rw-card-meta { display:flex; gap:10px; flex-wrap:wrap; font-size:.8rem; color:#64748b; align-items:center; }
.rw-card-meta span{ display:inline-flex; align-items:center; gap:4px; }
.rw-status { padding:4px 12px; border-radius:20px; font-size:.76rem; font-weight:700; white-space:nowrap; flex-shrink:0; display:inline-flex; align-items:center; gap:5px; }
.rw-status.belum { background:#f1f5f9; color:#64748b; }
.rw-status.selesai{ background:#d1fae5; color:#065f46; }
.rw-status.brlgs { background:#fef9c3; color:#854d0e; }
.rw-card-body { padding:10px 18px 14px; }
.rw-stats-row { display:flex; gap:6px; flex-wrap:wrap; align-items:center; margin-bottom:10px; }
.rw-chip { padding:4px 10px; border-radius:10px; font-size:.76rem; font-weight:700; display:inline-flex; align-items:center; gap:4px; }
.rw-chip.hadir { background:#d1fae5; color:#065f46; }
.rw-chip.terlambat{ background:#fff3e0; color:#e65100; }
.rw-chip.izin { background:#fef3c7; color:#92400e; }
.rw-chip.sakit { background:#dbeafe; color:#1e40af; }
.rw-chip.alpa { background:#fee2e2; color:#991b1b; }
.rw-chip.pulang { background:#f3e8ff; color:#6b21a8; }
.rw-chip.none { background:#f1f5f9; color:#94a3b8; }
.rw-progress-wrap { height:8px; background:#f1f5f9; border-radius:4px; overflow:hidden; display:flex; margin-bottom:6px; }
.rw-prog-hadir { background:#22c55e; }
.rw-prog-terlambat{ background:#FF9800; }
.rw-prog-izin { background:#f59e0b; }
.rw-prog-sakit { background:#3b82f6; }
.rw-prog-alpa { background:#ef4444; }
.rw-prog-pulang { background:#a855f7; }
.rw-prog-belum { background:#e2e8f0; }
.rw-card-foot { display:flex; align-items:center; justify-content:space-between; padding:8px 18px; background:#fafafa; border-top:1px solid #f1f5f9; flex-wrap:wrap; gap:8px; }
.rw-total-txt { font-size:.78rem; color:#94a3b8; }
.rw-total-txt strong { color:#374151; }
.btn-rw-detail { padding:6px 16px; background:var(--primary-color); color:#fff; border:none; border-radius:7px; font-size:.82rem; font-weight:600; text-decoration:none; display:inline-flex; align-items:center; gap:5px; }
.btn-rw-detail:hover { background:#059669; color:#fff; }
/* Empty */
.rw-empty { text-align:center; padding:48px 20px; background:#fff; border-radius:12px; box-shadow:0 2px 10px rgba(0,0,0,.06); }
.rw-empty i { font-size:3rem; color:#cbd5e1; display:block; margin-bottom:12px; }
.rw-empty h3 { margin:0 0 6px; color:var(--primary-dark); }
.rw-empty p { margin:0; color:var(--text-light); font-size:.88rem; }
@media(max-width:640px) {
.rw-filter-row { flex-direction:column; }
.rw-fg { width:100%; }
.rw-fg .form-control { width:100%; }
.btn-rw-apply,.btn-rw-reset { width:100%; justify-content:center; }
.rw-kpi-strip { grid-template-columns:repeat(3,1fr); }
.dh-count { display:none; }
} }
</style> </style>
@php @php
// Default: minggu ini $mode = $mode ?? 'hari_ini';
$defaultDari = now()->startOfWeek(\Carbon\Carbon::MONDAY)->format('Y-m-d'); $dari = $dari ?? now()->format('Y-m-d');
$defaultSampai = now()->endOfWeek(\Carbon\Carbon::SUNDAY)->format('Y-m-d'); $sampai = $sampai ?? now()->format('Y-m-d');
$tanggal = $tanggal ?? now()->format('Y-m-d');
$kategoriId = $kategoriId ?? '';
$passParams = ['mode' => $mode, 'dari' => $dari, 'sampai' => $sampai, 'tanggal' => $tanggal];
$activeDari = request('tanggal_dari', $defaultDari); $totalAbsensi = $summary['total_absensi'] ?? 0;
$activeSampai = request('tanggal_sampai', $defaultSampai); $totalHadir = $summary['hadir'] ?? 0;
$activeKategori = request('kategori_id', ''); $pctHadirGlbl = $totalAbsensi > 0 ? round($totalHadir / $totalAbsensi * 100, 1) : 0;
$activeBulan = request('bulan', '');
// Label periode
if ($activeBulan) {
$periodeLabel = 'Bulan ' . \Carbon\Carbon::parse($activeBulan . '-01')->locale('id')->isoFormat('MMMM Y');
} else {
$periodeLabel = \Carbon\Carbon::parse($activeDari)->locale('id')->isoFormat('D MMM Y')
. ' '
. \Carbon\Carbon::parse($activeSampai)->locale('id')->isoFormat('D MMM Y');
}
// Cek shortcut aktif
$isMingguIni = !$activeBulan
&& $activeDari == $defaultDari
&& $activeSampai == $defaultSampai;
$isBulanIni = !$activeBulan
&& $activeDari == now()->startOfMonth()->format('Y-m-d')
&& $activeSampai == now()->endOfMonth()->format('Y-m-d');
@endphp @endphp
<div class="page-header"> {{-- PAGE HEADER --}}
<h2><i class="fas fa-history"></i> Riwayat Kegiatan & Absensi</h2> <div class="rw-header">
<h2><i class="fas fa-history"></i> Riwayat Kegiatan &amp; Absensi</h2>
</div> </div>
@if(session('success')) {{-- FILTER --}}
<div class="alert alert-success"> <div class="rw-filter">
<i class="fas fa-check-circle"></i> {{ session('success') }} <div class="rw-mode-tabs">
</div> <a href="{{ route('admin.riwayat-kegiatan.index', ['mode'=>'hari_ini','tanggal'=>$tanggal]) }}"
@endif class="rw-tab {{ $mode==='hari_ini'?'active':'' }}">
<i class="fas fa-calendar-day"></i> Hari Ini
{{-- Filter --}} </a>
<div class="filter-box"> <a href="{{ route('admin.riwayat-kegiatan.index', ['mode'=>'minggu_ini']) }}"
class="rw-tab {{ $mode==='minggu_ini'?'active':'' }}">
{{-- Shortcut tabs --}}
<div class="period-tabs">
<a href="{{ route('admin.riwayat-kegiatan.index', ['tanggal_dari' => $defaultDari, 'tanggal_sampai' => $defaultSampai, 'kategori_id' => $activeKategori]) }}"
class="period-tab {{ $isMingguIni ? 'active' : '' }}">
<i class="fas fa-calendar-week"></i> Minggu Ini <i class="fas fa-calendar-week"></i> Minggu Ini
</a> </a>
<a href="{{ route('admin.riwayat-kegiatan.index', ['tanggal_dari' => now()->startOfMonth()->format('Y-m-d'), 'tanggal_sampai' => now()->endOfMonth()->format('Y-m-d'), 'kategori_id' => $activeKategori]) }}" <a href="{{ route('admin.riwayat-kegiatan.index', ['mode'=>'custom','dari'=>$dari,'sampai'=>$sampai]) }}"
class="period-tab {{ $isBulanIni ? 'active' : '' }}"> class="rw-tab {{ $mode==='custom'?'active':'' }}">
<i class="fas fa-calendar-alt"></i> Bulan Ini <i class="fas fa-sliders-h"></i> Rentang Tanggal
</a>
<a href="{{ route('admin.riwayat-kegiatan.index') }}"
class="period-tab {{ !$isMingguIni && !$isBulanIni ? 'active' : '' }}"
style="{{ !$isMingguIni && !$isBulanIni ? '' : 'display:none' }}">
<i class="fas fa-filter"></i> Custom
</a> </a>
</div> </div>
<form method="GET"> <form method="GET" action="{{ route('admin.riwayat-kegiatan.index') }}">
<div class="filter-grid">
<div class="form-group"> @if($mode === 'hari_ini')
<label for="kategori_id">Kategori</label> <input type="hidden" name="mode" value="hari_ini">
<select name="kategori_id" id="kategori_id" class="form-control"> <div class="rw-filter-row">
<option value="">-- Semua Kategori --</option> <div class="rw-fg">
<label><i class="fas fa-calendar-alt"></i> Tanggal</label>
<input type="date" name="tanggal" class="form-control" value="{{ $tanggal }}" style="max-width:180px;">
</div>
<div class="rw-fg">
<label><i class="fas fa-tag"></i> Kategori</label>
<select name="kategori_id" class="form-control" style="max-width:200px;">
<option value="">Semua Kategori</option>
@foreach($kategoris as $k) @foreach($kategoris as $k)
<option value="{{ $k->kategori_id }}" {{ $activeKategori == $k->kategori_id ? 'selected' : '' }}> <option value="{{ $k->kategori_id }}" {{ $kategoriId==$k->kategori_id?'selected':'' }}>{{ $k->nama_kategori }}</option>
{{ $k->nama_kategori }}
</option>
@endforeach @endforeach
</select> </select>
</div> </div>
<div class="form-group"> <button type="submit" class="btn-rw-apply"><i class="fas fa-search"></i> Tampilkan</button>
<label for="tanggal_dari">Tanggal Dari</label> <a href="{{ route('admin.riwayat-kegiatan.index') }}" class="btn-rw-reset"><i class="fas fa-undo"></i> Reset</a>
<input type="date" name="tanggal_dari" id="tanggal_dari" class="form-control" value="{{ $activeDari }}">
</div> </div>
<div class="form-group">
<label for="tanggal_sampai">Tanggal Sampai</label> @elseif($mode === 'minggu_ini')
<input type="date" name="tanggal_sampai" id="tanggal_sampai" class="form-control" value="{{ $activeSampai }}"> <input type="hidden" name="mode" value="minggu_ini">
<div class="rw-filter-row">
<div class="rw-fg">
<label><i class="fas fa-tag"></i> Kategori</label>
<select name="kategori_id" class="form-control" style="max-width:200px;">
<option value="">Semua Kategori</option>
@foreach($kategoris as $k)
<option value="{{ $k->kategori_id }}" {{ $kategoriId==$k->kategori_id?'selected':'' }}>{{ $k->nama_kategori }}</option>
@endforeach
</select>
</div> </div>
<div class="form-group"> <button type="submit" class="btn-rw-apply"><i class="fas fa-search"></i> Tampilkan</button>
<label for="bulan">Atau Pilih Bulan</label> <a href="{{ route('admin.riwayat-kegiatan.index', ['mode'=>'minggu_ini']) }}" class="btn-rw-reset"><i class="fas fa-undo"></i> Reset</a>
<input type="month" name="bulan" id="bulan" class="form-control" value="{{ $activeBulan }}">
</div> </div>
<div style="display: flex; align-items: flex-end; gap: 10px;">
<button type="submit" class="btn-filter" style="flex: 1;"> @else
<i class="fas fa-filter"></i> Filter <input type="hidden" name="mode" value="custom">
</button> <div class="rw-filter-row">
<a href="{{ route('admin.riwayat-kegiatan.index') }}" class="btn-reset" title="Reset ke minggu ini"> <div class="rw-fg">
<i class="fas fa-undo"></i> <label><i class="fas fa-calendar-alt"></i> Dari Tanggal</label>
</a> <input type="date" name="dari" class="form-control" value="{{ $dari }}" style="max-width:180px;" required>
</div> </div>
<div class="rw-fg">
<label><i class="fas fa-calendar-alt"></i> Sampai Tanggal</label>
<input type="date" name="sampai" class="form-control" value="{{ $sampai }}" style="max-width:180px;" required>
</div> </div>
<div class="rw-fg">
<label><i class="fas fa-tag"></i> Kategori</label>
<select name="kategori_id" class="form-control" style="max-width:200px;">
<option value="">Semua Kategori</option>
@foreach($kategoris as $k)
<option value="{{ $k->kategori_id }}" {{ $kategoriId==$k->kategori_id?'selected':'' }}>{{ $k->nama_kategori }}</option>
@endforeach
</select>
</div>
<button type="submit" class="btn-rw-apply"><i class="fas fa-search"></i> Tampilkan</button>
<a href="{{ route('admin.riwayat-kegiatan.index', ['mode'=>'custom']) }}" class="btn-rw-reset"><i class="fas fa-undo"></i> Reset</a>
</div>
@endif
</form> </form>
</div> </div>
{{-- Info periode --}} {{-- PERIODE LABEL --}}
<p class="periode-info"> <div class="rw-periode">
<i class="fas fa-calendar-check"></i> Menampilkan kegiatan periode: <strong>{{ $periodeLabel }}</strong> <i class="fas fa-calendar-check"></i>
Menampilkan: <strong>{{ $periodeLabel }}</strong>
@if($mode !== 'hari_ini' && ($summary['jumlah_hari'] ?? 0) > 0)
<span style="color:#94a3b8;">·</span>
<strong style="color:var(--primary-color);">{{ $summary['jumlah_hari'] }}</strong> hari aktif
<span style="color:#94a3b8;">·</span>
<strong style="color:var(--primary-color);">{{ $summary['jumlah_kegiatan'] }}</strong> sesi
@endif
</div>
{{-- KPI STRIP --}}
@if($totalAbsensi > 0)
<div class="rw-kpi-strip">
<div class="rw-kpi">
<div class="rw-kpi-val" style="color:#065f46;">{{ $summary['hadir'] }}</div>
<div class="rw-kpi-lbl"><i class="fas fa-check" style="color:#22c55e;"></i> Hadir Efektif</div>
@if($summary['terlambat'] > 0)
<div class="rw-kpi-sub">+{{ $summary['terlambat'] }} terlambat</div>
@endif
</div>
<div class="rw-kpi">
<div class="rw-kpi-val" style="color:#e65100;">{{ $summary['terlambat'] }}</div>
<div class="rw-kpi-lbl"><i class="fas fa-clock" style="color:#FF9800;"></i> Terlambat</div>
</div>
<div class="rw-kpi">
<div class="rw-kpi-val" style="color:#92400e;">{{ $summary['izin'] }}</div>
<div class="rw-kpi-lbl"><i class="fas fa-envelope" style="color:#f59e0b;"></i> Izin</div>
</div>
<div class="rw-kpi">
<div class="rw-kpi-val" style="color:#1e40af;">{{ $summary['sakit'] }}</div>
<div class="rw-kpi-lbl"><i class="fas fa-heartbeat" style="color:#3b82f6;"></i> Sakit</div>
</div>
<div class="rw-kpi">
<div class="rw-kpi-val" style="color:#991b1b;">{{ $summary['alpa'] }}</div>
<div class="rw-kpi-lbl"><i class="fas fa-times-circle" style="color:#ef4444;"></i> Alpa</div>
</div>
<div class="rw-kpi" style="border-top:2px solid var(--primary-color);">
<div class="rw-kpi-val" style="color:{{ $pctHadirGlbl>=85?'#059669':($pctHadirGlbl>=70?'#d97706':'#dc2626') }};">{{ $pctHadirGlbl }}%</div>
<div class="rw-kpi-lbl"><i class="fas fa-chart-pie" style="color:var(--primary-color);"></i> Rata-rata</div>
<div class="rw-kpi-sub">dari {{ $totalAbsensi }} tercatat
@if($mode !== 'hari_ini' && ($summary['jumlah_kegiatan']??0) > 0)
· {{ $summary['jumlah_kegiatan'] }} sesi
@endif
</div>
</div>
</div>
@endif
{{-- ════════════════════════════════════════════════════
MODE HARI INI Cards
════════════════════════════════════════════════════ --}}
@if($mode === 'hari_ini')
@if($kegiatans && $kegiatans->count() > 0)
@foreach($kegiatans as $kegiatan)
@include('admin.kegiatan.riwayat._card', ['kegiatan' => $kegiatan, 'passParams' => $passParams])
@endforeach
<div style="margin-top:16px;">{!! $kegiatans->appends(request()->query())->links('pagination::simple-bootstrap-4') !!}</div>
@else
<div class="rw-empty">
<i class="fas fa-calendar-times"></i>
<h3>Tidak Ada Kegiatan</h3>
<p>Tidak ada kegiatan pada <strong>{{ $periodeLabel }}</strong>.</p>
<p style="margin-top:8px; font-size:.82rem;">
Coba tanggal lain atau lihat <a href="{{ route('admin.riwayat-kegiatan.index', ['mode'=>'minggu_ini']) }}" style="color:var(--primary-color);">riwayat minggu ini</a>.
</p> </p>
</div>
@endif
@if($kegiatans->count() > 0) {{-- ════════════════════════════════════════════════════
MODE MULTI-HARI Tabel per Tanggal
════════════════════════════════════════════════════ --}}
@else
@if($kegiatanPerTanggal && $kegiatanPerTanggal->count() > 0)
@foreach($kegiatanPerTanggal as $tgl => $items)
@php @php
$hariOrder = ['Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu', 'Ahad']; $tglCarbon = \Carbon\Carbon::parse($tgl);
$grouped = $kegiatans->getCollection()->groupBy('hari'); $isHariIni = ($tgl === now()->format('Y-m-d'));
$hariLabel = $tglCarbon->locale('id')->isoFormat('dddd');
$tglLabel = $tglCarbon->locale('id')->isoFormat('D MMMM Y');
$tglHadir = $items->sum('hadir') + $items->sum('terlambat');
$tglTotal = $items->sum('total_absensi');
$tglPct = $tglTotal > 0 ? round($tglHadir / $tglTotal * 100) : 0;
@endphp @endphp
@foreach($hariOrder as $hari) <div class="rw-date-block">
@if($grouped->has($hari)) <div class="rw-date-header {{ $isHariIni ? 'rw-date-today' : '' }}">
@php $items = $grouped[$hari]; @endphp <span class="dh-date">{{ $tglLabel }}</span>
<div class="day-group"> <span class="dh-hari">{{ $hariLabel }}{{ $isHariIni ? ' · Hari Ini' : '' }}</span>
<div class="day-header" onclick="toggleDay(this)"> <span class="dh-count">
<div class="day-title"> {{ $items->count() }} kegiatan
<i class="fas fa-calendar-day"></i> {{ $hari }} &nbsp;·&nbsp;
</div> <strong>{{ $tglHadir }}</strong>/{{ $tglTotal }} hadir
<div class="day-meta"> @if($tglTotal > 0)
<span class="day-count">{{ $items->count() }} kegiatan</span> <span style="background:rgba(255,255,255,.15); padding:1px 7px; border-radius:8px; margin-left:4px;">{{ $tglPct }}%</span>
<i class="fas fa-chevron-down toggle-icon"></i> @endif
</div> </span>
</div> </div>
<div class="day-body"> <div class="rw-tbl-wrap">
<table> <table class="rw-table">
<thead> <thead>
<tr> <tr>
<th style="width: 40px;">No</th> <th style="width:36px; text-align:center;">No</th>
<th>Nama Kegiatan</th> <th>Nama Kegiatan</th>
<th style="width: 110px;">Waktu</th> <th style="width:95px;">Waktu</th>
<th>Kelas</th> <th style="width:110px;">Kategori</th>
<th style="width: 130px;">Kategori</th> <th style="width:140px;">Kelas</th>
<th style="width: 250px; text-align: center;">Statistik Absensi</th> <th style="width:58px; text-align:center; color:#22c55e;" title="Hadir efektif (termasuk terlambat)">Hadir</th>
<th style="width: 90px; text-align: center;">Aksi</th> <th style="width:52px; text-align:center; color:#FF9800;" title="Terlambat">Tlbt</th>
<th style="width:48px; text-align:center; color:#f59e0b;" title="Izin">Izin</th>
<th style="width:48px; text-align:center; color:#3b82f6;" title="Sakit">Skt</th>
<th style="width:48px; text-align:center; color:#ef4444;" title="Alpa">Alpa</th>
<th style="width:90px;">Progress</th>
<th style="width:88px; text-align:center;">Aksi</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach($items as $i => $kegiatan) @foreach($items as $idx => $kegiatan)
@php
$hadirEfektif = $kegiatan->hadir + $kegiatan->terlambat;
$totalKeg = $kegiatan->total_absensi;
$kelasNames = $kegiatan->kelasKegiatan->pluck('nama_kelas');
$isUmum = $kelasNames->isEmpty();
@endphp
<tr> <tr>
<td>{{ $i + 1 }}</td> <td style="color:#94a3b8; font-size:.76rem; text-align:center;">{{ $idx + 1 }}</td>
<td><strong>{{ $kegiatan->nama_kegiatan }}</strong></td> <td>
<td style="white-space: nowrap; color: #64748b; font-size: 0.82rem;"> <div style="font-weight:700; font-size:.87rem; color:var(--primary-dark);">{{ $kegiatan->nama_kegiatan }}</div>
<i class="fas fa-clock" style="color: var(--primary-color);"></i> </td>
{{ date('H:i', strtotime($kegiatan->waktu_mulai)) }}{{ date('H:i', strtotime($kegiatan->waktu_selesai)) }} <td style="font-size:.79rem; color:#64748b; white-space:nowrap;">
{{ date('H:i', strtotime($kegiatan->waktu_mulai)) }}<br>
<span style="color:#94a3b8; font-size:.7rem;">s/d {{ date('H:i', strtotime($kegiatan->waktu_selesai)) }}</span>
</td> </td>
<td> <td>
@if($kegiatan->kelasKegiatan->isEmpty()) @if($kegiatan->kategori)
<span class="umum-tag"><i class="fas fa-globe"></i> Umum</span> <span class="rw-kat-tag">{{ $kegiatan->kategori->nama_kategori }}</span>
@endif
</td>
<td>
@if($isUmum)
<span class="rw-umum-tag"><i class="fas fa-globe-asia"></i> Umum</span>
@else @else
@foreach($kegiatan->kelasKegiatan->take(3) as $kls) @foreach($kelasNames->take(2) as $kn)
<span class="kelas-tag">{{ $kls->nama_kelas }}</span> <span class="rw-kelas-tag">{{ $kn }}</span>
@endforeach @endforeach
@if($kegiatan->kelasKegiatan->count() > 3) @if($kelasNames->count() > 2)
<span class="umum-tag">+{{ $kegiatan->kelasKegiatan->count() - 3 }}</span> <span class="rw-umum-tag">+{{ $kelasNames->count()-2 }}</span>
@endif @endif
@endif @endif
</td> </td>
<td style="text-align:center; font-weight:700; color:#065f46;">{{ $hadirEfektif ?: '' }}</td>
<td style="text-align:center; color:#e65100;">{{ $kegiatan->terlambat ?: '' }}</td>
<td style="text-align:center; color:#92400e;">{{ $kegiatan->izin ?: '' }}</td>
<td style="text-align:center; color:#1e40af;">{{ $kegiatan->sakit ?: '' }}</td>
<td style="text-align:center; color:#991b1b; font-weight:700;">{{ $kegiatan->alpa ?: '' }}</td>
<td> <td>
<span class="badge badge-success">{{ $kegiatan->kategori->nama_kategori }}</span> @if($totalKeg > 0)
</td> @php
<td style="text-align: center;"> $segs = [
@if($kegiatan->total_absensi > 0) ['w'=>round($kegiatan->hadir/$totalKeg*100), 'c'=>'#22c55e'],
<div class="stat-chips" style="justify-content: center;"> ['w'=>round($kegiatan->terlambat/$totalKeg*100), 'c'=>'#FF9800'],
@if($kegiatan->hadir > 0) ['w'=>round($kegiatan->izin/$totalKeg*100), 'c'=>'#f59e0b'],
<span class="chip chip-hadir"><i class="fas fa-check"></i> {{ $kegiatan->hadir }}</span> ['w'=>round($kegiatan->sakit/$totalKeg*100), 'c'=>'#3b82f6'],
@endif ['w'=>round($kegiatan->alpa/$totalKeg*100), 'c'=>'#ef4444'],
@if(($kegiatan->terlambat ?? 0) > 0) ];
<span class="chip chip-terlambat"><i class="fas fa-clock"></i> {{ $kegiatan->terlambat }}</span> @endphp
@endif <div class="rw-mini-prog">
@if($kegiatan->izin > 0) @foreach($segs as $s)
<span class="chip chip-izin"><i class="fas fa-envelope"></i> {{ $kegiatan->izin }}</span> @if($s['w'] > 0)<div style="width:{{ $s['w'] }}%;background:{{ $s['c'] }};"></div>@endif
@endif @endforeach
@if($kegiatan->sakit > 0)
<span class="chip chip-sakit"><i class="fas fa-heartbeat"></i> {{ $kegiatan->sakit }}</span>
@endif
@if($kegiatan->alpa > 0)
<span class="chip chip-alpa"><i class="fas fa-times"></i> {{ $kegiatan->alpa }}</span>
@endif
@if(($kegiatan->pulang ?? 0) > 0)
<span class="chip chip-pulang"><i class="fas fa-home"></i> {{ $kegiatan->pulang }}</span>
@endif
</div>
<div style="font-size: 0.74rem; color: #94a3b8; margin-top: 3px;">
Total: {{ $kegiatan->total_absensi }}
</div> </div>
<div style="font-size:.67rem; color:#94a3b8; margin-top:2px;">{{ $hadirEfektif }}/{{ $totalKeg }}</div>
@else @else
<span class="chip chip-none">Belum ada data</span> <span style="color:#cbd5e1; font-size:.76rem;"></span>
@endif @endif
</td> </td>
<td style="text-align:center;"> <td style="text-align:center;">
{{-- Teruskan parameter periode ke halaman detail --}} <a href="{{ route('admin.riwayat-kegiatan.show', $kegiatan->id) }}?mode=hari_ini&tanggal={{ $tgl }}&dari={{ $tgl }}&sampai={{ $tgl }}"
<a href="{{ route('admin.riwayat-kegiatan.show', $kegiatan->id) }}?tanggal_dari={{ $activeDari }}&tanggal_sampai={{ $activeSampai }}" class="btn-tbl-detail">
class="btn-detail"> <i class="fas fa-users"></i> Santri
<i class="fas fa-eye"></i> Detail
</a> </a>
</td> </td>
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>
@if($items->count() > 1)
<tfoot>
<tr style="background:#f0fdf4; border-top:1.5px solid #bbf7d0;">
<td colspan="5" style="font-size:.78rem; font-weight:700; color:#065f46; padding:8px 13px;">
<i class="fas fa-layer-group"></i> Total {{ $tglLabel }}
</td>
<td style="text-align:center; font-weight:800; color:#065f46;">{{ $tglHadir }}</td>
<td style="text-align:center; font-weight:700; color:#e65100;">{{ $items->sum('terlambat') }}</td>
<td style="text-align:center; font-weight:700; color:#92400e;">{{ $items->sum('izin') }}</td>
<td style="text-align:center; font-weight:700; color:#1e40af;">{{ $items->sum('sakit') }}</td>
<td style="text-align:center; font-weight:700; color:#991b1b;">{{ $items->sum('alpa') }}</td>
<td colspan="2" style="font-size:.75rem; color:#94a3b8; padding:8px 13px;">
{{ $tglTotal }} tercatat &nbsp;·&nbsp; {{ $tglPct }}% hadir
</td>
</tr>
</tfoot>
@endif
</table> </table>
</div> </div>
</div> </div>
@endif
@endforeach @endforeach
<div class="pagination" style="margin-top: 16px;">
{!! $kegiatans->appends(request()->query())->links('pagination::simple-bootstrap-4') !!}
</div>
@else @else
<div class="empty-state"> <div class="rw-empty">
<i class="fas fa-inbox"></i> <i class="fas fa-calendar-times"></i>
<h3>Tidak Ada Data</h3> <h3>Tidak Ada Data Absensi</h3>
<p>Tidak ada kegiatan pada periode <strong>{{ $periodeLabel }}</strong>.</p> <p>Tidak ada absensi yang tercatat pada periode <strong>{{ $periodeLabel }}</strong>.</p>
@if($mode === 'custom')
<p style="margin-top:8px; font-size:.82rem; color:#6b7280;">
Pastikan rentang tanggal sudah benar dan ada data absensi di periode tersebut.
</p>
@endif
</div> </div>
@endif @endif
<script> @endif
function toggleDay(header) {
var body = header.nextElementSibling;
var icon = header.querySelector('.toggle-icon');
if (body.style.display === 'none') {
body.style.display = 'block';
icon.classList.remove('collapsed');
} else {
body.style.display = 'none';
icon.classList.add('collapsed');
}
}
</script>
@endsection @endsection

View File

@ -3,237 +3,265 @@
@section('content') @section('content')
<style> <style>
.page-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; } /* ====================================================
.page-header h2 { margin: 0; color: var(--primary-dark); font-size: 1.5rem; display: flex; align-items: center; gap: 10px; } RIWAYAT KEGIATAN SHOW (detail per kegiatan)
.btn-back { padding: 8px 16px; background: #6B7280; color: #fff; border: none; border-radius: 8px; font-size: 0.85rem; text-decoration: none; display: inline-flex; align-items: center; gap: 6px; transition: background 0.2s; } ==================================================== */
.btn-back:hover { background: #4B5563; color: #fff; } .rv-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px;
margin-bottom: 18px; flex-wrap: wrap; }
.rv-header h2 { margin: 0; font-size: 1.3rem; color: var(--primary-dark); display: flex; align-items: center; gap: 9px; }
.btn-rv-back { padding: 8px 16px; background: #6b7280; color: #fff; border-radius: 8px; font-size: 0.83rem;
font-weight: 600; text-decoration: none; display: inline-flex; align-items: center; gap: 6px;
transition: background 0.18s; white-space: nowrap; }
.btn-rv-back:hover { background: #4b5563; color: #fff; }
.info-box-header { background: linear-gradient(135deg, var(--primary-color), #059669); color: #fff; padding: 20px 24px; border-radius: 12px; margin-bottom: 14px; box-shadow: 0 4px 12px rgba(16,185,129,0.2); } /* Info kegiatan banner */
.info-box-header h3 { margin: 0 0 6px; font-size: 1.3rem; display: flex; align-items: center; gap: 10px; } .rv-banner { background: linear-gradient(135deg, var(--primary-color), #059669); color: #fff;
.info-box-header .meta { opacity: 0.9; font-size: 0.88rem; display: flex; flex-wrap: wrap; gap: 12px; margin-top: 6px; } border-radius: 12px; padding: 18px 22px; margin-bottom: 14px;
.info-box-header .periode-tag { background: rgba(255,255,255,0.2); padding: 3px 10px; border-radius: 20px; font-size: 0.8rem; display: inline-flex; align-items: center; gap: 5px; } box-shadow: 0 4px 14px rgba(16,185,129,0.22); }
.rv-banner h3 { margin: 0 0 8px; font-size: 1.15rem; display: flex; align-items: center; gap: 9px; }
.rv-banner .meta { display: flex; flex-wrap: wrap; gap: 10px; font-size: 0.83rem; opacity: 0.92; }
.rv-banner .meta span { display: inline-flex; align-items: center; gap: 5px; }
.rv-periode-pill { background: rgba(255,255,255,0.22); padding: 3px 11px; border-radius: 20px;
font-size: 0.78rem; font-weight: 600; display: inline-flex; align-items: center; gap: 5px; }
/* 6 KPI cards */ /* Total santri ringkasan */
.stats-row { .rv-total-box { background: #fff; border-radius: 12px; padding: 14px 18px; margin-bottom: 14px;
display: grid; box-shadow: 0 2px 10px rgba(0,0,0,0.06); border-left: 4px solid #2563eb; }
grid-template-columns: repeat(6, 1fr); .rv-total-head { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 10px; }
gap: 12px; .rv-total-pct { font-size: 1.6rem; font-weight: 800; line-height: 1; }
margin-bottom: 14px;
}
@media (max-width: 1100px) { .stats-row { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 600px) { .stats-row { grid-template-columns: repeat(2, 1fr); } }
.stat-card { background: #fff; padding: 14px 12px; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); display: flex; align-items: center; gap: 12px; } /* KPI cards (6 status) */
.stat-card .icon { font-size: 1.4rem; width: 40px; height: 40px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; border-radius: 10px; } .rv-kpi-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 10px; margin-bottom: 14px; }
.stat-card.hadir .icon { background: #D1FAE5; color: #065F46; } @media (max-width: 1000px) { .rv-kpi-grid { grid-template-columns: repeat(3, 1fr); } }
.stat-card.terlambat .icon { background: #FFF3E0; color: #E65100; } @media (max-width: 580px) { .rv-kpi-grid { grid-template-columns: repeat(2, 1fr); } }
.stat-card.izin .icon { background: #FEF3C7; color: #92400E; }
.stat-card.sakit .icon { background: #DBEAFE; color: #1E40AF; }
.stat-card.alpa .icon { background: #FEE2E2; color: #991B1B; }
.stat-card.pulang .icon { background: #F3E8FF; color: #6B21A8; }
.stat-card .content { flex: 1; min-width: 0; }
.stat-card .label { font-size: 0.78rem; color: var(--text-light); margin-bottom: 2px; }
.stat-card .value { font-size: 1.5rem; font-weight: 700; color: var(--primary-dark); line-height: 1.2; }
.filter-box { background: #fff; padding: 14px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); margin-bottom: 14px; } .rv-kpi { background: #fff; border-radius: 10px; padding: 12px 14px; box-shadow: 0 2px 8px rgba(0,0,0,0.06);
.filter-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 11px; } display: flex; align-items: center; gap: 10px; }
.form-group { margin: 0; } .rv-kpi .ico { width: 36px; height: 36px; border-radius: 9px; display: flex; align-items: center; justify-content: center;
.form-group label { display: block; font-size: 0.85rem; margin-bottom: 5px; color: var(--text-light); font-weight: 500; } font-size: 1.1rem; flex-shrink: 0; }
.form-control { width: 100%; padding: 8px 12px; border: 1px solid #e2e8f0; border-radius: 8px; font-size: 0.85rem; } .rv-kpi.hadir .ico { background: #d1fae5; color: #065f46; }
.btn-filter { background: var(--primary-color); color: #fff; border: none; padding: 9px 16px; border-radius: 8px; cursor: pointer; font-size: 0.85rem; display: inline-flex; align-items: center; gap: 6px; transition: all 0.2s; } .rv-kpi.terlambat .ico { background: #fff3e0; color: #e65100; }
.btn-filter:hover { background: #059669; } .rv-kpi.izin .ico { background: #fef3c7; color: #92400e; }
.btn-reset { background: #6B7280; color: #fff; border: none; padding: 9px 12px; border-radius: 8px; font-size: 0.85rem; display: inline-flex; align-items: center; gap: 6px; text-decoration: none; } .rv-kpi.sakit .ico { background: #dbeafe; color: #1e40af; }
.btn-reset:hover { background: #4B5563; color: #fff; } .rv-kpi.alpa .ico { background: #fee2e2; color: #991b1b; }
.rv-kpi.pulang .ico { background: #f3e8ff; color: #6b21a8; }
.rv-kpi .cnt { font-size: 1.4rem; font-weight: 800; color: var(--primary-dark); line-height: 1; }
.rv-kpi .lbl { font-size: 0.75rem; color: #94a3b8; margin-top: 2px; }
.day-group { margin-bottom: 18px; background: #fff; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); overflow: hidden; } /* Filter box */
.day-header { background: linear-gradient(135deg, #f0fdf4 0%, #E8F7F2 100%); padding: 14px 18px; display: flex; justify-content: space-between; align-items: center; border-bottom: 2px solid #E8F7F2; cursor: pointer; transition: background 0.2s; user-select: none; } .rv-filter { background: #fff; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);
.day-header:hover { background: linear-gradient(135deg, #E8F7F2 0%, #d1f2e8 100%); } padding: 12px 16px; margin-bottom: 14px; }
.day-title { font-weight: 700; font-size: 1rem; color: var(--primary-dark); display: flex; align-items: center; gap: 8px; } .rv-filter-row { display: flex; gap: 9px; align-items: flex-end; flex-wrap: wrap; }
.day-title i { color: var(--primary-color); } .rv-fg { display: flex; flex-direction: column; gap: 4px; }
.day-stats { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; } .rv-fg label { font-size: 0.77rem; font-weight: 600; color: #64748b; }
.mini-badge { padding: 4px 10px; border-radius: 20px; font-size: 0.75rem; font-weight: 600; display: inline-flex; align-items: center; gap: 4px; } .rv-fg select, .rv-fg input { padding: 7px 10px; font-size: 0.83rem; border: 1.5px solid #e2e8f0; border-radius: 7px; }
.mini-badge.hadir { background: #D1FAE5; color: #065F46; } .rv-fg select:focus, .rv-fg input:focus { border-color: var(--primary-color); outline: none; }
.mini-badge.terlambat { background: #FFF3E0; color: #E65100; } .btn-rv-filter { background: var(--primary-color); color: #fff; border: none; padding: 8px 16px; border-radius: 7px;
.mini-badge.izin { background: #FEF3C7; color: #92400E; } font-size: 0.82rem; font-weight: 600; cursor: pointer; display: inline-flex; align-items: center;
.mini-badge.sakit { background: #DBEAFE; color: #1E40AF; } gap: 5px; align-self: flex-end; transition: background 0.18s; }
.mini-badge.alpa { background: #FEE2E2; color: #991B1B; } .btn-rv-filter:hover { background: #059669; }
.mini-badge.pulang { background: #F3E8FF; color: #6B21A8; } .btn-rv-clear { background: #f1f5f9; color: #64748b; border: 1.5px solid #e2e8f0; padding: 8px 10px; border-radius: 7px;
.day-body table { width: 100%; border-collapse: collapse; } font-size: 0.82rem; font-weight: 600; text-decoration: none; display: inline-flex; align-items: center;
.day-body table thead { background: #f8fafc; } gap: 5px; align-self: flex-end; transition: all 0.18s; }
.day-body table th { padding: 10px 14px; text-align: left; font-weight: 600; font-size: 0.82rem; color: #64748b; border-bottom: 1px solid #e2e8f0; } .btn-rv-clear:hover { background: #e2e8f0; color: #374151; }
.day-body table td { padding: 9px 14px; font-size: 0.85rem; border-bottom: 1px solid #f1f5f9; }
.day-body table tbody tr:last-child td { border-bottom: none; }
.day-body table tbody tr:hover { background: #f8fafc; }
.toggle-icon { transition: transform 0.3s; font-size: 0.85rem; color: #94a3b8; }
.toggle-icon.collapsed { transform: rotate(-90deg); }
.empty-state { text-align: center; padding: 36px 20px; color: var(--text-light); background: #fff; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); } /* Day group */
.empty-state i { font-size: 3.5rem; margin-bottom: 14px; opacity: 0.3; display: block; } .rv-day-group { background: #fff; border-radius: 12px; box-shadow: 0 2px 10px rgba(0,0,0,0.06);
overflow: hidden; margin-bottom: 16px; border: 1px solid #f0f0f0; }
.rv-day-head { background: linear-gradient(135deg, #f0fdf4, #e8f7f2); padding: 13px 18px;
display: flex; justify-content: space-between; align-items: center;
border-bottom: 2px solid #e8f7f2; cursor: pointer; user-select: none;
transition: background 0.18s; }
.rv-day-head:hover{ background: linear-gradient(135deg, #e8f7f2, #d1f2e8); }
.rv-day-title { font-weight: 700; font-size: 0.95rem; color: var(--primary-dark);
display: flex; align-items: center; gap: 8px; }
.rv-day-badges { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.rv-mini { padding: 3px 10px; border-radius: 18px; font-size: 0.74rem; font-weight: 700;
display: inline-flex; align-items: center; gap: 4px; }
.rv-mini.hadir { background: #d1fae5; color: #065f46; }
.rv-mini.terlambat{ background: #fff3e0; color: #e65100; }
.rv-mini.izin { background: #fef3c7; color: #92400e; }
.rv-mini.sakit { background: #dbeafe; color: #1e40af; }
.rv-mini.alpa { background: #fee2e2; color: #991b1b; }
.rv-mini.pulang { background: #f3e8ff; color: #6b21a8; }
.rv-toggle { color: #94a3b8; transition: transform 0.25s; font-size: 0.82rem; flex-shrink: 0; }
.rv-toggle.closed { transform: rotate(-90deg); }
.pagination { display: flex; justify-content: center; align-items: center; gap: 6px; margin-top: 14px; } /* Kelas sub-header */
.pagination a, .pagination span { padding: 6px 12px; border: 1px solid #e2e8f0; border-radius: 6px; font-size: 0.82rem; text-decoration: none; color: var(--text-dark); transition: all 0.2s; } .rv-kelas-subhead { background: linear-gradient(90deg, #f0fdf4, #e8f5e9); padding: 8px 16px;
.pagination a:hover { background: var(--primary-color); color: #fff; border-color: var(--primary-color); } display: flex; justify-content: space-between; align-items: center;
.pagination .active { background: var(--primary-color); color: #fff; border-color: var(--primary-color); font-weight: 600; } border-bottom: 1px solid #e2e8f0; }
.pagination .disabled { color: #cbd5e1; cursor: not-allowed; } .rv-kelas-subhead .name { font-size: 0.85rem; font-weight: 700; color: #065f46;
display: flex; align-items: center; gap: 6px; }
.rv-kelas-subhead .cnt { background: #6fbaa5; color: #fff; padding: 2px 10px; border-radius: 10px;
font-size: 0.74rem; font-weight: 700; }
@media (max-width: 768px) { /* Table santri */
.day-header { flex-direction: column; align-items: flex-start; gap: 8px; } .rv-table { width: 100%; border-collapse: collapse; }
.day-body table th:nth-child(2), .day-body table td:nth-child(2) { display: none; } .rv-table thead th { padding: 9px 14px; text-align: left; font-size: 0.79rem; font-weight: 600;
.day-body table th:nth-child(7), .day-body table td:nth-child(7) { display: none; } color: #64748b; background: #f8fafc; border-bottom: 1px solid #e2e8f0; }
} .rv-table tbody td { padding: 9px 14px; font-size: 0.84rem; border-bottom: 1px solid #f8fafc;
vertical-align: middle; }
.rv-table tbody tr:last-child td { border-bottom: none; }
.rv-table tbody tr:hover { background: #f8fafc; }
/* Santri name link */
.rv-santri-link { color: var(--primary-color); text-decoration: none; font-weight: 600;
display: inline-flex; align-items: center; gap: 5px; transition: color 0.15s; }
.rv-santri-link:hover { color: #059669; text-decoration: underline; }
.btn-rv-history { padding: 3px 10px; background: #f0fdf4; color: var(--primary-color);
border: 1px solid #bbf7d0; border-radius: 6px; font-size: 0.74rem; font-weight: 600;
text-decoration: none; display: inline-flex; align-items: center; gap: 4px;
transition: all 0.15s; white-space: nowrap; }
.btn-rv-history:hover { background: var(--primary-color); color: #fff; border-color: var(--primary-color); }
/* Metode badges */
.rv-rfid { background: #dbeafe; color: #1e40af; padding: 3px 9px; border-radius: 9px; font-size: 0.74rem; font-weight: 700; }
.rv-mesin { background: #ede9fe; color: #6b21a8; padding: 3px 9px; border-radius: 9px; font-size: 0.74rem; font-weight: 700; }
.rv-manual { background: #f1f5f9; color: #374151; padding: 3px 9px; border-radius: 9px; font-size: 0.74rem; font-weight: 700; }
/* Progress bar reuse */
.rv-prog-wrap { height: 16px; background: #f3f4f6; border-radius: 8px; overflow: hidden; display: flex; }
/* Empty */
.rv-empty { text-align: center; padding: 36px 20px; color: #94a3b8; background: #fff;
border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
.rv-empty i { font-size: 2.8rem; margin-bottom: 10px; display: block; opacity: 0.35; }
</style> </style>
@php @php
// Ambil range dari query string (diteruskan dari index) $mode = $mode ?? 'hari_ini';
$defaultDari = now()->startOfWeek(\Carbon\Carbon::MONDAY)->format('Y-m-d'); $dari = $dari ?? now()->format('Y-m-d');
$defaultSampai = now()->endOfWeek(\Carbon\Carbon::SUNDAY)->format('Y-m-d'); $sampai = $sampai ?? now()->format('Y-m-d');
$filterDari = request('tanggal_dari', $defaultDari); $tanggal = $tanggal ?? now()->format('Y-m-d');
$filterSampai = request('tanggal_sampai', $defaultSampai);
$filterBulan = request('bulan', '');
if ($filterBulan) {
$periodeLabel = 'Bulan ' . \Carbon\Carbon::parse($filterBulan . '-01')->locale('id')->isoFormat('MMMM Y');
} else {
$periodeLabel = \Carbon\Carbon::parse($filterDari)->locale('id')->isoFormat('D MMM Y')
. ' '
. \Carbon\Carbon::parse($filterSampai)->locale('id')->isoFormat('D MMM Y');
}
// Hitung KPI dari data yang sudah difilter (semua halaman, bukan hanya halaman ini)
// $stats sudah dihitung di controller berdasarkan filter — gunakan langsung
// Tapi jika controller belum menghitung per filter, hitung dari koleksi paginator saat ini
// Gunakan $stats dari controller jika ada, fallback ke hitung manual
$statsHadir = $stats['Hadir'] ?? 0; $statsHadir = $stats['Hadir'] ?? 0;
$statsTerlambat = $stats['Terlambat'] ?? 0; $statsTerlambat = $stats['Terlambat'] ?? 0;
$statsIzin = $stats['Izin'] ?? 0; $statsIzin = $stats['Izin'] ?? 0;
$statsSakit = $stats['Sakit'] ?? 0; $statsSakit = $stats['Sakit'] ?? 0;
$statsAlpa = $stats['Alpa'] ?? 0; $statsAlpa = $stats['Alpa'] ?? 0;
$statsPulang = $stats['Pulang'] ?? 0; $statsPulang = $stats['Pulang'] ?? 0;
$backParams = ['mode' => $mode, 'dari' => $dari, 'sampai' => $sampai, 'tanggal' => $tanggal];
@endphp @endphp
<div class="page-header"> {{-- ── HEADER ───────────────────────────────────────────────────────────────── --}}
<h2><i class="fas fa-file-alt"></i> Detail Riwayat: {{ $kegiatan->nama_kegiatan }}</h2> <div class="rv-header">
<a href="{{ route('admin.riwayat-kegiatan.index', ['tanggal_dari' => $filterDari, 'tanggal_sampai' => $filterSampai]) }}" <h2><i class="fas fa-file-alt" style="color:var(--primary-color);"></i>
class="btn-back"> {{ $kegiatan->nama_kegiatan }}
</h2>
<a href="{{ route('admin.riwayat-kegiatan.index', $backParams) }}" class="btn-rv-back">
<i class="fas fa-arrow-left"></i> Kembali <i class="fas fa-arrow-left"></i> Kembali
</a> </a>
</div> </div>
{{-- Info Kegiatan --}} {{-- ── BANNER INFO ──────────────────────────────────────────────────────────── --}}
<div class="info-box-header"> <div class="rv-banner">
<h3><i class="fas fa-clipboard-check"></i> {{ $kegiatan->nama_kegiatan }}</h3> <h3><i class="fas fa-clipboard-check"></i> {{ $kegiatan->nama_kegiatan }}</h3>
<div class="meta"> <div class="meta">
<span><i class="fas fa-tag"></i> {{ $kegiatan->kategori->nama_kategori }}</span> <span><i class="fas fa-tag"></i> {{ $kegiatan->kategori->nama_kategori }}</span>
<span><i class="fas fa-clock"></i> {{ date('H:i', strtotime($kegiatan->waktu_mulai)) }} - {{ date('H:i', strtotime($kegiatan->waktu_selesai)) }}</span> <span><i class="fas fa-clock"></i> {{ date('H:i', strtotime($kegiatan->waktu_mulai)) }} {{ date('H:i', strtotime($kegiatan->waktu_selesai)) }}</span>
<span><i class="fas fa-calendar-day"></i> {{ $kegiatan->hari }}</span> <span><i class="fas fa-calendar-day"></i> {{ $kegiatan->hari }}</span>
@if($kegiatan->kelasKegiatan->count() > 0) @if($kegiatan->kelasKegiatan->count() > 0)
<span><i class="fas fa-users"></i> {{ $kegiatan->kelasKegiatan->pluck('nama_kelas')->implode(', ') }}</span> <span><i class="fas fa-users"></i> {{ $kegiatan->kelasKegiatan->pluck('nama_kelas')->implode(', ') }}</span>
@else @else
<span><i class="fas fa-globe"></i> Umum</span> <span><i class="fas fa-globe"></i> Kegiatan Umum</span>
@endif @endif
<span class="periode-tag"><i class="fas fa-calendar-check"></i> {{ $periodeLabel }}</span> <span class="rv-periode-pill"><i class="fas fa-calendar-check"></i> {{ $periodeLabel }}</span>
</div> </div>
</div> </div>
{{-- Ringkasan Total Santri --}} {{-- ── TOTAL SANTRI RINGKASAN ───────────────────────────────────────────────── --}}
@if(isset($totalSantriEligible)) @if(isset($totalSantriEligible))
<div style="background: #fff; border-radius: 12px; padding: 16px 20px; margin-bottom: 14px; box-shadow: 0 2px 12px rgba(0,0,0,0.06); border-left: 4px solid #2563eb;"> <div class="rv-total-box">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 10px;"> <div class="rv-total-head">
<div> <div>
<h4 style="margin: 0; font-size: 1rem; color: #1a2332;"> <div style="font-size:0.95rem; font-weight:700; color:#1a2332; margin-bottom:4px;">
<i class="fas fa-users" style="color: #2563eb;"></i> Total Semua Santri: <strong>{{ $totalSantriEligible }}</strong> <i class="fas fa-users" style="color:#2563eb;"></i>
</h4> Total Santri Seharusnya Hadir: <strong>{{ $totalSantriEligible }}</strong>
<p style="margin: 4px 0 0; font-size: 0.84rem; color: #6b7280;"> </div>
Sudah absen: <strong style="color: #059669;">{{ $totalRecorded }}</strong> <div style="font-size:0.82rem; color:#6b7280;">
Sudah tercatat: <strong style="color:#059669;">{{ $totalRecorded }}</strong>
&nbsp;·&nbsp; &nbsp;·&nbsp;
Belum absen: <strong style="color: {{ ($totalSantriEligible - $totalRecorded) > 0 ? '#dc2626' : '#059669' }};">{{ max(0, $totalSantriEligible - $totalRecorded) }}</strong> Belum tercatat:
</p> <strong style="color:{{ ($totalSantriEligible - $totalRecorded) > 0 ? '#dc2626' : '#059669' }};">
{{ max(0, $totalSantriEligible - $totalRecorded) }}
</strong>
</div>
</div> </div>
<div style="text-align:right;"> <div style="text-align:right;">
<div style="font-size: 1.5rem; font-weight: 800; color: {{ $persenHadir >= 85 ? '#059669' : ($persenHadir >= 70 ? '#d97706' : '#dc2626') }};"> <div class="rv-total-pct"
style="color:{{ $persenHadir >= 85 ? '#059669' : ($persenHadir >= 70 ? '#d97706' : '#dc2626') }};">
{{ $persenHadir }}% {{ $persenHadir }}%
</div> </div>
<div style="font-size: 0.78rem; color: #6b7280;">Kehadiran</div> <div style="font-size:0.74rem; color:#6b7280;">Kehadiran</div>
</div> </div>
</div> </div>
{{-- Progress bar --}}
@php @php
$pctSudah = $totalSantriEligible > 0 ? round($totalRecorded / $totalSantriEligible * 100, 1) : 0; $pctSudah = $totalSantriEligible > 0 ? round($totalRecorded / $totalSantriEligible * 100, 1) : 0;
$pctBelumRiwayat = 100 - $pctSudah; $pctBlm = 100 - $pctSudah;
@endphp @endphp
<div style="height: 24px; background: #f3f4f6; border-radius: 12px; overflow: hidden; display: flex;"> <div class="rv-prog-wrap">
@if($pctSudah > 0) @if($pctSudah > 0)
<div style="width: {{ $pctSudah }}%; background: linear-gradient(90deg, #22c55e, #16a34a); display: flex; align-items: center; justify-content: center; color: white; font-size: 0.73rem; font-weight: 700;" title="Sudah Absen: {{ $totalRecorded }}"> <div style="width:{{ $pctSudah }}%; background:linear-gradient(90deg,#22c55e,#16a34a);
{{ $totalRecorded }} display:flex; align-items:center; justify-content:center;
color:white; font-size:0.72rem; font-weight:700;">
{{ $totalRecorded > 0 && $pctSudah > 8 ? $totalRecorded : '' }}
</div> </div>
@endif @endif
@if($pctBelumRiwayat > 0 && ($totalSantriEligible - $totalRecorded) > 0) @if($pctBlm > 0 && ($totalSantriEligible - $totalRecorded) > 0)
<div style="width: {{ $pctBelumRiwayat }}%; background: #d1d5db; display: flex; align-items: center; justify-content: center; color: #6b7280; font-size: 0.73rem; font-weight: 700;" title="Belum Absen: {{ $totalSantriEligible - $totalRecorded }}"> <div style="width:{{ $pctBlm }}%; background:#d1d5db;
{{ $totalSantriEligible - $totalRecorded }} display:flex; align-items:center; justify-content:center;
color:#6b7280; font-size:0.72rem; font-weight:700;">
{{ ($totalSantriEligible - $totalRecorded) > 0 && $pctBlm > 8 ? ($totalSantriEligible - $totalRecorded) : '' }}
</div> </div>
@endif @endif
</div> </div>
</div> </div>
@endif @endif
{{-- 6 KPI Cards --}} {{-- ── 6 KPI CARDS ─────────────────────────────────────────────────────────── --}}
<div class="stats-row"> <div class="rv-kpi-grid">
<div class="stat-card hadir"> <div class="rv-kpi hadir">
<div class="icon"><i class="fas fa-check-circle"></i></div> <div class="ico"><i class="fas fa-check-circle"></i></div>
<div class="content"> <div><div class="cnt">{{ $statsHadir }}</div><div class="lbl">Hadir</div></div>
<div class="label">Hadir</div>
<div class="value">{{ $statsHadir }}</div>
</div> </div>
<div class="rv-kpi terlambat">
<div class="ico"><i class="fas fa-clock"></i></div>
<div><div class="cnt">{{ $statsTerlambat }}</div><div class="lbl">Terlambat</div></div>
</div> </div>
<div class="stat-card terlambat"> <div class="rv-kpi izin">
<div class="icon"><i class="fas fa-clock"></i></div> <div class="ico"><i class="fas fa-envelope"></i></div>
<div class="content"> <div><div class="cnt">{{ $statsIzin }}</div><div class="lbl">Izin</div></div>
<div class="label">Terlambat</div>
<div class="value">{{ $statsTerlambat }}</div>
</div> </div>
<div class="rv-kpi sakit">
<div class="ico"><i class="fas fa-heartbeat"></i></div>
<div><div class="cnt">{{ $statsSakit }}</div><div class="lbl">Sakit</div></div>
</div> </div>
<div class="stat-card izin"> <div class="rv-kpi alpa">
<div class="icon"><i class="fas fa-envelope"></i></div> <div class="ico"><i class="fas fa-times-circle"></i></div>
<div class="content"> <div><div class="cnt">{{ $statsAlpa }}</div><div class="lbl">Alpa</div></div>
<div class="label">Izin</div>
<div class="value">{{ $statsIzin }}</div>
</div>
</div>
<div class="stat-card sakit">
<div class="icon"><i class="fas fa-heartbeat"></i></div>
<div class="content">
<div class="label">Sakit</div>
<div class="value">{{ $statsSakit }}</div>
</div>
</div>
<div class="stat-card alpa">
<div class="icon"><i class="fas fa-times-circle"></i></div>
<div class="content">
<div class="label">Alpa</div>
<div class="value">{{ $statsAlpa }}</div>
</div>
</div>
<div class="stat-card pulang">
<div class="icon"><i class="fas fa-home"></i></div>
<div class="content">
<div class="label">Pulang</div>
<div class="value">{{ $statsPulang }}</div>
</div> </div>
<div class="rv-kpi pulang">
<div class="ico"><i class="fas fa-home"></i></div>
<div><div class="cnt">{{ $statsPulang }}</div><div class="lbl">Pulang</div></div>
</div> </div>
</div> </div>
{{-- Filter --}} {{-- ── FILTER ───────────────────────────────────────────────────────────────── --}}
<div class="filter-box"> <div class="rv-filter">
<form method="GET"> <form method="GET">
{{-- Pertahankan range periode dari index --}} {{-- Pertahankan parameter periode --}}
<input type="hidden" name="tanggal_dari" value="{{ $filterDari }}"> <input type="hidden" name="mode" value="{{ $mode }}">
<input type="hidden" name="tanggal_sampai" value="{{ $filterSampai }}"> <input type="hidden" name="dari" value="{{ $dari }}">
<input type="hidden" name="sampai" value="{{ $sampai }}">
<input type="hidden" name="tanggal" value="{{ $tanggal }}">
<div class="filter-grid"> <div class="rv-filter-row">
<div class="form-group"> <div class="rv-fg">
<label for="id_santri">Santri</label> <label><i class="fas fa-user"></i> Cari Santri</label>
<select name="id_santri" id="id_santri" class="form-control"> <select name="id_santri" style="min-width:200px;">
<option value="">-- Semua Santri --</option> <option value="">Semua Santri</option>
@foreach($santris as $s) @foreach($santris as $s)
<option value="{{ $s->id_santri }}" {{ request('id_santri') == $s->id_santri ? 'selected' : '' }}> <option value="{{ $s->id_santri }}" {{ request('id_santri') == $s->id_santri ? 'selected' : '' }}>
{{ $s->nama_lengkap }} {{ $s->nama_lengkap }}
@ -242,13 +270,13 @@ class="btn-back">
</select> </select>
</div> </div>
<div class="form-group"> <div class="rv-fg">
<label for="id_kelas">Kelas</label> <label><i class="fas fa-school"></i> Kelas</label>
<select name="id_kelas" id="id_kelas" class="form-control"> <select name="id_kelas" style="min-width:160px;">
<option value="">-- Semua Kelas --</option> <option value="">Semua Kelas</option>
@foreach($kelasList->groupBy('kelompok.nama_kelompok') as $kelompokNama => $kelasList_group) @foreach($kelasList->groupBy('kelompok.nama_kelompok') as $grpNama => $grpKelas)
<optgroup label="{{ $kelompokNama }}"> <optgroup label="{{ $grpNama }}">
@foreach($kelasList_group as $kelas) @foreach($grpKelas as $kelas)
<option value="{{ $kelas->id }}" {{ request('id_kelas') == $kelas->id ? 'selected' : '' }}> <option value="{{ $kelas->id }}" {{ request('id_kelas') == $kelas->id ? 'selected' : '' }}>
{{ $kelas->nama_kelas }} {{ $kelas->nama_kelas }}
</option> </option>
@ -258,197 +286,204 @@ class="btn-back">
</select> </select>
</div> </div>
<div class="form-group"> <div class="rv-fg">
<label for="status">Status</label> <label><i class="fas fa-filter"></i> Status</label>
<select name="status" id="status" class="form-control"> <select name="status" style="min-width:140px;">
<option value="">-- Semua Status --</option> <option value="">Semua Status</option>
<option value="Hadir" {{ request('status') == 'Hadir' ? 'selected' : '' }}>Hadir</option> @foreach(['Hadir','Terlambat','Izin','Sakit','Alpa','Pulang'] as $st)
<option value="Terlambat" {{ request('status') == 'Terlambat' ? 'selected' : '' }}>Terlambat</option> <option value="{{ $st }}" {{ request('status') == $st ? 'selected' : '' }}>{{ $st }}</option>
<option value="Izin" {{ request('status') == 'Izin' ? 'selected' : '' }}>Izin</option> @endforeach
<option value="Sakit" {{ request('status') == 'Sakit' ? 'selected' : '' }}>Sakit</option>
<option value="Alpa" {{ request('status') == 'Alpa' ? 'selected' : '' }}>Alpa</option>
<option value="Pulang" {{ request('status') == 'Pulang' ? 'selected' : '' }}>Pulang</option>
</select> </select>
</div> </div>
<div class="form-group"> @if($mode !== 'hari_ini')
<label for="tanggal_spesifik">Filter Tanggal Spesifik</label> <div class="rv-fg">
<input type="date" name="tanggal_spesifik" id="tanggal_spesifik" class="form-control" <label><i class="fas fa-calendar"></i> Tanggal Spesifik</label>
<input type="date" name="tanggal_spesifik"
value="{{ request('tanggal_spesifik') }}" value="{{ request('tanggal_spesifik') }}"
min="{{ $filterDari }}" max="{{ $filterSampai }}"> min="{{ $dari }}" max="{{ $sampai }}">
</div> </div>
@endif
<div style="display: flex; align-items: flex-end; gap: 10px;"> <button type="submit" class="btn-rv-filter">
<button type="submit" class="btn-filter" style="flex: 1;">
<i class="fas fa-filter"></i> Filter <i class="fas fa-filter"></i> Filter
</button> </button>
@if(request()->hasAny(['id_santri','id_kelas','status','tanggal_spesifik'])) @if(request()->hasAny(['id_santri','id_kelas','status','tanggal_spesifik']))
<a href="{{ route('admin.riwayat-kegiatan.show', $kegiatan->id) }}?tanggal_dari={{ $filterDari }}&tanggal_sampai={{ $filterSampai }}" <a href="{{ route('admin.riwayat-kegiatan.show', $kegiatan->id) }}?{{ http_build_query(['mode'=>$mode,'dari'=>$dari,'sampai'=>$sampai,'tanggal'=>$tanggal]) }}"
class="btn-reset"> class="btn-rv-clear">
<i class="fas fa-times"></i> <i class="fas fa-times"></i> Hapus Filter
</a> </a>
@endif @endif
</div> </div>
</div>
</form> </form>
</div> </div>
{{-- Tabel Riwayat Grouped by Tanggal --}} {{-- ── TABEL RIWAYAT DIKELOMPOK PER TANGGAL ────────────────────────────────── --}}
@if($riwayats->count() > 0) @if($riwayats->count() > 0)
@php @php
$grouped = $riwayats->getCollection()->groupBy(function($item) { $grouped = $riwayats->getCollection()->groupBy(fn($item) => $item->tanggal->format('Y-m-d'))->sortKeysDesc();
return $item->tanggal->format('Y-m-d'); $isUmum = $kegiatan->kelasKegiatan->isEmpty();
})->sortKeysDesc();
@endphp @endphp
@foreach($grouped as $tanggal => $records) @foreach($grouped as $tanggal => $records)
@php @php
$tglCarbon = \Carbon\Carbon::parse($tanggal); $tglC = \Carbon\Carbon::parse($tanggal);
$hariIndo = $tglCarbon->locale('id')->isoFormat('dddd'); $hariStr = $tglC->locale('id')->isoFormat('dddd');
$tglFormatted = $tglCarbon->locale('id')->isoFormat('D MMMM Y'); $tglStr = $tglC->locale('id')->isoFormat('D MMMM Y');
$dayHadir = $records->where('status', 'Hadir')->count(); $dHadir = $records->where('status','Hadir')->count();
$dayTerlambat = $records->where('status', 'Terlambat')->count(); $dTerlambat = $records->where('status','Terlambat')->count();
$dayIzin = $records->where('status', 'Izin')->count(); $dIzin = $records->where('status','Izin')->count();
$daySakit = $records->where('status', 'Sakit')->count(); $dSakit = $records->where('status','Sakit')->count();
$dayAlpa = $records->where('status', 'Alpa')->count(); $dAlpa = $records->where('status','Alpa')->count();
$dayPulang = $records->where('status', 'Pulang')->count(); $dPulang = $records->where('status','Pulang')->count();
$dayTotal = $records->count(); $dTotal = $records->count();
// Group per kelas kegiatan (khusus) atau kelas_name santri (umum) // Kelompok per kelas (sama seperti show sebelumnya)
$isUmum = $kegiatan->kelasKegiatan->isEmpty();
if ($isUmum) { if ($isUmum) {
$recordsPerKelas = $records->groupBy(fn($r) => $perKelas = $records->groupBy(fn($r) =>
optional(optional($r->santri->kelasSantri->first())->kelas)->nama_kelas ?? 'Tanpa Kelas' optional(optional($r->santri->kelasSantri->first())->kelas)->nama_kelas ?? 'Tanpa Kelas'
)->sortKeys(); )->sortKeys();
} else { } else {
$recordsPerKelas = collect(); $perKelas = collect();
$placedIds = []; $placedIds = [];
foreach ($kegiatan->kelasKegiatan as $kls) { foreach ($kegiatan->kelasKegiatan as $kls) {
$inKelas = $records->filter(function($r) use ($kls, &$placedIds) { $inKls = $records->filter(function($r) use ($kls, &$placedIds) {
if (in_array($r->id, $placedIds)) return false; if (in_array($r->id, $placedIds)) return false;
return $r->santri->kelasSantri->contains('id_kelas', $kls->id); return $r->santri->kelasSantri->contains('id_kelas', $kls->id);
}); });
foreach ($inKelas as $r) $placedIds[] = $r->id; foreach ($inKls as $r) $placedIds[] = $r->id;
if ($inKelas->count() > 0) $recordsPerKelas[$kls->nama_kelas] = $inKelas; if ($inKls->count() > 0) $perKelas[$kls->nama_kelas] = $inKls;
} }
$lainnya = $records->filter(fn($r) => !in_array($r->id, $placedIds)); $lainnya = $records->filter(fn($r) => !in_array($r->id, $placedIds));
if ($lainnya->count() > 0) $recordsPerKelas['Kelas Lain'] = $lainnya; if ($lainnya->count() > 0) $perKelas['Kelas Lain'] = $lainnya;
} }
@endphp @endphp
<div class="day-group"> <div class="rv-day-group">
<div class="day-header" onclick="toggleDay(this)">
<div class="day-title"> {{-- Day header --}}
<i class="fas fa-calendar-day"></i> <div class="rv-day-head" onclick="toggleDay(this)">
{{ $hariIndo }}, {{ $tglFormatted }} <div class="rv-day-title">
<span style="font-weight: 400; font-size: 0.85rem; color: #94a3b8; margin-left: 4px;">({{ $dayTotal }} santri)</span> <i class="fas fa-calendar-day" style="color:var(--primary-color);"></i>
{{ $hariStr }}, {{ $tglStr }}
<span style="font-weight:400; font-size:0.82rem; color:#94a3b8;">({{ $dTotal }} santri)</span>
</div> </div>
<div class="day-stats"> <div class="rv-day-badges">
@if($dayHadir > 0) @if($dHadir > 0) <span class="rv-mini hadir"><i class="fas fa-check"></i> {{ $dHadir }}</span> @endif
<span class="mini-badge hadir"><i class="fas fa-check"></i> {{ $dayHadir }}</span> @if($dTerlambat > 0) <span class="rv-mini terlambat"><i class="fas fa-clock"></i> {{ $dTerlambat }}</span> @endif
@endif @if($dIzin > 0) <span class="rv-mini izin"><i class="fas fa-envelope"></i> {{ $dIzin }}</span> @endif
@if($dayTerlambat > 0) @if($dSakit > 0) <span class="rv-mini sakit"><i class="fas fa-heartbeat"></i> {{ $dSakit }}</span> @endif
<span class="mini-badge terlambat"><i class="fas fa-clock"></i> {{ $dayTerlambat }}</span> @if($dAlpa > 0) <span class="rv-mini alpa"><i class="fas fa-times"></i> {{ $dAlpa }}</span> @endif
@endif @if($dPulang > 0) <span class="rv-mini pulang"><i class="fas fa-home"></i> {{ $dPulang }}</span> @endif
@if($dayIzin > 0) <i class="fas fa-chevron-down rv-toggle"></i>
<span class="mini-badge izin"><i class="fas fa-envelope"></i> {{ $dayIzin }}</span>
@endif
@if($daySakit > 0)
<span class="mini-badge sakit"><i class="fas fa-heartbeat"></i> {{ $daySakit }}</span>
@endif
@if($dayAlpa > 0)
<span class="mini-badge alpa"><i class="fas fa-times"></i> {{ $dayAlpa }}</span>
@endif
@if($dayPulang > 0)
<span class="mini-badge pulang"><i class="fas fa-home"></i> {{ $dayPulang }}</span>
@endif
<i class="fas fa-chevron-down toggle-icon"></i>
</div> </div>
</div> </div>
<div class="day-body">
@foreach($recordsPerKelas as $namaKelas => $kelasRecords) {{-- Day body --}}
<div style="background: linear-gradient(135deg, #f0fdf4, #e8f5e9); padding: 8px 18px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #e2e8f0;"> <div class="rv-day-body">
<span style="font-size: 0.85rem; font-weight: 600; color: #065f46;"> @foreach($perKelas as $namaKelas => $kelasRecords)
{{-- Kelas sub-header --}}
<div class="rv-kelas-subhead">
<div class="name">
<i class="fas fa-school"></i> {{ $namaKelas }} <i class="fas fa-school"></i> {{ $namaKelas }}
</span>
<span style="background: #6FBAA5; color: white; padding: 2px 10px; border-radius: 10px; font-size: 0.75rem; font-weight: 600;">
{{ $kelasRecords->count() }} santri
</span>
</div> </div>
<table> <span class="cnt">{{ $kelasRecords->count() }} santri</span>
</div>
{{-- Santri table --}}
<table class="rv-table">
<thead> <thead>
<tr> <tr>
<th style="width: 45px;">No</th> <th style="width:40px;">No</th>
<th style="width: 90px;">ID Santri</th> <th style="width:90px;">ID</th>
<th>Nama Santri</th> <th>Nama Santri</th>
<th style="width: 90px; text-align: center;">Status</th> <th style="width:100px; text-align:center;">Status</th>
<th style="width: 80px; text-align: center;">Waktu</th> <th style="width:75px; text-align:center;">Waktu</th>
<th style="width: 80px;">Metode</th> <th style="width:85px;">Metode</th>
<th style="width:110px; text-align:center;">Riwayat</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach($kelasRecords->values() as $index => $riwayat) @foreach($kelasRecords->values() as $idx => $riwayat)
<tr> <tr>
<td>{{ $index + 1 }}</td> <td style="color:#94a3b8; font-size:0.78rem;">{{ $idx + 1 }}</td>
<td><strong>{{ $riwayat->id_santri }}</strong></td> <td>
<span style="font-size:0.78rem; font-weight:700; color:#64748b;">
{{ $riwayat->id_santri }}
</span>
</td>
<td> <td>
<a href="{{ route('admin.riwayat-kegiatan.detail-santri', $riwayat->id_santri) }}" <a href="{{ route('admin.riwayat-kegiatan.detail-santri', $riwayat->id_santri) }}"
style="color: var(--primary-color); text-decoration: none; font-weight: 500;"> class="rv-santri-link">
<i class="fas fa-user" style="font-size:0.75rem; opacity:0.6;"></i>
{{ $riwayat->santri->nama_lengkap }} {{ $riwayat->santri->nama_lengkap }}
</a> </a>
</td> </td>
<td style="text-align: center;">{!! $riwayat->status_badge !!}</td>
<td style="text-align:center;"> <td style="text-align:center;">
{{ $riwayat->waktu_absen ? \Carbon\Carbon::parse($riwayat->waktu_absen)->format('H:i') : '-' }} {!! $riwayat->status_badge !!}
</td>
<td style="text-align:center; font-size:0.8rem; color:#64748b;">
{{ $riwayat->waktu_absen ? \Carbon\Carbon::parse($riwayat->waktu_absen)->format('H:i') : '' }}
</td> </td>
<td> <td>
@if($riwayat->metode_absen == 'RFID') @if($riwayat->metode_absen === 'RFID')
<span style="background: #DBEAFE; color: #1E40AF; padding: 3px 8px; border-radius: 10px; font-size: 0.75rem; font-weight: 600;"> <span class="rv-rfid"><i class="fas fa-id-card"></i> RFID</span>
<i class="fas fa-id-card"></i> RFID @elseif($riwayat->metode_absen === 'Import_Mesin')
</span> <span class="rv-mesin"><i class="fas fa-desktop"></i> Mesin</span>
@elseif($riwayat->metode_absen == 'Import_Mesin')
<span style="background: #EDE9FE; color: #6B21A8; padding: 3px 8px; border-radius: 10px; font-size: 0.75rem; font-weight: 600;">
<i class="fas fa-desktop"></i> Mesin
</span>
@else @else
<span style="background: #E5E7EB; color: #374151; padding: 3px 8px; border-radius: 10px; font-size: 0.75rem; font-weight: 600;"> <span class="rv-manual"><i class="fas fa-hand-pointer"></i> Manual</span>
<i class="fas fa-hand-pointer"></i> Manual
</span>
@endif @endif
</td> </td>
<td style="text-align:center;">
<a href="{{ route('admin.riwayat-kegiatan.detail-santri', $riwayat->id_santri) }}"
class="btn-rv-history" title="Lihat seluruh riwayat {{ $riwayat->santri->nama_lengkap }}">
<i class="fas fa-chart-line"></i> Riwayat
</a>
</td>
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>
</table> </table>
@endforeach @endforeach
</div> </div>{{-- end rv-day-body --}}
</div> </div>{{-- end rv-day-group --}}
@endforeach @endforeach
<div class="pagination"> <div style="margin-top:14px;">
{!! $riwayats->appends(request()->query())->links('pagination::simple-bootstrap-4') !!} {!! $riwayats->appends(request()->query())->links('pagination::simple-bootstrap-4') !!}
</div> </div>
@else @else
<div class="empty-state"> <div class="rv-empty">
<i class="fas fa-inbox"></i> <i class="fas fa-inbox"></i>
<h3>Tidak Ada Riwayat</h3> <h3>Tidak Ada Data</h3>
<p>Tidak ada data absensi untuk periode <strong>{{ $periodeLabel }}</strong>.</p> <p>Tidak ada riwayat absensi untuk periode <strong>{{ $periodeLabel }}</strong>.</p>
@if(request()->hasAny(['id_santri','id_kelas','status','tanggal_spesifik']))
<p style="margin-top:8px; font-size:0.82rem;">
Coba
<a href="{{ route('admin.riwayat-kegiatan.show', $kegiatan->id) }}?{{ http_build_query(['mode'=>$mode,'dari'=>$dari,'sampai'=>$sampai,'tanggal'=>$tanggal]) }}"
style="color:var(--primary-color);">hapus filter</a>
untuk melihat semua data.
</p>
@endif
</div> </div>
@endif @endif
<script> <script>
function toggleDay(header) { function toggleDay(header) {
var body = header.nextElementSibling; var body = header.nextElementSibling;
var icon = header.querySelector('.toggle-icon'); var icon = header.querySelector('.rv-toggle');
if (body.style.display === 'none') { if (body.style.display === 'none') {
body.style.display = 'block'; body.style.display = 'block';
icon.classList.remove('collapsed'); icon.classList.remove('closed');
} else { } else {
body.style.display = 'none'; body.style.display = 'none';
icon.classList.add('collapsed'); icon.classList.add('closed');
} }
} }
</script> </script>

View File

@ -67,8 +67,6 @@
<p style="margin: 5px 0;"><strong>Sisa Kuota:</strong> <span id="sisaKuota" class="badge">-</span></p> <p style="margin: 5px 0;"><strong>Sisa Kuota:</strong> <span id="sisaKuota" class="badge">-</span></p>
</div> </div>
</div> </div>
{{-- Progress Bar Kuota --}}
<div style="margin-top: 15px;"> <div style="margin-top: 15px;">
<label style="font-size: 0.9rem; color: #7F8C8D; margin-bottom: 5px;">Penggunaan Kuota:</label> <label style="font-size: 0.9rem; color: #7F8C8D; margin-bottom: 5px;">Penggunaan Kuota:</label>
<div style="width: 100%; height: 20px; background: #E0F0EC; border-radius: 10px; overflow: hidden; position: relative;"> <div style="width: 100%; height: 20px; background: #E0F0EC; border-radius: 10px; overflow: hidden; position: relative;">
@ -76,10 +74,9 @@
</div> </div>
<small id="progressText" style="color: #7F8C8D; margin-top: 5px; display: block;">0% dari kuota terpakai</small> <small id="progressText" style="color: #7F8C8D; margin-top: 5px; display: block;">0% dari kuota terpakai</small>
</div> </div>
<div id="warningOverLimit" style="display: none; margin-top: 15px; padding: 12px; background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; color: #856404;"> <div id="warningOverLimit" style="display: none; margin-top: 15px; padding: 12px; background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; color: #856404;">
<i class="fas fa-exclamation-triangle"></i> <i class="fas fa-exclamation-triangle"></i>
<strong>⚠️ PERHATIAN:</strong> <span id="warningText"></span> <strong>PERHATIAN:</strong> <span id="warningText"></span>
</div> </div>
</div> </div>
@ -89,32 +86,22 @@
<i class="fas fa-calendar-alt form-icon"></i> <i class="fas fa-calendar-alt form-icon"></i>
Tanggal Pulang <span style="color: #dc3545;">*</span> Tanggal Pulang <span style="color: #dc3545;">*</span>
</label> </label>
<input type="date" <input type="date" name="tanggal_pulang" id="tanggal_pulang" class="form-control"
name="tanggal_pulang" value="{{ old('tanggal_pulang', date('Y-m-d')) }}" min="{{ date('Y-m-d') }}" required>
id="tanggal_pulang"
class="form-control"
value="{{ old('tanggal_pulang', date('Y-m-d')) }}"
min="{{ date('Y-m-d') }}"
required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="tanggal_kembali"> <label for="tanggal_kembali">
<i class="fas fa-calendar-check form-icon"></i> <i class="fas fa-calendar-check form-icon"></i>
Tanggal Kembali <span style="color: #dc3545;">*</span> Tanggal Kembali <span style="color: #dc3545;">*</span>
</label> </label>
<input type="date" <input type="date" name="tanggal_kembali" id="tanggal_kembali" class="form-control"
name="tanggal_kembali" value="{{ old('tanggal_kembali') }}" required>
id="tanggal_kembali"
class="form-control"
value="{{ old('tanggal_kembali') }}"
required>
</div> </div>
</div> </div>
{{-- Info Durasi Izin --}} {{-- Info Durasi Izin --}}
<div id="durasiInfo" style="display: none; background: #fff3e0; padding: 14px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #ff9800;"> <div id="durasiInfo" style="display: none; background: #fff3e0; padding: 14px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #ff9800;">
<h4 style="margin-top: 0; color: #2C3E50;">⏱️ Detail Durasi Izin</h4> <h4 style="margin-top: 0; color: #2C3E50;">Detail Durasi Izin</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 11px;"> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 11px;">
<div style="text-align: center; padding: 15px; background: white; border-radius: 8px;"> <div style="text-align: center; padding: 15px; background: white; border-radius: 8px;">
<div style="font-size: 0.85rem; color: #7F8C8D; margin-bottom: 5px;">Durasi Izin</div> <div style="font-size: 0.85rem; color: #7F8C8D; margin-bottom: 5px;">Durasi Izin</div>
@ -134,7 +121,7 @@ class="form-control"
</div> </div>
<div id="warningDurasi" style="display: none; margin-top: 15px; padding: 12px; background: #ffebee; border: 1px solid #ffcdd2; border-radius: 6px; color: #c62828;"> <div id="warningDurasi" style="display: none; margin-top: 15px; padding: 12px; background: #ffebee; border: 1px solid #ffcdd2; border-radius: 6px; color: #c62828;">
<i class="fas fa-exclamation-circle"></i> <i class="fas fa-exclamation-circle"></i>
<strong>⚠️ PERHATIAN:</strong> <span id="warningDurasiMessage"></span> <strong>PERHATIAN:</strong> <span id="warningDurasiMessage"></span>
</div> </div>
</div> </div>
@ -143,12 +130,8 @@ class="form-control"
<i class="fas fa-comment-alt form-icon"></i> <i class="fas fa-comment-alt form-icon"></i>
Alasan Kepulangan <span style="color: #dc3545;">*</span> Alasan Kepulangan <span style="color: #dc3545;">*</span>
</label> </label>
<textarea name="alasan" <textarea name="alasan" id="alasan" class="form-control" rows="4"
id="alasan" placeholder="Jelaskan alasan kepulangan" required>{{ old('alasan') }}</textarea>
class="form-control"
rows="4"
placeholder="Jelaskan alasan kepulangan"
required>{{ old('alasan') }}</textarea>
<small style="color: #7F8C8D; margin-top: 5px; display: block;"> <small style="color: #7F8C8D; margin-top: 5px; display: block;">
<span id="charCount">0</span>/500 karakter <span id="charCount">0</span>/500 karakter
</small> </small>
@ -172,16 +155,13 @@ class="form-control"
<div class="modal fade" id="overLimitModal" tabindex="-1" style="display: none;"> <div class="modal fade" id="overLimitModal" tabindex="-1" style="display: none;">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;"> <div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;">
<div style="margin-bottom: 14px;"> <div style="margin-bottom: 14px;"><h3 style="margin: 0; color: #2C3E50;">Konfirmasi Izin Melebihi Batas</h3></div>
<h3 style="margin: 0; color: #2C3E50;">⚠️ Konfirmasi Izin Melebihi Batas</h3>
</div>
<div style="padding: 15px; background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; margin-bottom: 15px;"> <div style="padding: 15px; background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; margin-bottom: 15px;">
<i class="fas fa-exclamation-triangle" style="font-size: 2rem; color: #856404; margin-bottom: 10px;"></i> <i class="fas fa-exclamation-triangle" style="font-size: 2rem; color: #856404; margin-bottom: 10px;"></i>
<h4 style="margin: 10px 0; color: #856404;">Peringatan!</h4> <h4 style="margin: 10px 0; color: #856404;">Peringatan!</h4>
<p id="overLimitMessage" style="margin: 0; color: #856404;"></p> <p id="overLimitMessage" style="margin: 0; color: #856404;"></p>
</div> </div>
<p style="margin: 15px 0;">Izin tetap bisa diproses, tetapi santri ini akan <strong>melebihi kuota maksimal</strong>.</p> <p style="margin: 15px 0;">Izin tetap bisa diproses, tetapi santri ini akan <strong>melebihi kuota maksimal</strong>.</p>
<p style="margin: 15px 0; color: #7F8C8D; font-size: 0.9rem;">Apakah Anda yakin ingin melanjutkan pengajuan izin ini?</p>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;"> <div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;">
<button type="button" class="btn btn-secondary" onclick="closeModal('overLimitModal')">Batal</button> <button type="button" class="btn btn-secondary" onclick="closeModal('overLimitModal')">Batal</button>
<button type="button" class="btn btn-warning" id="confirmOverLimit" style="background: #ff9800; border-color: #ff9800;"> <button type="button" class="btn btn-warning" id="confirmOverLimit" style="background: #ff9800; border-color: #ff9800;">
@ -199,14 +179,18 @@ class="form-control"
.badge { display: inline-block; padding: 4px 10px; border-radius: 4px; font-size: 0.9rem; font-weight: 600; } .badge { display: inline-block; padding: 4px 10px; border-radius: 4px; font-size: 0.9rem; font-weight: 600; }
</style> </style>
{{-- FIX: Definisikan URL API dari Laravel, bukan hardcode --}}
<script>
const KEPULANGAN_API_URL = "{{ url('admin/kepulangan/api/santri') }}";
const KUOTA_MAKSIMAL = {{ $settings->kuota_maksimal }};
</script>
<script> <script>
let currentSantriData = null; let currentSantriData = null;
let isOverLimit = false; let isOverLimit = false;
// Load santri data when selected
document.getElementById('id_santri').addEventListener('change', function() { document.getElementById('id_santri').addEventListener('change', function() {
const santriId = this.value; const santriId = this.value;
if (!santriId) { if (!santriId) {
document.getElementById('santriInfo').style.display = 'none'; document.getElementById('santriInfo').style.display = 'none';
currentSantriData = null; currentSantriData = null;
@ -216,16 +200,12 @@ class="form-control"
const infoDiv = document.getElementById('santriInfo'); const infoDiv = document.getElementById('santriInfo');
infoDiv.style.display = 'block'; infoDiv.style.display = 'block';
// Show loading state
infoDiv.innerHTML = '<div style="text-align: center; padding: 14px;"><i class="fas fa-spinner fa-spin"></i> Memuat data santri...</div>'; infoDiv.innerHTML = '<div style="text-align: center; padding: 14px;"><i class="fas fa-spinner fa-spin"></i> Memuat data santri...</div>';
// PERBAIKAN: Proper error handling untuk API // ✅ FIX: pakai KEPULANGAN_API_URL dari Laravel
fetch(`/admin/kepulangan/api/santri/${santriId}`) fetch(`${KEPULANGAN_API_URL}/${santriId}`)
.then(response => { .then(response => {
if (!response.ok) { if (!response.ok) throw new Error('Network response was not ok');
throw new Error('Network response was not ok');
}
return response.json(); return response.json();
}) })
.then(data => { .then(data => {
@ -243,70 +223,52 @@ class="form-control"
}); });
}); });
// PERBAIKAN: Function untuk show error
function showError(message) { function showError(message) {
const infoDiv = document.getElementById('santriInfo'); const infoDiv = document.getElementById('santriInfo');
infoDiv.innerHTML = ` infoDiv.innerHTML = `
<div style="padding: 15px; background: #ffebee; border: 1px solid #ffcdd2; border-radius: 6px; color: #c62828;"> <div style="padding: 15px; background: #ffebee; border: 1px solid #ffcdd2; border-radius: 6px; color: #c62828;">
<i class="fas fa-exclamation-circle"></i> <i class="fas fa-exclamation-circle"></i> <strong>Error:</strong> ${message}
<strong>Error:</strong> ${message} </div>`;
</div>
`;
currentSantriData = null; currentSantriData = null;
} }
function updateSantriInfo(data) { function updateSantriInfo(data) {
const santri = data.santri; const santri = data.santri;
const kuota = data.penggunaan_izin; const kuota = data.penggunaan_izin;
// Rebuild HTML structure
const infoDiv = document.getElementById('santriInfo'); const infoDiv = document.getElementById('santriInfo');
infoDiv.innerHTML = ` infoDiv.innerHTML = `
<h4 style="margin-top: 0; color: #2C3E50;">Informasi Santri & Kuota</h4> <h4 style="margin-top: 0; color: #2C3E50;">Informasi Santri & Kuota</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px;"> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px;">
<div> <div>
<p style="margin: 5px 0;"><strong>Nama:</strong> <span id="santriNama">${santri.nama_lengkap}</span></p> <p style="margin: 5px 0;"><strong>Nama:</strong> ${santri.nama_lengkap}</p>
<p style="margin: 5px 0;"><strong>Kelas:</strong> <span id="santriKelas">${santri.kelas}</span></p> <p style="margin: 5px 0;"><strong>Kelas:</strong> ${santri.kelas}</p>
<p style="margin: 5px 0;"><strong>Periode:</strong> <span id="santriPeriode">${kuota.periode_mulai} - ${kuota.periode_akhir}</span></p> <p style="margin: 5px 0;"><strong>Periode:</strong> ${kuota.periode_mulai} - ${kuota.periode_akhir}</p>
</div> </div>
<div> <div>
<p style="margin: 5px 0;"><strong>Kuota Maksimal:</strong> <span id="kuotaMaksimal">${kuota.kuota_maksimal} hari</span></p> <p style="margin: 5px 0;"><strong>Kuota Maksimal:</strong> ${kuota.kuota_maksimal} hari</p>
<p style="margin: 5px 0;"><strong>Total Terpakai:</strong> <span id="totalTerpakai" class="badge" style="background: ${getBadgeColor(kuota.badge_color)}; color: ${kuota.badge_color === 'warning' ? '#000' : 'white'};">${kuota.total_terpakai} hari</span></p> <p style="margin: 5px 0;"><strong>Total Terpakai:</strong> <span style="display:inline-block;background:${getBadgeColor(kuota.badge_color)};color:${kuota.badge_color==='warning'?'#000':'white'};padding:4px 10px;border-radius:4px;font-weight:600;">${kuota.total_terpakai} hari</span></p>
<p style="margin: 5px 0;"><strong>Sisa Kuota:</strong> <span id="sisaKuota" class="badge" style="background: ${getBadgeColor(kuota.badge_color)}; color: ${kuota.badge_color === 'warning' ? '#000' : 'white'};">${kuota.sisa_kuota} hari</span></p> <p style="margin: 5px 0;"><strong>Sisa Kuota:</strong> <span style="display:inline-block;background:${getBadgeColor(kuota.badge_color)};color:${kuota.badge_color==='warning'?'#000':'white'};padding:4px 10px;border-radius:4px;font-weight:600;">${kuota.sisa_kuota} hari</span></p>
</div> </div>
</div> </div>
<div style="margin-top: 15px;"> <div style="margin-top: 15px;">
<label style="font-size: 0.9rem; color: #7F8C8D; margin-bottom: 5px;">Penggunaan Kuota:</label> <label style="font-size: 0.9rem; color: #7F8C8D; margin-bottom: 5px;">Penggunaan Kuota:</label>
<div style="width: 100%; height: 20px; background: #E0F0EC; border-radius: 10px; overflow: hidden; position: relative;"> <div style="width: 100%; height: 20px; background: #E0F0EC; border-radius: 10px; overflow: hidden;">
<div id="progressBar" style="height: 100%; width: ${Math.min(100, kuota.persentase)}%; background: ${getProgressColor(kuota.persentase)}; transition: all 0.3s ease; display: flex; align-items: center; justify-content: center; color: white; font-size: 0.75rem; font-weight: 600;">${kuota.persentase}%</div> <div style="height:100%;width:${Math.min(100,kuota.persentase)}%;background:${getProgressColor(kuota.persentase)};display:flex;align-items:center;justify-content:center;color:white;font-size:0.75rem;font-weight:600;">${kuota.persentase}%</div>
</div> </div>
<small id="progressText" style="color: #7F8C8D; margin-top: 5px; display: block;">${kuota.persentase}% dari kuota terpakai</small> <small style="color: #7F8C8D; margin-top: 5px; display: block;">${kuota.persentase}% dari kuota terpakai</small>
</div> </div>
<div style="display:${kuota.status==='melebihi'?'block':'none'};margin-top:15px;padding:12px;background:#fff3cd;border:1px solid #ffeaa7;border-radius:6px;color:#856404;">
<div id="warningOverLimit" style="display: ${kuota.status === 'melebihi' ? 'block' : 'none'}; margin-top: 15px; padding: 12px; background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; color: #856404;"> <i class="fas fa-exclamation-triangle"></i> <strong>PERHATIAN:</strong> Santri ini sudah melebihi kuota ${kuota.kuota_maksimal} hari! Total terpakai: ${kuota.total_terpakai} hari.
<i class="fas fa-exclamation-triangle"></i> </div>`;
<strong>⚠️ PERHATIAN:</strong> <span id="warningText">Santri ini sudah melebihi kuota ${kuota.kuota_maksimal} hari per tahun! Total terpakai: ${kuota.total_terpakai} hari.</span>
</div>
`;
} }
function getBadgeColor(badge) { function getBadgeColor(badge) {
const colors = { return { 'success': '#28a745', 'warning': '#ffc107', 'danger': '#dc3545' }[badge] || '#6c757d';
'success': '#28a745', }
'warning': '#ffc107', function getProgressColor(p) {
'danger': '#dc3545' return p >= 100 ? '#dc3545' : p >= 80 ? '#ffc107' : '#28a745';
};
return colors[badge] || '#6c757d';
} }
function getProgressColor(persentase) {
if (persentase >= 100) return '#dc3545';
if (persentase >= 80) return '#ffc107';
return '#28a745';
}
// Calculate durasi when dates change
document.getElementById('tanggal_pulang').addEventListener('change', calculateDurasi); document.getElementById('tanggal_pulang').addEventListener('change', calculateDurasi);
document.getElementById('tanggal_kembali').addEventListener('change', calculateDurasi); document.getElementById('tanggal_kembali').addEventListener('change', calculateDurasi);
@ -314,168 +276,96 @@ function calculateDurasi() {
const tanggalPulang = document.getElementById('tanggal_pulang').value; const tanggalPulang = document.getElementById('tanggal_pulang').value;
const tanggalKembali = document.getElementById('tanggal_kembali').value; const tanggalKembali = document.getElementById('tanggal_kembali').value;
const durasiInfoDiv = document.getElementById('durasiInfo'); const durasiInfoDiv = document.getElementById('durasiInfo');
if (!tanggalPulang || !tanggalKembali) { durasiInfoDiv.style.display = 'none'; return; }
if (!tanggalPulang || !tanggalKembali) {
durasiInfoDiv.style.display = 'none';
return;
}
const startDate = new Date(tanggalPulang); const startDate = new Date(tanggalPulang);
const endDate = new Date(tanggalKembali); const endDate = new Date(tanggalKembali);
if (endDate <= startDate) { durasiInfoDiv.style.display = 'none'; return; }
if (endDate <= startDate) { const diffDays = Math.ceil(Math.abs(endDate - startDate) / (1000 * 60 * 60 * 24)) + 1;
durasiInfoDiv.style.display = 'none';
return;
}
// Hitung durasi (termasuk hari pertama)
const diffTime = Math.abs(endDate - startDate);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1;
durasiInfoDiv.style.display = 'block'; durasiInfoDiv.style.display = 'block';
// Update durasi
document.getElementById('durasiHari').textContent = diffDays; document.getElementById('durasiHari').textContent = diffDays;
let totalSetelah = diffDays; let totalSetelah = diffDays;
let sisaSetelah = {{ $settings->kuota_maksimal }} - diffDays; let sisaSetelah = KUOTA_MAKSIMAL - diffDays;
let showWarning = false; let showWarning = false, warningMessage = '';
let warningMessage = '';
if (currentSantriData) { if (currentSantriData) {
const currentUsage = currentSantriData.penggunaan_izin.total_terpakai; const currentUsage = currentSantriData.penggunaan_izin.total_terpakai;
const kuotaMaks = currentSantriData.penggunaan_izin.kuota_maksimal; const kuotaMaks = currentSantriData.penggunaan_izin.kuota_maksimal;
totalSetelah = currentUsage + diffDays; totalSetelah = currentUsage + diffDays;
sisaSetelah = kuotaMaks - totalSetelah; sisaSetelah = kuotaMaks - totalSetelah;
// Update nilai
document.getElementById('totalSetelahIzin').textContent = totalSetelah; document.getElementById('totalSetelahIzin').textContent = totalSetelah;
document.getElementById('sisaKuotaSetelah').textContent = Math.max(0, sisaSetelah); document.getElementById('sisaKuotaSetelah').textContent = Math.max(0, sisaSetelah);
// Ubah warna berdasarkan status
const totalSetelahEl = document.getElementById('totalSetelahIzin');
const sisaSetelahEl = document.getElementById('sisaKuotaSetelah');
if (totalSetelah > kuotaMaks) { if (totalSetelah > kuotaMaks) {
totalSetelahEl.style.color = '#dc3545'; document.getElementById('totalSetelahIzin').style.color = '#dc3545';
sisaSetelahEl.style.color = '#dc3545'; document.getElementById('sisaKuotaSetelah').style.color = '#dc3545';
showWarning = true; showWarning = true;
warningMessage = `Izin ini akan melebihi batas ${kuotaMaks} hari per tahun (Total setelah izin: ${totalSetelah} hari, Kelebihan: ${totalSetelah - kuotaMaks} hari)`; warningMessage = `Izin ini akan melebihi batas ${kuotaMaks} hari (Total setelah izin: ${totalSetelah} hari, Kelebihan: ${totalSetelah - kuotaMaks} hari)`;
isOverLimit = true; isOverLimit = true;
} else if (totalSetelah >= kuotaMaks * 0.8) { } else if (totalSetelah >= kuotaMaks * 0.8) {
totalSetelahEl.style.color = '#ff9800'; document.getElementById('totalSetelahIzin').style.color = '#ff9800';
sisaSetelahEl.style.color = '#ff9800'; document.getElementById('sisaKuotaSetelah').style.color = '#ff9800';
showWarning = true; showWarning = true;
warningMessage = `Perhatian: Kuota hampir habis! Sisa kuota setelah izin ini hanya ${sisaSetelah} hari.`; warningMessage = `Kuota hampir habis! Sisa kuota setelah izin ini hanya ${sisaSetelah} hari.`;
isOverLimit = false; isOverLimit = false;
} else { } else {
totalSetelahEl.style.color = '#2196f3'; document.getElementById('totalSetelahIzin').style.color = '#2196f3';
sisaSetelahEl.style.color = '#28a745'; document.getElementById('sisaKuotaSetelah').style.color = '#28a745';
showWarning = false; showWarning = false; isOverLimit = false;
isOverLimit = false;
} }
} }
// Tampilkan warning durasi
const warningDiv = document.getElementById('warningDurasi'); const warningDiv = document.getElementById('warningDurasi');
const warningMessageEl = document.getElementById('warningDurasiMessage'); warningDiv.style.display = showWarning ? 'block' : 'none';
if (showWarning) { if (showWarning) document.getElementById('warningDurasiMessage').textContent = warningMessage;
warningDiv.style.display = 'block';
warningMessageEl.textContent = warningMessage;
} else {
warningDiv.style.display = 'none';
}
} }
// Character counter (PERBAIKAN: Tidak ada validasi minimal)
document.getElementById('alasan').addEventListener('input', function() { document.getElementById('alasan').addEventListener('input', function() {
const current = this.value.length;
const counter = document.getElementById('charCount'); const counter = document.getElementById('charCount');
counter.textContent = current; counter.textContent = this.value.length;
counter.style.color = this.value.length > 500 ? 'red' : '#7F8C8D';
if (current > 500) {
counter.style.color = 'red';
} else {
counter.style.color = '#7F8C8D';
}
}); });
// Form submission with over limit confirmation
document.getElementById('kepulanganForm').addEventListener('submit', function(e) { document.getElementById('kepulanganForm').addEventListener('submit', function(e) {
if (isOverLimit) { if (isOverLimit) {
e.preventDefault(); e.preventDefault();
const msg = document.getElementById('warningDurasiMessage')?.textContent || 'Izin ini akan melebihi batas kuota';
const warningMessageEl = document.getElementById('warningDurasiMessage'); document.getElementById('overLimitMessage').textContent = msg;
const message = warningMessageEl ? warningMessageEl.textContent : 'Izin ini akan melebihi batas kuota per tahun';
document.getElementById('overLimitMessage').textContent = message;
document.getElementById('overLimitModal').style.display = 'flex'; document.getElementById('overLimitModal').style.display = 'flex';
} }
}); });
// Confirm over limit submission
document.getElementById('confirmOverLimit').addEventListener('click', function() { document.getElementById('confirmOverLimit').addEventListener('click', function() {
closeModal('overLimitModal'); closeModal('overLimitModal');
isOverLimit = false; isOverLimit = false;
document.getElementById('kepulanganForm').submit(); document.getElementById('kepulanganForm').submit();
}); });
// Auto-set minimum tanggal_kembali
document.getElementById('tanggal_pulang').addEventListener('change', function() { document.getElementById('tanggal_pulang').addEventListener('change', function() {
const pulangDate = new Date(this.value); const pulangDate = new Date(this.value);
pulangDate.setDate(pulangDate.getDate() + 1); pulangDate.setDate(pulangDate.getDate() + 1);
const minKembali = pulangDate.toISOString().split('T')[0];
const minKembaliDate = pulangDate.toISOString().split('T')[0]; document.getElementById('tanggal_kembali').min = minKembali;
document.getElementById('tanggal_kembali').min = minKembaliDate;
const currentKembali = document.getElementById('tanggal_kembali').value; const currentKembali = document.getElementById('tanggal_kembali').value;
if (currentKembali && currentKembali <= this.value) { if (currentKembali && currentKembali <= this.value) document.getElementById('tanggal_kembali').value = minKembali;
document.getElementById('tanggal_kembali').value = minKembaliDate;
}
}); });
// Initialize
document.addEventListener('DOMContentLoaded', function() {
const today = new Date().toISOString().split('T')[0];
document.getElementById('tanggal_pulang').min = today;
const alasanField = document.getElementById('alasan');
document.getElementById('charCount').textContent = alasanField.value.length;
calculateDurasi();
});
// Form reset handler
document.querySelector('button[type="reset"]').addEventListener('click', function() { document.querySelector('button[type="reset"]').addEventListener('click', function() {
setTimeout(() => { setTimeout(() => {
document.getElementById('santriInfo').style.display = 'none'; document.getElementById('santriInfo').style.display = 'none';
document.getElementById('durasiInfo').style.display = 'none'; document.getElementById('durasiInfo').style.display = 'none';
currentSantriData = null; currentSantriData = null; isOverLimit = false;
isOverLimit = false;
document.getElementById('charCount').textContent = '0'; document.getElementById('charCount').textContent = '0';
}, 100); }, 100);
}); });
// Helper functions function closeModal(modalId) { document.getElementById(modalId).style.display = 'none'; }
function closeModal(modalId) {
document.getElementById(modalId).style.display = 'none';
}
// Close modal on ESC document.addEventListener('DOMContentLoaded', function() {
document.addEventListener('keydown', function(e) { document.getElementById('tanggal_pulang').min = new Date().toISOString().split('T')[0];
if (e.key === 'Escape') { document.getElementById('charCount').textContent = document.getElementById('alasan').value.length;
document.querySelectorAll('.modal.fade').forEach(modal => modal.style.display = 'none'); calculateDurasi();
}
}); });
// Close modal on outside click document.addEventListener('keydown', e => { if (e.key === 'Escape') document.querySelectorAll('.modal.fade').forEach(m => m.style.display = 'none'); });
document.querySelectorAll('.modal.fade').forEach(modal => { document.querySelectorAll('.modal.fade').forEach(modal => {
modal.addEventListener('click', function(e) { modal.addEventListener('click', function(e) { if (e.target === this) this.style.display = 'none'; });
if (e.target === this) {
this.style.display = 'none';
}
});
}); });
</script> </script>
@endsection @endsection

View File

@ -104,8 +104,6 @@
<a href="{{ route('admin.kepulangan.create') }}" class="btn btn-primary"> <a href="{{ route('admin.kepulangan.create') }}" class="btn btn-primary">
<i class="fas fa-plus"></i> Tambah Izin Kepulangan <i class="fas fa-plus"></i> Tambah Izin Kepulangan
</a> </a>
{{-- TOMBOL PENGAJUAN MOBILE (BARU) --}}
<a href="{{ route('admin.kepulangan.pengajuan') }}" class="btn btn-warning"> <a href="{{ route('admin.kepulangan.pengajuan') }}" class="btn btn-warning">
<i class="fas fa-mobile-alt"></i> Pengajuan izin <i class="fas fa-mobile-alt"></i> Pengajuan izin
@if($pendingPengajuan > 0) @if($pendingPengajuan > 0)
@ -121,14 +119,8 @@
<form method="GET" action="{{ route('admin.kepulangan.index') }}" id="filterForm" style="margin-bottom: 14px;"> <form method="GET" action="{{ route('admin.kepulangan.index') }}" id="filterForm" style="margin-bottom: 14px;">
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 11px; align-items: end;"> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 11px; align-items: end;">
<div class="form-group" style="margin-bottom: 0;"> <div class="form-group" style="margin-bottom: 0;">
<input type="text" <input type="text" name="search" class="form-control" placeholder="Cari nama, ID, atau alasan..." value="{{ request('search') }}" id="searchInput">
name="search"
class="form-control"
placeholder="Cari nama, ID, atau alasan..."
value="{{ request('search') }}"
id="searchInput">
</div> </div>
<div class="form-group" style="margin-bottom: 0;"> <div class="form-group" style="margin-bottom: 0;">
<select name="status" class="form-control" onchange="document.getElementById('filterForm').submit();"> <select name="status" class="form-control" onchange="document.getElementById('filterForm').submit();">
<option value="">Semua Status</option> <option value="">Semua Status</option>
@ -138,18 +130,14 @@ class="form-control"
<option value="Selesai" {{ request('status') == 'Selesai' ? 'selected' : '' }}>Selesai</option> <option value="Selesai" {{ request('status') == 'Selesai' ? 'selected' : '' }}>Selesai</option>
</select> </select>
</div> </div>
<div class="form-group" style="margin-bottom: 0;"> <div class="form-group" style="margin-bottom: 0;">
<select name="tahun" class="form-control" onchange="document.getElementById('filterForm').submit();"> <select name="tahun" class="form-control" onchange="document.getElementById('filterForm').submit();">
<option value="">Semua Tahun</option> <option value="">Semua Tahun</option>
@foreach($tahunList as $tahun) @foreach($tahunList as $tahun)
<option value="{{ $tahun }}" {{ request('tahun') == $tahun ? 'selected' : '' }}> <option value="{{ $tahun }}" {{ request('tahun') == $tahun ? 'selected' : '' }}>{{ $tahun }}</option>
{{ $tahun }}
</option>
@endforeach @endforeach
</select> </select>
</div> </div>
<div class="form-group" style="margin-bottom: 0;"> <div class="form-group" style="margin-bottom: 0;">
<select name="bulan" class="form-control" onchange="document.getElementById('filterForm').submit();"> <select name="bulan" class="form-control" onchange="document.getElementById('filterForm').submit();">
<option value="">Semua Bulan</option> <option value="">Semua Bulan</option>
@ -160,19 +148,14 @@ class="form-control"
@endfor @endfor
</select> </select>
</div> </div>
<div style="display: flex; gap: 10px;"> <div style="display: flex; gap: 10px;">
<button type="submit" class="btn btn-primary"> <button type="submit" class="btn btn-primary"><i class="fas fa-search"></i> Filter</button>
<i class="fas fa-search"></i> Filter <a href="{{ route('admin.kepulangan.index') }}" class="btn btn-secondary"><i class="fas fa-redo"></i> Reset</a>
</button>
<a href="{{ route('admin.kepulangan.index') }}" class="btn btn-secondary">
<i class="fas fa-redo"></i> Reset
</a>
</div> </div>
</div> </div>
</form> </form>
{{-- Data Table (SAMA SEPERTI SEBELUMNYA) --}} {{-- Data Table --}}
<div style="overflow-x: auto;"> <div style="overflow-x: auto;">
<div class="table-wrapper"> <div class="table-wrapper">
<table class="data-table"> <table class="data-table">
@ -199,8 +182,7 @@ class="form-control"
<td> <td>
<strong>{{ $item->id_kepulangan }}</strong> <strong>{{ $item->id_kepulangan }}</strong>
@if($isOverLimit) @if($isOverLimit)
<span style="display: inline-block; background: #dc3545; color: white; padding: 2px 6px; border-radius: 4px; font-size: 0.75rem; margin-left: 5px; animation: pulse 2s infinite;" <span style="display: inline-block; background: #dc3545; color: white; padding: 2px 6px; border-radius: 4px; font-size: 0.75rem; margin-left: 5px; animation: pulse 2s infinite;" title="Over Limit: {{ $totalHariTerpakai }} hari">
title="Over Limit: {{ $totalHariTerpakai }} hari">
<i class="fas fa-exclamation-triangle"></i> <i class="fas fa-exclamation-triangle"></i>
</span> </span>
@endif @endif
@ -208,9 +190,7 @@ class="form-control"
<td> <td>
<div> <div>
<strong>{{ $item->santri->nama_lengkap ?? 'N/A' }}</strong><br> <strong>{{ $item->santri->nama_lengkap ?? 'N/A' }}</strong><br>
<small style="color: #7F8C8D;"> <small style="color: #7F8C8D;">{{ $item->santri->id_santri ?? '' }} | {{ $item->santri->kelas ?? '' }}</small>
{{ $item->santri->id_santri ?? '' }} | {{ $item->santri->kelas ?? '' }}
</small>
</div> </div>
</td> </td>
<td>{{ $item->tanggal_pulang_formatted }}</td> <td>{{ $item->tanggal_pulang_formatted }}</td>
@ -224,11 +204,7 @@ class="form-control"
@php @php
$kuotaSantri = \App\Models\Kepulangan::getSisaKuotaSantri($item->id_santri); $kuotaSantri = \App\Models\Kepulangan::getSisaKuotaSantri($item->id_santri);
$badgeColor = $kuotaSantri['badge_color']; $badgeColor = $kuotaSantri['badge_color'];
$badgeColors = [ $badgeColors = ['success' => '#28a745', 'warning' => '#ffc107', 'danger' => '#dc3545'];
'success' => '#28a745',
'warning' => '#ffc107',
'danger' => '#dc3545'
];
$bgColor = $badgeColors[$badgeColor] ?? '#6c757d'; $bgColor = $badgeColors[$badgeColor] ?? '#6c757d';
$textColor = $badgeColor == 'warning' ? '#000' : '#fff'; $textColor = $badgeColor == 'warning' ? '#000' : '#fff';
@endphp @endphp
@ -267,49 +243,32 @@ class="form-control"
</td> </td>
<td class="text-center"> <td class="text-center">
<div style="display: flex; gap: 5px; justify-content: center; flex-wrap: wrap;"> <div style="display: flex; gap: 5px; justify-content: center; flex-wrap: wrap;">
<a href="{{ route('admin.kepulangan.show', $item->id_kepulangan) }}" <a href="{{ route('admin.kepulangan.show', $item->id_kepulangan) }}" class="btn btn-sm btn-primary" title="Detail">
class="btn btn-sm btn-primary" title="Detail">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
</a> </a>
@if($item->status == 'Menunggu') @if($item->status == 'Menunggu')
<a href="{{ route('admin.kepulangan.edit', $item->id_kepulangan) }}" <a href="{{ route('admin.kepulangan.edit', $item->id_kepulangan) }}" class="btn btn-sm btn-warning" title="Edit">
class="btn btn-sm btn-warning" title="Edit">
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
</a> </a>
<button type="button" <button type="button" class="btn btn-sm btn-success" onclick="approveKepulangan('{{ $item->id_kepulangan }}')" title="Setujui">
class="btn btn-sm btn-success"
onclick="approveKepulangan('{{ $item->id_kepulangan }}')"
title="Setujui">
<i class="fas fa-check"></i> <i class="fas fa-check"></i>
</button> </button>
<button type="button" <button type="button" class="btn btn-sm btn-danger" onclick="rejectKepulangan('{{ $item->id_kepulangan }}')" title="Tolak">
class="btn btn-sm btn-danger"
onclick="rejectKepulangan('{{ $item->id_kepulangan }}')"
title="Tolak">
<i class="fas fa-times"></i> <i class="fas fa-times"></i>
</button> </button>
@endif @endif
@if($item->status == 'Disetujui') @if($item->status == 'Disetujui')
<a href="{{ route('admin.kepulangan.print', $item->id_kepulangan) }}" <a href="{{ route('admin.kepulangan.print', $item->id_kepulangan) }}" class="btn btn-sm btn-secondary" target="_blank" title="Cetak Surat">
class="btn btn-sm btn-secondary"
target="_blank" title="Cetak Surat">
<i class="fas fa-print"></i> <i class="fas fa-print"></i>
</a> </a>
<button type="button" <button type="button" class="btn btn-sm btn-success"
class="btn btn-sm btn-success"
onclick="completeKepulangan('{{ $item->id_kepulangan }}', '{{ $item->santri->nama_lengkap }}', '{{ $item->tanggal_pulang->format('Y-m-d') }}', '{{ $item->tanggal_kembali->format('Y-m-d') }}', {{ $item->durasi_izin }})" onclick="completeKepulangan('{{ $item->id_kepulangan }}', '{{ $item->santri->nama_lengkap }}', '{{ $item->tanggal_pulang->format('Y-m-d') }}', '{{ $item->tanggal_kembali->format('Y-m-d') }}', {{ $item->durasi_izin }})"
title="Selesaikan"> title="Selesaikan">
<i class="fas fa-check-double"></i> <i class="fas fa-check-double"></i>
</button> </button>
@endif @endif
@if(in_array($item->status, ['Menunggu', 'Ditolak', 'Selesai'])) @if(in_array($item->status, ['Menunggu', 'Ditolak', 'Selesai']))
<button type="button" <button type="button" class="btn btn-sm btn-danger" onclick="deleteKepulangan('{{ $item->id_kepulangan }}')" title="Hapus">
class="btn btn-sm btn-danger"
onclick="deleteKepulangan('{{ $item->id_kepulangan }}')"
title="Hapus">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
</button> </button>
@endif @endif
@ -332,13 +291,8 @@ class="btn btn-sm btn-danger"
{{-- Pagination --}} {{-- Pagination --}}
@if($kepulangan->hasPages()) @if($kepulangan->hasPages())
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 14px; flex-wrap: wrap; gap: 11px;"> <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 14px; flex-wrap: wrap; gap: 11px;">
<div> <div>Menampilkan {{ $kepulangan->firstItem() ?? 0 }} - {{ $kepulangan->lastItem() ?? 0 }} dari {{ $kepulangan->total() }} data</div>
Menampilkan {{ $kepulangan->firstItem() ?? 0 }} - {{ $kepulangan->lastItem() ?? 0 }} <div>{{ $kepulangan->appends(request()->query())->links() }}</div>
dari {{ $kepulangan->total() }} data
</div>
<div>
{{ $kepulangan->appends(request()->query())->links() }}
</div>
</div> </div>
@endif @endif
</div> </div>
@ -349,19 +303,14 @@ class="btn btn-sm btn-danger"
<div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;"> <div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;">
<form id="approveForm"> <form id="approveForm">
@csrf @csrf
<div style="margin-bottom: 14px;"> <div style="margin-bottom: 14px;"><h3 style="margin: 0; color: #2C3E50;">Setujui Izin Kepulangan</h3></div>
<h3 style="margin: 0; color: #2C3E50;">Setujui Izin Kepulangan</h3>
</div>
<div class="form-group"> <div class="form-group">
<label>Catatan (Opsional):</label> <label>Catatan (Opsional):</label>
<textarea name="catatan" class="form-control" rows="3" <textarea name="catatan" class="form-control" rows="3" placeholder="Tambahkan catatan untuk persetujuan ini..."></textarea>
placeholder="Tambahkan catatan untuk persetujuan ini..."></textarea>
</div> </div>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;"> <div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;">
<button type="button" class="btn btn-secondary" onclick="closeModal('approveModal')">Batal</button> <button type="button" class="btn btn-secondary" onclick="closeModal('approveModal')">Batal</button>
<button type="submit" class="btn btn-success"> <button type="submit" class="btn btn-success"><i class="fas fa-check"></i> Setujui</button>
<i class="fas fa-check"></i> Setujui
</button>
</div> </div>
</form> </form>
</div> </div>
@ -374,19 +323,14 @@ class="btn btn-sm btn-danger"
<div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;"> <div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;">
<form id="rejectForm"> <form id="rejectForm">
@csrf @csrf
<div style="margin-bottom: 14px;"> <div style="margin-bottom: 14px;"><h3 style="margin: 0; color: #2C3E50;">Tolak Izin Kepulangan</h3></div>
<h3 style="margin: 0; color: #2C3E50;">Tolak Izin Kepulangan</h3>
</div>
<div class="form-group"> <div class="form-group">
<label>Alasan Penolakan: <span style="color: #dc3545;">*</span></label> <label>Alasan Penolakan: <span style="color: #dc3545;">*</span></label>
<textarea name="alasan_penolakan" class="form-control" rows="3" <textarea name="alasan_penolakan" class="form-control" rows="3" placeholder="Jelaskan alasan penolakan..." required></textarea>
placeholder="Jelaskan alasan penolakan..." required></textarea>
</div> </div>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;"> <div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;">
<button type="button" class="btn btn-secondary" onclick="closeModal('rejectModal')">Batal</button> <button type="button" class="btn btn-secondary" onclick="closeModal('rejectModal')">Batal</button>
<button type="submit" class="btn btn-danger"> <button type="submit" class="btn btn-danger"><i class="fas fa-times"></i> Tolak</button>
<i class="fas fa-times"></i> Tolak
</button>
</div> </div>
</form> </form>
</div> </div>
@ -397,34 +341,26 @@ class="btn btn-sm btn-danger"
<div class="modal fade" id="deleteModal" tabindex="-1" style="display: none;"> <div class="modal fade" id="deleteModal" tabindex="-1" style="display: none;">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;"> <div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;">
<div style="margin-bottom: 14px;"> <div style="margin-bottom: 14px;"><h3 style="margin: 0; color: #2C3E50;">Konfirmasi Hapus</h3></div>
<h3 style="margin: 0; color: #2C3E50;">Konfirmasi Hapus</h3>
</div>
<p>Apakah Anda yakin ingin menghapus data kepulangan ini?</p> <p>Apakah Anda yakin ingin menghapus data kepulangan ini?</p>
<p style="color: #dc3545; font-size: 0.9rem;">Data yang sudah dihapus tidak dapat dikembalikan.</p> <p style="color: #dc3545; font-size: 0.9rem;">Data yang sudah dihapus tidak dapat dikembalikan.</p>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;"> <div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;">
<button type="button" class="btn btn-secondary" onclick="closeModal('deleteModal')">Batal</button> <button type="button" class="btn btn-secondary" onclick="closeModal('deleteModal')">Batal</button>
<button type="button" class="btn btn-danger" id="confirmDeleteBtn"> <button type="button" class="btn btn-danger" id="confirmDeleteBtn"><i class="fas fa-trash"></i> Hapus</button>
<i class="fas fa-trash"></i> Hapus
</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{{-- Modal Complete (Selesaikan Kepulangan) --}} {{-- Modal Complete --}}
<div class="modal fade" id="completeModal" tabindex="-1" style="display: none;"> <div class="modal fade" id="completeModal" tabindex="-1" style="display: none;">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;"> <div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;">
<form id="completeForm"> <form id="completeForm">
@csrf @csrf
<div style="margin-bottom: 14px;"> <div style="margin-bottom: 14px;">
<h3 style="margin: 0; color: #2C3E50;"> <h3 style="margin: 0; color: #2C3E50;"><i class="fas fa-check-circle" style="color: #28a745;"></i> Selesaikan Kepulangan</h3>
<i class="fas fa-check-circle" style="color: #28a745;"></i>
Selesaikan Kepulangan
</h3>
</div> </div>
<div style="background: #E8F7F2; padding: 15px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #6FBA9D;"> <div style="background: #E8F7F2; padding: 15px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #6FBA9D;">
<p style="margin: 5px 0;"><strong>ID Kepulangan:</strong> <span id="completeIdKepulangan"></span></p> <p style="margin: 5px 0;"><strong>ID Kepulangan:</strong> <span id="completeIdKepulangan"></span></p>
<p style="margin: 5px 0;"><strong>Santri:</strong> <span id="completeNamaSantri"></span></p> <p style="margin: 5px 0;"><strong>Santri:</strong> <span id="completeNamaSantri"></span></p>
@ -432,32 +368,20 @@ class="btn btn-sm btn-danger"
<p style="margin: 5px 0;"><strong>Rencana Kembali:</strong> <span id="completeTanggalKembaliRencana"></span></p> <p style="margin: 5px 0;"><strong>Rencana Kembali:</strong> <span id="completeTanggalKembaliRencana"></span></p>
<p style="margin: 5px 0;"><strong>Durasi Rencana:</strong> <span id="completeDurasiRencana"></span> hari</p> <p style="margin: 5px 0;"><strong>Durasi Rencana:</strong> <span id="completeDurasiRencana"></span> hari</p>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="tanggal_kembali_aktual"> <label for="tanggal_kembali_aktual">
<i class="fas fa-calendar-check"></i> <i class="fas fa-calendar-check"></i> Tanggal Kembali Aktual <span style="color: #dc3545;">*</span>
Tanggal Kembali Aktual <span style="color: #dc3545;">*</span>
</label> </label>
<input type="date" <input type="date" name="tanggal_kembali_aktual" id="tanggal_kembali_aktual" class="form-control" required>
name="tanggal_kembali_aktual" <small style="color: #7F8C8D; margin-top: 5px; display: block;">Masukkan tanggal santri kembali ke pesantren.</small>
id="tanggal_kembali_aktual"
class="form-control"
required>
<small style="color: #7F8C8D; margin-top: 5px; display: block;">
Masukkan tanggal santri kembali ke pesantren. Jika pulang lebih cepat, kuota akan disesuaikan otomatis.
</small>
</div> </div>
<div id="durasiAktualInfo" style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #007bff; display: none;"> <div id="durasiAktualInfo" style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #007bff; display: none;">
<p style="margin: 0;"><strong>Durasi Aktual:</strong> <span id="durasiAktual" style="font-weight: 600; color: #007bff;">-</span> hari</p> <p style="margin: 0;"><strong>Durasi Aktual:</strong> <span id="durasiAktual" style="font-weight: 600; color: #007bff;">-</span> hari</p>
<p style="margin: 5px 0 0 0; font-size: 0.9rem; color: #7F8C8D;" id="selisihInfo"></p> <p style="margin: 5px 0 0 0; font-size: 0.9rem; color: #7F8C8D;" id="selisihInfo"></p>
</div> </div>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;"> <div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;">
<button type="button" class="btn btn-secondary" onclick="closeModal('completeModal')">Batal</button> <button type="button" class="btn btn-secondary" onclick="closeModal('completeModal')">Batal</button>
<button type="submit" class="btn btn-success"> <button type="submit" class="btn btn-success"><i class="fas fa-check"></i> Selesaikan</button>
<i class="fas fa-check"></i> Selesaikan
</button>
</div> </div>
</form> </form>
</div> </div>
@ -468,26 +392,26 @@ class="form-control"
.modal.fade { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center; } .modal.fade { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center; }
.modal-dialog { max-width: 500px; width: 90%; margin: auto; } .modal-dialog { max-width: 500px; width: 90%; margin: auto; }
.modal-content { max-height: 90vh; overflow-y: auto; } .modal-content { max-height: 90vh; overflow-y: auto; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
</style> </style>
{{-- FIX: Definisikan semua URL dari Laravel, bukan hardcode di JS --}}
<script>
const KEPULANGAN_BASE_URL = "{{ url('admin/kepulangan') }}";
const CSRF_TOKEN = "{{ csrf_token() }}";
</script>
<script> <script>
let currentActionId = null; let currentActionId = null;
// Auto submit search dengan debounce // Auto submit search
let searchTimeout; let searchTimeout;
document.getElementById('searchInput')?.addEventListener('input', function() { document.getElementById('searchInput')?.addEventListener('input', function() {
clearTimeout(searchTimeout); clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => { searchTimeout = setTimeout(() => document.getElementById('filterForm').submit(), 500);
document.getElementById('filterForm').submit();
}, 500);
}); });
// Approve // ===== APPROVE =====
function approveKepulangan(id) { function approveKepulangan(id) {
currentActionId = id; currentActionId = id;
document.getElementById('approveModal').style.display = 'flex'; document.getElementById('approveModal').style.display = 'flex';
@ -498,33 +422,25 @@ function approveKepulangan(id) {
const formData = new FormData(this); const formData = new FormData(this);
const submitBtn = this.querySelector('button[type="submit"]'); const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML; const originalText = submitBtn.innerHTML;
submitBtn.disabled = true; submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...'; submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...';
fetch(`/admin/kepulangan/${currentActionId}/approve`, { // ✅ FIX: pakai KEPULANGAN_BASE_URL
fetch(`${KEPULANGAN_BASE_URL}/${currentActionId}/approve`, {
method: 'POST', method: 'POST',
body: formData, body: formData,
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' } headers: { 'X-CSRF-TOKEN': CSRF_TOKEN }
}) })
.then(response => response.json()) .then(r => r.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) { closeModal('approveModal'); showAlert('success', data.message); setTimeout(() => location.reload(), 1000); }
closeModal('approveModal'); else showAlert('danger', data.message);
showAlert('success', data.message);
setTimeout(() => window.location.reload(), 1000);
} else {
showAlert('danger', data.message);
}
}) })
.catch(error => showAlert('danger', 'Error: ' + error.message)) .catch(e => showAlert('danger', 'Error: ' + e.message))
.finally(() => { .finally(() => { submitBtn.disabled = false; submitBtn.innerHTML = originalText; });
submitBtn.disabled = false;
submitBtn.innerHTML = originalText;
});
}); });
// Reject // ===== REJECT =====
function rejectKepulangan(id) { function rejectKepulangan(id) {
currentActionId = id; currentActionId = id;
document.getElementById('rejectModal').style.display = 'flex'; document.getElementById('rejectModal').style.display = 'flex';
@ -535,150 +451,92 @@ function rejectKepulangan(id) {
const formData = new FormData(this); const formData = new FormData(this);
const submitBtn = this.querySelector('button[type="submit"]'); const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML; const originalText = submitBtn.innerHTML;
submitBtn.disabled = true; submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...'; submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...';
fetch(`/admin/kepulangan/${currentActionId}/reject`, { // ✅ FIX: pakai KEPULANGAN_BASE_URL
fetch(`${KEPULANGAN_BASE_URL}/${currentActionId}/reject`, {
method: 'POST', method: 'POST',
body: formData, body: formData,
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' } headers: { 'X-CSRF-TOKEN': CSRF_TOKEN }
}) })
.then(response => response.json()) .then(r => r.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) { closeModal('rejectModal'); showAlert('success', data.message); setTimeout(() => location.reload(), 1000); }
closeModal('rejectModal'); else showAlert('danger', data.message);
showAlert('success', data.message);
setTimeout(() => window.location.reload(), 1000);
} else {
showAlert('danger', data.message);
}
}) })
.catch(error => showAlert('danger', 'Error: ' + error.message)) .catch(e => showAlert('danger', 'Error: ' + e.message))
.finally(() => { .finally(() => { submitBtn.disabled = false; submitBtn.innerHTML = originalText; });
submitBtn.disabled = false;
submitBtn.innerHTML = originalText;
});
}); });
// Complete (Selesaikan Kepulangan) // ===== COMPLETE =====
let currentCompleteData = {}; let currentCompleteData = {};
function completeKepulangan(id, namaSantri, tanggalPulang, tanggalKembaliRencana, durasiRencana) { function completeKepulangan(id, namaSantri, tanggalPulang, tanggalKembaliRencana, durasiRencana) {
currentCompleteData = { currentCompleteData = { id, namaSantri, tanggalPulang, tanggalKembaliRencana, durasiRencana };
id: id,
namaSantri: namaSantri,
tanggalPulang: tanggalPulang,
tanggalKembaliRencana: tanggalKembaliRencana,
durasiRencana: durasiRencana
};
// Populate modal
document.getElementById('completeIdKepulangan').textContent = id; document.getElementById('completeIdKepulangan').textContent = id;
document.getElementById('completeNamaSantri').textContent = namaSantri; document.getElementById('completeNamaSantri').textContent = namaSantri;
document.getElementById('completeTanggalPulang').textContent = formatTanggal(tanggalPulang); document.getElementById('completeTanggalPulang').textContent = formatTanggal(tanggalPulang);
document.getElementById('completeTanggalKembaliRencana').textContent = formatTanggal(tanggalKembaliRencana); document.getElementById('completeTanggalKembaliRencana').textContent = formatTanggal(tanggalKembaliRencana);
document.getElementById('completeDurasiRencana').textContent = durasiRencana; document.getElementById('completeDurasiRencana').textContent = durasiRencana;
// Set default tanggal kembali aktual = hari ini
const today = new Date().toISOString().split('T')[0]; const today = new Date().toISOString().split('T')[0];
document.getElementById('tanggal_kembali_aktual').value = today; document.getElementById('tanggal_kembali_aktual').value = today;
document.getElementById('tanggal_kembali_aktual').min = tanggalPulang; document.getElementById('tanggal_kembali_aktual').min = tanggalPulang;
// Hitung durasi aktual
calculateDurasiAktual(); calculateDurasiAktual();
// Show modal
document.getElementById('completeModal').style.display = 'flex'; document.getElementById('completeModal').style.display = 'flex';
} }
// Calculate durasi aktual
function calculateDurasiAktual() { function calculateDurasiAktual() {
const tanggalPulang = currentCompleteData.tanggalPulang;
const tanggalKembaliAktual = document.getElementById('tanggal_kembali_aktual').value; const tanggalKembaliAktual = document.getElementById('tanggal_kembali_aktual').value;
if (!tanggalKembaliAktual || !currentCompleteData.tanggalPulang) return;
if (!tanggalKembaliAktual) return; const startDate = new Date(currentCompleteData.tanggalPulang);
const startDate = new Date(tanggalPulang);
const endDate = new Date(tanggalKembaliAktual); const endDate = new Date(tanggalKembaliAktual);
if (endDate < startDate) { document.getElementById('durasiAktualInfo').style.display = 'none'; return; }
if (endDate < startDate) { const durasiAktual = Math.ceil(Math.abs(endDate - startDate) / (1000 * 60 * 60 * 24)) + 1;
document.getElementById('durasiAktualInfo').style.display = 'none';
return;
}
const diffTime = Math.abs(endDate - startDate);
const durasiAktual = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1;
const durasiRencana = currentCompleteData.durasiRencana; const durasiRencana = currentCompleteData.durasiRencana;
document.getElementById('durasiAktual').textContent = durasiAktual; document.getElementById('durasiAktual').textContent = durasiAktual;
document.getElementById('durasiAktualInfo').style.display = 'block'; document.getElementById('durasiAktualInfo').style.display = 'block';
let selisihText = '', selisihColor = '#007bff';
// Show selisih
let selisihText = '';
let selisihColor = '#007bff';
if (durasiAktual < durasiRencana) { if (durasiAktual < durasiRencana) {
const selisih = durasiRencana - durasiAktual; selisihText = `Santri pulang ${durasiRencana - durasiAktual} hari lebih cepat. Kuota akan berkurang ${durasiAktual} hari.`;
selisihText = `✅ Santri pulang ${selisih} hari lebih cepat dari rencana. Kuota akan berkurang ${durasiAktual} hari.`;
selisihColor = '#28a745'; selisihColor = '#28a745';
} else if (durasiAktual > durasiRencana) { } else if (durasiAktual > durasiRencana) {
const selisih = durasiAktual - durasiRencana; selisihText = `Santri pulang ${durasiAktual - durasiRencana} hari lebih lambat. Kuota akan bertambah.`;
selisihText = `⚠️ Santri pulang ${selisih} hari lebih lambat dari rencana. Kuota akan bertambah ${selisih} hari.`;
selisihColor = '#ffc107'; selisihColor = '#ffc107';
} else { } else {
selisihText = `✓ Sesuai rencana (${durasiAktual} hari).`; selisihText = `Sesuai rencana (${durasiAktual} hari).`;
selisihColor = '#007bff';
} }
document.getElementById('selisihInfo').textContent = selisihText;
const selisihInfo = document.getElementById('selisihInfo'); document.getElementById('selisihInfo').style.color = selisihColor;
selisihInfo.textContent = selisihText;
selisihInfo.style.color = selisihColor;
document.getElementById('durasiAktual').style.color = selisihColor; document.getElementById('durasiAktual').style.color = selisihColor;
} }
// Event listener untuk tanggal kembali aktual
document.getElementById('tanggal_kembali_aktual')?.addEventListener('change', calculateDurasiAktual); document.getElementById('tanggal_kembali_aktual')?.addEventListener('change', calculateDurasiAktual);
// Submit form complete
document.getElementById('completeForm')?.addEventListener('submit', function(e) { document.getElementById('completeForm')?.addEventListener('submit', function(e) {
e.preventDefault(); e.preventDefault();
const formData = new FormData(this); const formData = new FormData(this);
const submitBtn = this.querySelector('button[type="submit"]'); const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML; const originalText = submitBtn.innerHTML;
submitBtn.disabled = true; submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...'; submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...';
fetch(`/admin/kepulangan/${currentCompleteData.id}/complete`, { // ✅ FIX: pakai KEPULANGAN_BASE_URL
fetch(`${KEPULANGAN_BASE_URL}/${currentCompleteData.id}/complete`, {
method: 'POST', method: 'POST',
body: formData, body: formData,
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' } headers: { 'X-CSRF-TOKEN': CSRF_TOKEN }
}) })
.then(response => response.json()) .then(r => r.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) { closeModal('completeModal'); showAlert('success', data.message); setTimeout(() => location.reload(), 1500); }
closeModal('completeModal'); else showAlert('danger', data.message);
showAlert('success', data.message);
setTimeout(() => window.location.reload(), 1500);
} else {
showAlert('danger', data.message);
}
}) })
.catch(error => showAlert('danger', 'Error: ' + error.message)) .catch(e => showAlert('danger', 'Error: ' + e.message))
.finally(() => { .finally(() => { submitBtn.disabled = false; submitBtn.innerHTML = originalText; });
submitBtn.disabled = false;
submitBtn.innerHTML = originalText;
});
}); });
// Helper: Format tanggal // ===== DELETE =====
function formatTanggal(dateString) {
const options = { year: 'numeric', month: 'long', day: 'numeric' };
return new Date(dateString).toLocaleDateString('id-ID', options);
}
// Delete
function deleteKepulangan(id) { function deleteKepulangan(id) {
currentActionId = id; currentActionId = id;
document.getElementById('deleteModal').style.display = 'flex'; document.getElementById('deleteModal').style.display = 'flex';
@ -687,61 +545,39 @@ function deleteKepulangan(id) {
document.getElementById('confirmDeleteBtn').addEventListener('click', function() { document.getElementById('confirmDeleteBtn').addEventListener('click', function() {
const btn = this; const btn = this;
const originalText = btn.innerHTML; const originalText = btn.innerHTML;
btn.disabled = true; btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Menghapus...'; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Menghapus...';
fetch(`/admin/kepulangan/${currentActionId}`, { // ✅ FIX: pakai KEPULANGAN_BASE_URL
fetch(`${KEPULANGAN_BASE_URL}/${currentActionId}`, {
method: 'DELETE', method: 'DELETE',
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' } headers: { 'X-CSRF-TOKEN': CSRF_TOKEN }
}) })
.then(response => response.json()) .then(r => r.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) { closeModal('deleteModal'); showAlert('success', data.message); setTimeout(() => location.reload(), 1000); }
closeModal('deleteModal'); else showAlert('danger', data.message);
showAlert('success', data.message);
setTimeout(() => window.location.reload(), 1000);
} else {
showAlert('danger', data.message);
}
}) })
.catch(error => showAlert('danger', 'Error: ' + error.message)) .catch(e => showAlert('danger', 'Error: ' + e.message))
.finally(() => { .finally(() => { btn.disabled = false; btn.innerHTML = originalText; });
btn.disabled = false;
btn.innerHTML = originalText;
});
}); });
// Helper functions // ===== HELPERS =====
function closeModal(modalId) { function formatTanggal(dateString) {
document.getElementById(modalId).style.display = 'none'; return new Date(dateString).toLocaleDateString('id-ID', { year: 'numeric', month: 'long', day: 'numeric' });
} }
function closeModal(modalId) { document.getElementById(modalId).style.display = 'none'; }
function showAlert(type, message) { function showAlert(type, message) {
const alertDiv = document.createElement('div'); const alertDiv = document.createElement('div');
alertDiv.className = `alert alert-${type}`; alertDiv.className = `alert alert-${type}`;
alertDiv.innerHTML = `<i class="fas fa-${type === 'success' ? 'check' : 'exclamation'}-circle"></i> ${message}`; alertDiv.innerHTML = `<i class="fas fa-${type === 'success' ? 'check' : 'exclamation'}-circle"></i> ${message}`;
document.querySelector('.page-header').insertAdjacentElement('afterend', alertDiv);
const pageHeader = document.querySelector('.page-header');
pageHeader.insertAdjacentElement('afterend', alertDiv);
setTimeout(() => alertDiv.remove(), 5000); setTimeout(() => alertDiv.remove(), 5000);
} }
// Close modals on ESC document.addEventListener('keydown', e => { if (e.key === 'Escape') document.querySelectorAll('.modal.fade').forEach(m => m.style.display = 'none'); });
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
document.querySelectorAll('.modal.fade').forEach(modal => modal.style.display = 'none');
}
});
// Close modal on outside click
document.querySelectorAll('.modal.fade').forEach(modal => { document.querySelectorAll('.modal.fade').forEach(modal => {
modal.addEventListener('click', function(e) { modal.addEventListener('click', function(e) { if (e.target === this) this.style.display = 'none'; });
if (e.target === this) {
this.style.display = 'none';
}
});
}); });
</script> </script>
@endsection @endsection

View File

@ -13,17 +13,17 @@
<div style="background: linear-gradient(135deg, #ff5252 0%, #f48fb1 100%); color: white; padding: 14px; border-radius: 12px; margin-bottom: 14px;"> <div style="background: linear-gradient(135deg, #ff5252 0%, #f48fb1 100%); color: white; padding: 14px; border-radius: 12px; margin-bottom: 14px;">
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 20px; align-items: center;"> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 20px; align-items: center;">
<div> <div>
<h4 style="margin: 0 0 5px 0; opacity: 0.9;">⚠️ Total Santri Over Limit</h4> <h4 style="margin: 0 0 5px 0; opacity: 0.9;">Total Santri Over Limit</h4>
<p style="margin: 0; font-size: 2rem; font-weight: 700;">{{ $santriList->count() }}</p> <p style="margin: 0; font-size: 2rem; font-weight: 700;">{{ $santriList->count() }}</p>
</div> </div>
<div> <div>
<h4 style="margin: 0 0 5px 0; opacity: 0.9;">📅 Periode Kuota</h4> <h4 style="margin: 0 0 5px 0; opacity: 0.9;">Periode Kuota</h4>
<p style="margin: 0; font-size: 1.1rem; font-weight: 600;"> <p style="margin: 0; font-size: 1.1rem; font-weight: 600;">
{{ $settings->periode_mulai->format('d M Y') }} - {{ $settings->periode_akhir->format('d M Y') }} {{ $settings->periode_mulai->format('d M Y') }} - {{ $settings->periode_akhir->format('d M Y') }}
</p> </p>
</div> </div>
<div> <div>
<h4 style="margin: 0 0 5px 0; opacity: 0.9;">📊 Kuota Maksimal</h4> <h4 style="margin: 0 0 5px 0; opacity: 0.9;">Kuota Maksimal</h4>
<p style="margin: 0; font-size: 1.1rem; font-weight: 600;">{{ $settings->kuota_maksimal }} Hari / Tahun</p> <p style="margin: 0; font-size: 1.1rem; font-weight: 600;">{{ $settings->kuota_maksimal }} Hari / Tahun</p>
</div> </div>
<div style="text-align: right;"> <div style="text-align: right;">
@ -36,7 +36,7 @@
{{-- Alert Info --}} {{-- Alert Info --}}
<div style="background: #fff3cd; padding: 15px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #ffc107;"> <div style="background: #fff3cd; padding: 15px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #ffc107;">
<strong>ℹ️ Informasi:</strong> <strong>Informasi:</strong>
<p style="margin: 10px 0 0 0;"> <p style="margin: 10px 0 0 0;">
Berikut adalah daftar santri yang telah melebihi kuota maksimal <strong>{{ $settings->kuota_maksimal }} hari</strong> dalam periode ini. Berikut adalah daftar santri yang telah melebihi kuota maksimal <strong>{{ $settings->kuota_maksimal }} hari</strong> dalam periode ini.
Santri tetap bisa mengajukan izin, namun akan mendapat peringatan visual. Santri tetap bisa mengajukan izin, namun akan mendapat peringatan visual.
@ -131,7 +131,7 @@ class="btn btn-sm btn-warning"
{{-- Summary Statistics --}} {{-- Summary Statistics --}}
<div style="margin-top: 22px; padding: 14px; background: #f8f9fa; border-radius: 8px;"> <div style="margin-top: 22px; padding: 14px; background: #f8f9fa; border-radius: 8px;">
<h4 style="margin: 0 0 15px 0; color: #2C3E50;">📊 Ringkasan Statistik</h4> <h4 style="margin: 0 0 15px 0; color: #2C3E50;">Ringkasan Statistik</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 20px;"> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 20px;">
<div style="text-align: center; padding: 15px; background: white; border-radius: 8px; border: 2px solid #dc3545;"> <div style="text-align: center; padding: 15px; background: white; border-radius: 8px; border: 2px solid #dc3545;">
<div style="font-size: 0.85rem; color: #7F8C8D; margin-bottom: 5px;">Total Santri Over Limit</div> <div style="font-size: 0.85rem; color: #7F8C8D; margin-bottom: 5px;">Total Santri Over Limit</div>

View File

@ -164,15 +164,16 @@ class="form-control"
<td class="text-center"> <td class="text-center">
<div style="display: flex; gap: 5px; justify-content: center; flex-wrap: wrap;"> <div style="display: flex; gap: 5px; justify-content: center; flex-wrap: wrap;">
@if($item->status == 'Menunggu') @if($item->status == 'Menunggu')
{{-- FIX: kirim URL dari route() helper sebagai parameter --}}
<button type="button" <button type="button"
class="btn btn-sm btn-success" class="btn btn-sm btn-success"
onclick="approvePengajuan({{ $item->id }})" onclick="approvePengajuan({{ $item->id }}, '{{ route('admin.kepulangan.pengajuan.approve', $item->id) }}')"
title="Setujui"> title="Setujui">
<i class="fas fa-check"></i> Setujui <i class="fas fa-check"></i> Setujui
</button> </button>
<button type="button" <button type="button"
class="btn btn-sm btn-danger" class="btn btn-sm btn-danger"
onclick="rejectPengajuan({{ $item->id }})" onclick="rejectPengajuan({{ $item->id }}, '{{ route('admin.kepulangan.pengajuan.reject', $item->id) }}')"
title="Tolak"> title="Tolak">
<i class="fas fa-times"></i> Tolak <i class="fas fa-times"></i> Tolak
</button> </button>
@ -296,12 +297,19 @@ class="btn btn-sm btn-danger"
} }
</style> </style>
{{-- FIX: CSRF token tersimpan di variabel JS, bukan di dalam fetch --}}
<script> <script>
let currentPengajuanId = null; const CSRF_TOKEN = "{{ csrf_token() }}";
</script>
// Approve <script>
function approvePengajuan(id) { let currentApproveUrl = null;
currentPengajuanId = id; let currentRejectUrl = null;
// ===== APPROVE =====
// ✅ FIX: terima routeUrl dari blade, simpan di variabel, pakai saat submit
function approvePengajuan(id, routeUrl) {
currentApproveUrl = routeUrl;
document.getElementById('approveModal').style.display = 'flex'; document.getElementById('approveModal').style.display = 'flex';
} }
@ -314,12 +322,20 @@ function approvePengajuan(id) {
submitBtn.disabled = true; submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...'; submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...';
fetch(`/admin/kepulangan/pengajuan/${currentPengajuanId}/approve`, { // ✅ FIX: pakai currentApproveUrl yang sudah di-set dari route() blade
fetch(currentApproveUrl, {
method: 'POST', method: 'POST',
body: formData, body: formData,
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' } headers: { 'X-CSRF-TOKEN': CSRF_TOKEN }
})
.then(response => {
// ✅ FIX: cek content-type sebelum parse JSON agar error HTML tidak merusak
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new Error('Response bukan JSON. Kemungkinan terjadi error server (500/404).');
}
return response.json();
}) })
.then(response => response.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) {
closeModal('approveModal'); closeModal('approveModal');
@ -336,9 +352,10 @@ function approvePengajuan(id) {
}); });
}); });
// Reject // ===== REJECT =====
function rejectPengajuan(id) { // ✅ FIX: terima routeUrl dari blade, simpan di variabel, pakai saat submit
currentPengajuanId = id; function rejectPengajuan(id, routeUrl) {
currentRejectUrl = routeUrl;
document.getElementById('rejectModal').style.display = 'flex'; document.getElementById('rejectModal').style.display = 'flex';
} }
@ -351,12 +368,20 @@ function rejectPengajuan(id) {
submitBtn.disabled = true; submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...'; submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...';
fetch(`/admin/kepulangan/pengajuan/${currentPengajuanId}/reject`, { // ✅ FIX: pakai currentRejectUrl yang sudah di-set dari route() blade
fetch(currentRejectUrl, {
method: 'POST', method: 'POST',
body: formData, body: formData,
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' } headers: { 'X-CSRF-TOKEN': CSRF_TOKEN }
})
.then(response => {
// ✅ FIX: cek content-type sebelum parse JSON
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new Error('Response bukan JSON. Kemungkinan terjadi error server (500/404).');
}
return response.json();
}) })
.then(response => response.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) {
closeModal('rejectModal'); closeModal('rejectModal');
@ -373,7 +398,7 @@ function rejectPengajuan(id) {
}); });
}); });
// Helper functions // ===== HELPERS =====
function closeModal(modalId) { function closeModal(modalId) {
document.getElementById(modalId).style.display = 'none'; document.getElementById(modalId).style.display = 'none';
} }

View File

@ -67,19 +67,19 @@
<td> <td>
@if($kepulangan->is_aktif) @if($kepulangan->is_aktif)
<span style="display: inline-block; background: #28a745; color: white; padding: 4px 10px; border-radius: 4px; font-size: 0.9rem;"> <span style="display: inline-block; background: #28a745; color: white; padding: 4px 10px; border-radius: 4px; font-size: 0.9rem;">
🏠 Sedang Izin Sedang Izin
</span> </span>
@elseif($kepulangan->is_terlambat) @elseif($kepulangan->is_terlambat)
<span style="display: inline-block; background: #dc3545; color: white; padding: 4px 10px; border-radius: 4px; font-size: 0.9rem;"> <span style="display: inline-block; background: #dc3545; color: white; padding: 4px 10px; border-radius: 4px; font-size: 0.9rem;">
⏰ Terlambat Kembali Terlambat Kembali
</span> </span>
@elseif($kepulangan->status == 'Selesai') @elseif($kepulangan->status == 'Selesai')
<span style="display: inline-block; background: #6c757d; color: white; padding: 4px 10px; border-radius: 4px; font-size: 0.9rem;"> <span style="display: inline-block; background: #6c757d; color: white; padding: 4px 10px; border-radius: 4px; font-size: 0.9rem;">
✅ Sudah Selesai Sudah Selesai
</span> </span>
@else @else
<span style="display: inline-block; background: #81C6E8; color: white; padding: 4px 10px; border-radius: 4px; font-size: 0.9rem;"> <span style="display: inline-block; background: #81C6E8; color: white; padding: 4px 10px; border-radius: 4px; font-size: 0.9rem;">
📅 Belum Dimulai Belum Dimulai
</span> </span>
@endif @endif
</td> </td>

View File

@ -243,10 +243,16 @@ class="btn btn-danger btn-sm"
</div> </div>
</div> </div>
{{-- FIX: Simpan base URL dari Laravel agar tidak hardcode di JS --}}
<script>
const BASE_URL = "{{ url('admin/kesehatan-santri') }}";
</script>
<script> <script>
function keluarUkp(id, namaSantri, tanggalMasuk) { function keluarUkp(id, namaSantri, tanggalMasuk) {
document.getElementById('modalNamaSantri').value = namaSantri; document.getElementById('modalNamaSantri').value = namaSantri;
document.getElementById('keluarUkpForm').action = `/admin/kesehatan-santri/${id}/keluar-ukp`; // ✅ FIX: Gunakan BASE_URL dari Laravel, bukan hardcode path
document.getElementById('keluarUkpForm').action = BASE_URL + '/' + id + '/keluar-ukp';
document.getElementById('tanggal_keluar').value = new Date().toISOString().split('T')[0]; document.getElementById('tanggal_keluar').value = new Date().toISOString().split('T')[0];
document.getElementById('tanggal_keluar').min = tanggalMasuk; document.getElementById('tanggal_keluar').min = tanggalMasuk;
document.getElementById('tanggal_keluar').max = new Date().toISOString().split('T')[0]; document.getElementById('tanggal_keluar').max = new Date().toISOString().split('T')[0];

View File

@ -23,7 +23,7 @@
</div> </div>
<div style="opacity: 0.95;"> <div style="opacity: 0.95;">
<strong>Status:</strong> {{ $santri->status_badge }}<br> <strong>Status:</strong> {!! $santri->status_badge !!}<br>
<strong>NIS:</strong> {{ $santri->nis ?: '-' }} <strong>NIS:</strong> {{ $santri->nis ?: '-' }}
</div> </div>

View File

@ -269,7 +269,7 @@ class="btn btn-success"
</div> </div>
</div> </div>
<!-- Action Buttons (Fixed at Bottom) --> <!-- Action Buttons -->
<div class="content-box" style="background: linear-gradient(135deg, #F8FBF9 0%, #E8F7F2 100%); border-top: 3px solid var(--primary-color);"> <div class="content-box" style="background: linear-gradient(135deg, #F8FBF9 0%, #E8F7F2 100%); border-top: 3px solid var(--primary-color);">
<h4 style="color: var(--primary-color); margin-bottom: 15px;"> <h4 style="color: var(--primary-color); margin-bottom: 15px;">
<i class="fas fa-tools"></i> Aksi Tersedia <i class="fas fa-tools"></i> Aksi Tersedia
@ -289,7 +289,7 @@ class="btn btn-primary">
<form action="{{ route('admin.kesehatan-santri.destroy', $kesehatanSantri) }}" <form action="{{ route('admin.kesehatan-santri.destroy', $kesehatanSantri) }}"
method="POST" method="POST"
style="display: inline;" style="display: inline;"
onsubmit="return confirm('⚠️ Yakin ingin menghapus data kesehatan ini?\n\nData yang dihapus tidak dapat dikembalikan!')"> onsubmit="return confirm('Yakin ingin menghapus data kesehatan ini?\n\nData yang dihapus tidak dapat dikembalikan!')">
@csrf @csrf
@method('DELETE') @method('DELETE')
<button type="submit" class="btn btn-danger"> <button type="submit" class="btn btn-danger">
@ -312,7 +312,6 @@ class="btn btn-primary">
</h3> </h3>
<div class="table-wrapper"> <div class="table-wrapper">
<table class="data-table"> <table class="data-table">
<thead> <thead>
<tr> <tr>
@ -362,7 +361,6 @@ class="btn btn-primary btn-sm">
@endforeach @endforeach
</tbody> </tbody>
</table> </table>
</div> </div>
<div style="text-align: center; margin-top: 14px;"> <div style="text-align: center; margin-top: 14px;">
@ -424,43 +422,28 @@ class="btn btn-primary">
from { opacity: 0; } from { opacity: 0; }
to { opacity: 1; } to { opacity: 1; }
} }
@keyframes slideDown { @keyframes slideDown {
from { from { opacity: 0; transform: translate(-50%, -60%); }
opacity: 0; to { opacity: 1; transform: translate(-50%, -50%); }
transform: translate(-50%, -60%);
} }
to { .info-item { transition: all 0.3s ease; }
opacity: 1; .info-item:hover { transform: translateX(5px); }
transform: translate(-50%, -50%);
}
}
.info-item {
transition: all 0.3s ease;
}
.info-item:hover {
transform: translateX(5px);
}
/* Responsive adjustments */
@media (max-width: 768px) { @media (max-width: 768px) {
#keluarUkpModal > div { #keluarUkpModal > div { min-width: 90%; padding: 14px; }
min-width: 90%; .page-header h2 { font-size: 1.3rem; }
padding: 14px;
}
.page-header h2 {
font-size: 1.3rem;
}
} }
</style> </style>
{{-- FIX: Simpan base URL dari Laravel agar tidak hardcode di JS --}}
<script>
const BASE_URL = "{{ url('admin/kesehatan-santri') }}";
</script>
<script> <script>
function keluarUkp(id, namaSantri, tanggalMasuk) { function keluarUkp(id, namaSantri, tanggalMasuk) {
document.getElementById('modalNamaSantri').value = namaSantri; document.getElementById('modalNamaSantri').value = namaSantri;
document.getElementById('keluarUkpForm').action = `/admin/kesehatan-santri/${id}/keluar-ukp`; // ✅ FIX: Gunakan BASE_URL dari Laravel, bukan hardcode path
document.getElementById('keluarUkpForm').action = BASE_URL + '/' + id + '/keluar-ukp';
document.getElementById('tanggal_keluar').value = new Date().toISOString().split('T')[0]; document.getElementById('tanggal_keluar').value = new Date().toISOString().split('T')[0];
document.getElementById('tanggal_keluar').min = tanggalMasuk; document.getElementById('tanggal_keluar').min = tanggalMasuk;
document.getElementById('tanggal_keluar').max = new Date().toISOString().split('T')[0]; document.getElementById('tanggal_keluar').max = new Date().toISOString().split('T')[0];
@ -471,18 +454,12 @@ function closeKeluarUkpModal() {
document.getElementById('keluarUkpModal').style.display = 'none'; document.getElementById('keluarUkpModal').style.display = 'none';
} }
// Close modal when clicking outside
document.getElementById('keluarUkpModal').addEventListener('click', function(e) { document.getElementById('keluarUkpModal').addEventListener('click', function(e) {
if (e.target === this) { if (e.target === this) closeKeluarUkpModal();
closeKeluarUkpModal();
}
}); });
// Close modal with Escape key
document.addEventListener('keydown', function(e) { document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') { if (e.key === 'Escape') closeKeluarUkpModal();
closeKeluarUkpModal();
}
}); });
</script> </script>

View File

@ -14,8 +14,18 @@
'Sakit' => ['bg'=>'#E0F2FE','c'=>'#0C4A6E','ic'=>'🏥'], 'Sakit' => ['bg'=>'#E0F2FE','c'=>'#0C4A6E','ic'=>'🏥'],
]; ];
// ── 1. Kolom kegiatan: UNIK, diurutkan waktu_mulai ─────────────────────────── // ── 1. Kelompokkan data per tanggal → per santri ─────────────────────────────
$kegiatanCols = collect($hasilEnriched) $byTanggal = [];
foreach ($hasilEnriched as $h) {
$tgl = $h['tanggal'];
$byTanggal[$tgl][] = $h;
}
ksort($byTanggal);
// ── 2. Buat kolom kegiatan UNIK per tanggal, diurutkan waktu_mulai ───────────
$kegiatanByTanggal = [];
foreach ($byTanggal as $tgl => $santriList) {
$cols = collect($santriList)
->flatMap(fn($h) => $h['rows']) ->flatMap(fn($h) => $h['rows'])
->unique('kegiatan_id') ->unique('kegiatan_id')
->sortBy('waktu_mulai') ->sortBy('waktu_mulai')
@ -25,37 +35,21 @@
'nama' => $r['nama_kegiatan'], 'nama' => $r['nama_kegiatan'],
'waktu_mulai' => $r['waktu_mulai'], 'waktu_mulai' => $r['waktu_mulai'],
]); ]);
$kegiatanByTanggal[$tgl] = $cols;
// ── 2. Susun data: [tanggal][id_santri_or_mesin] = data ──────────────────────
$byTanggalSantri = [];
$santriList = []; // untuk urutan santri konsisten
foreach ($hasilEnriched as $h) {
$tgl = $h['tanggal'];
$key = $h['id_santri'] ?? ('__'.$h['id_mesin']);
$byTanggalSantri[$tgl][$key] = $h;
if (!isset($santriList[$key])) {
$santriList[$key] = [
'nama' => $h['nama_web'] ?? $h['nama_mesin'],
'kelas' => $h['kelas'] ?? '-',
'status' => $h['match_status'],
];
} }
}
ksort($byTanggalSantri);
// ── 3. Statistik ───────────────────────────────────────────────────────────── // ── 3. Statistik global ──────────────────────────────────────────────────────
$allRows = collect($hasilEnriched)->flatMap(fn($h) => $h['rows']); $allRows = collect($hasilEnriched)->flatMap(fn($h) => $h['rows']);
$totalKonflik = $allRows->where('is_conflict', true)->count(); $totalKonflik = $allRows->where('is_conflict', true)->count();
$hadir = $allRows->where('status_final','Hadir')->count(); $hadirTotal = $allRows->where('status_final','Hadir')->count();
$terlambat = $allRows->where('status_final','Terlambat')->count(); $terlambatTotal = $allRows->where('status_final','Terlambat')->count();
$alpa = $allRows->where('status_final','Alpa')->count(); $alpaTotal = $allRows->where('status_final','Alpa')->count();
$notMapped = collect($hasilEnriched)->where('match_status','NOT_MAPPED')->count(); $notMapped = collect($hasilEnriched)->where('match_status','NOT_MAPPED')->count();
$totalSantri = collect($hasilEnriched)->unique(fn($h) => $h['id_santri'] ?? $h['id_mesin'])->count();
@endphp @endphp
<style> <style>
/* Sticky top bar */ /* ── Top sticky bar ───────────────────────────────── */
.top-bar { .top-bar {
position: sticky; top: 0; z-index: 50; position: sticky; top: 0; z-index: 50;
background: #0F172A; color: #F1F5F9; background: #0F172A; color: #F1F5F9;
@ -80,41 +74,61 @@
color: #fff; white-space: nowrap; transition: background .2s; color: #fff; white-space: nowrap; transition: background .2s;
} }
/* Matrix table */ /* ── Per-day block ────────────────────────────────── */
.wrap { overflow-x: auto } .day-block {
.mx { border-collapse: collapse; font-size: 12px; width: 100% } margin: 14px 14px 0;
.mx th, .mx td { border-radius: 12px;
border: 1px solid #E5E7EB; padding: 0; overflow: hidden;
white-space: nowrap; box-shadow: 0 2px 10px rgba(0,0,0,.08);
border: 1px solid #E5E7EB;
} }
/* Sticky kolom tanggal + nama */ .day-block:last-child { margin-bottom: 14px; }
.col-tgl {
position: sticky; left: 0; z-index: 4; .day-header {
background: #F8FAFC; min-width: 90px; background: #1E293B;
border-right: 2px solid #CBD5E1; color: #F1F5F9;
padding: 6px 10px; font-size: 11px; padding: 10px 16px;
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
} }
.col-nama { .day-header .hari-nama {
position: sticky; left: 90px; z-index: 4; font-size: 10px; color: #64748B;
background: #F8FAFC; min-width: 130px; text-transform: uppercase; letter-spacing: 1px;
border-right: 2px solid #CBD5E1;
padding: 6px 10px;
} }
/* Header kegiatan (rotate) */ .day-header .tgl-label {
.th-wrap { font-weight: 700; font-size: 16px; margin-top: 1px;
writing-mode: vertical-rl;
transform: rotate(180deg);
display: flex; align-items: center; justify-content: flex-end;
gap: 2px; height: 80px; padding: 5px 6px;
} }
/* Status pill */ .day-badge {
border-radius: 6px; padding: 3px 10px;
font-size: 11px; font-weight: 700;
}
/* ── Tabel per hari ───────────────────────────────── */
.tbl-day { border-collapse: collapse; font-size: 12px; width: 100% }
.tbl-day th, .tbl-day td {
border: 1px solid #E5E7EB;
padding: 0;
}
.th-no { width: 36px; text-align: center; padding: 8px 4px !important; }
.th-nama { min-width: 150px; padding: 8px 10px !important; text-align: left; }
.th-kelas { min-width: 80px; padding: 8px 10px !important; text-align: left; }
.th-keg { min-width: 90px; vertical-align: bottom; }
.th-keg-inner {
padding: 6px 8px 6px;
display: flex; flex-direction: column; align-items: center;
gap: 2px;
}
/* ── Status pill ──────────────────────────────────── */
.pill { .pill {
display: inline-block; border-radius: 8px; display: inline-block; border-radius: 8px;
padding: 2px 6px; font-size: 10px; font-weight: 700; padding: 2px 7px; font-size: 10px; font-weight: 700;
} }
/* Konflik cell */
.conf-cell { background: #FFF5F5 !important; border: 2px solid #FCA5A5 !important } /* ── Konflik cell ─────────────────────────────────── */
.conf-wrap { display: flex; flex-direction: column } .conf-wrap { display: flex; flex-direction: column; }
.conf-opt { .conf-opt {
padding: 4px 8px; cursor: pointer; padding: 4px 8px; cursor: pointer;
font-size: 11px; display: flex; align-items: center; gap: 4px; font-size: 11px; display: flex; align-items: center; gap: 4px;
@ -124,27 +138,12 @@
.conf-opt:hover { background: #F8FAFC } .conf-opt:hover { background: #F8FAFC }
.sel-m { background: #DCFCE7 !important } .sel-m { background: #DCFCE7 !important }
.sel-e { background: #DBEAFE !important } .sel-e { background: #DBEAFE !important }
/* Date separator row */
.date-sep td {
background: #1E293B; color: #94A3B8; font-weight: 700;
font-size: 11px; padding: 5px 12px; border-bottom: 2px solid #334155;
}
/* Alternating santri rows */
.row-alt { background: #FAFAFA }
/* Sticky header */
.th-sticky {
position: sticky; top: 52px; z-index: 6;
background: #1E293B;
}
.th-tgl { position: sticky; left: 0; z-index: 8 }
.th-nama { position: sticky; left: 90px; z-index: 8 }
</style> </style>
<form action="{{ route('admin.mesin.import.store') }}" method="POST" id="frm"> <form action="{{ route('admin.mesin.import.store') }}" method="POST" id="frm">
@csrf @csrf
<input type="hidden" name="conflict_strategy" value="manual" id="stratInput"> <input type="hidden" name="conflict_strategy" value="manual" id="stratInput">
{{-- Error flash --}}
@if(session('error')) @if(session('error'))
<div style="background:#FEE2E2;border:1px solid #FCA5A5;border-left:4px solid #DC2626; <div style="background:#FEE2E2;border:1px solid #FCA5A5;border-left:4px solid #DC2626;
padding:12px 16px;font-size:13px;color:#991B1B"> padding:12px 16px;font-size:13px;color:#991B1B">
@ -152,14 +151,15 @@
</div> </div>
@endif @endif
{{-- ── TOP BAR ──────────────────────────────────────────────────────────────── --}} {{-- ══ TOP BAR ═════════════════════════════════════════════════════════════ --}}
<div class="top-bar"> <div class="top-bar">
<div style="flex:1;min-width:160px"> <div style="flex:1;min-width:200px">
<div style="color:#64748B;font-size:10px;text-transform:uppercase;letter-spacing:1px"> <div style="color:#64748B;font-size:10px;text-transform:uppercase;letter-spacing:1px">
Preview Import Preview Import
</div> </div>
<div style="font-weight:700;font-size:14px;margin-top:1px"> <div style="font-weight:700;font-size:14px;margin-top:1px">
{{ count($santriList) }} santri {{ $totalSantri }} santri ·
{{ count($byTanggal) }} hari
@if($totalKonflik > 0) @if($totalKonflik > 0)
· <span style="color:#FCA5A5" id="lbl"> · <span style="color:#FCA5A5" id="lbl">
<span id="cnt">{{ $totalKonflik }}</span> konflik perlu diselesaikan <span id="cnt">{{ $totalKonflik }}</span> konflik perlu diselesaikan
@ -170,15 +170,22 @@
</div> </div>
</div> </div>
{{-- Toleransi tampilkan nilai DARI form, bukan hardcode --}}
<div style="background:#1E3A5F;border:1px solid #2D5A8E;border-radius:8px;
padding:5px 12px;font-size:11px;color:#93C5FD;white-space:nowrap">
Toleransi: <strong style="color:#BFDBFE">{{ $tolSebelum }}m</strong> sebelum
/ <strong style="color:#BFDBFE">{{ $tolSesudah }}m</strong> sesudah
</div>
{{-- Stat chips --}} {{-- Stat chips --}}
<div class="chip" style="background:#DCFCE7;color:#166534"> <div class="chip" style="background:#DCFCE7;color:#166534">
<span class="n">{{ $hadir }}</span>Hadir <span class="n">{{ $hadirTotal }}</span>Hadir
</div> </div>
<div class="chip" style="background:#FEF9C3;color:#92400E"> <div class="chip" style="background:#FEF9C3;color:#92400E">
<span class="n">{{ $terlambat }}</span>Telat <span class="n">{{ $terlambatTotal }}</span>Telat
</div> </div>
<div class="chip" style="background:#FEE2E2;color:#991B1B"> <div class="chip" style="background:#FEE2E2;color:#991B1B">
<span class="n">{{ $alpa }}</span>Alpa <span class="n">{{ $alpaTotal }}</span>Alpa
</div> </div>
@if($totalKonflik > 0) @if($totalKonflik > 0)
<div class="chip" style="background:#FEE2E2;color:#DC2626"> <div class="chip" style="background:#FEE2E2;color:#DC2626">
@ -191,18 +198,22 @@
</div> </div>
@endif @endif
{{-- Conflict actions --}} {{-- Konflik: bulk actions --}}
@if($totalKonflik > 0) @if($totalKonflik > 0)
<div style="display:flex;flex-direction:column;gap:3px;font-size:11px;color:#94A3B8"> <div style="display:flex;flex-direction:column;gap:3px;font-size:11px;color:#94A3B8">
Konflik: Konflik:
</div> </div>
<button type="button" class="btn-act" style="background:#DCFCE7;color:#166534" <button type="button" class="btn-act" style="background:#DCFCE7;color:#166534"
onclick="resolveAll('m');document.getElementById('stratInput').value='mesin'">👆 Mesin</button> onclick="resolveAll('m');document.getElementById('stratInput').value='mesin'">
👆 Semua Mesin
</button>
<button type="button" class="btn-act" style="background:#DBEAFE;color:#1D4ED8" <button type="button" class="btn-act" style="background:#DBEAFE;color:#1D4ED8"
onclick="resolveAll('e');document.getElementById('stratInput').value='exist'">🔒 Lama</button> onclick="resolveAll('e');document.getElementById('stratInput').value='exist'">
🔒 Semua Lama
</button>
@endif @endif
{{-- Save --}} {{-- Simpan --}}
<button type="button" class="btn-save" id="saveBtn" <button type="button" class="btn-save" id="saveBtn"
style="background:{{ $totalKonflik > 0 ? '#64748B' : 'linear-gradient(135deg,#166534,#22C55E)' }}" style="background:{{ $totalKonflik > 0 ? '#64748B' : 'linear-gradient(135deg,#166534,#22C55E)' }}"
{{ $totalKonflik > 0 ? 'disabled' : '' }} {{ $totalKonflik > 0 ? 'disabled' : '' }}
@ -218,7 +229,7 @@ class="btn-act" style="background:#374151;color:#F1F5F9;text-decoration:none">
</div> </div>
{{-- Legenda --}} {{-- Legenda --}}
<div style="display:flex;gap:8px;flex-wrap:wrap;padding:8px 16px; <div style="display:flex;gap:8px;flex-wrap:wrap;padding:8px 14px;
background:#F8FAFC;border-bottom:1px solid #E5E7EB;font-size:11px"> background:#F8FAFC;border-bottom:1px solid #E5E7EB;font-size:11px">
<span style="color:#6B7280;font-weight:600">Status:</span> <span style="color:#6B7280;font-weight:600">Status:</span>
@foreach($statusStyle as $st => $s) @foreach($statusStyle as $st => $s)
@ -227,44 +238,84 @@ class="btn-act" style="background:#374151;color:#F1F5F9;text-decoration:none">
</span> </span>
@endforeach @endforeach
<span style="color:#9CA3AF;margin-left:4px">| = tidak ada data</span> <span style="color:#9CA3AF;margin-left:4px">| = tidak ada data</span>
<span style="border:2px solid #FCA5A5;border-radius:4px;padding:1px 6px;color:#991B1B"> <span style="border:2px solid #FCA5A5;border-radius:4px;padding:1px 6px;color:#991B1B"> Konflik</span>
Konflik <span style="color:#9CA3AF">= pilih salah satu</span>
</span>
<span style="color:#9CA3AF">= ada data berbeda, pilih salah satu</span>
@if($notMapped > 0) @if($notMapped > 0)
<span style="margin-left:auto"> <span style="margin-left:auto">
⚠️ {{ $notMapped }} belum dipetakan ⚠️ {{ $notMapped }} belum dipetakan
<a href="{{ route('admin.mesin.mapping-santri.index') }}" target="_blank"> <a href="{{ route('admin.mesin.mapping-santri.index') }}" target="_blank">Lengkapi Mapping</a>
Lengkapi Mapping
</a>
</span> </span>
@endif @endif
</div> </div>
{{-- ── MATRIX TABLE ──────────────────────────────────────────────────────────── --}} {{-- ══ TABEL PER HARI ══════════════════════════════════════════════════════ --}}
<div class="wrap"> @foreach($byTanggal as $tgl => $santriListRaw)
<table class="mx"> @php
// Urutkan santri berdasarkan nama
$santriListSorted = collect($santriListRaw)
->sortBy(fn($h) => $h['nama_web'] ?? $h['nama_mesin'])
->values()
->all();
{{-- Sticky header --}} $tglCarbon = Carbon::parse($tgl);
$namaHari = $tglCarbon->locale('id')->isoFormat('dddd');
$tglFormatted = $tglCarbon->locale('id')->isoFormat('D MMMM Y');
$kegiatanHariIni = $kegiatanByTanggal[$tgl];
// Statistik untuk hari ini
$rowsHari = collect($santriListSorted)->flatMap(fn($h) => $h['rows']);
$hadirHari = $rowsHari->where('status_final','Hadir')->count();
$telambatHari = $rowsHari->where('status_final','Terlambat')->count();
$alpaHari = $rowsHari->where('status_final','Alpa')->count();
$konflikHari = $rowsHari->where('is_conflict',true)->count();
@endphp
<div class="day-block">
{{-- Header Tanggal --}}
<div class="day-header">
<div>
<div class="hari-nama">{{ $namaHari }}</div>
<div class="tgl-label">{{ $tglFormatted }}</div>
</div>
<div style="margin-left:auto;display:flex;gap:6px;flex-wrap:wrap;align-items:center">
<span class="day-badge" style="background:#DCFCE7;color:#166534"> {{ $hadirHari }} Hadir</span>
@if($telambatHari > 0)
<span class="day-badge" style="background:#FEF9C3;color:#92400E"> {{ $telambatHari }} Terlambat</span>
@endif
<span class="day-badge" style="background:#FEE2E2;color:#991B1B"> {{ $alpaHari }} Alpa</span>
@if($konflikHari > 0)
<span class="day-badge" style="background:#FEE2E2;color:#DC2626"> {{ $konflikHari }} Konflik</span>
@endif
<span class="day-badge" style="background:#334155;color:#94A3B8">
👥 {{ count($santriListSorted) }} santri
</span>
</div>
</div>
{{-- Tabel hari ini --}}
<div style="overflow-x:auto">
<table class="tbl-day">
<thead> <thead>
<tr> <tr style="background:#F1F5F9">
{{-- Tanggal header --}} <th class="th-no"
<th class="th-sticky th-tgl" style="border:1px solid #E2E8F0;color:#6B7280;font-size:10px;font-weight:700">
style="min-width:90px;padding:8px 10px;text-align:left; No
color:#94A3B8;font-size:10px;border-right:2px solid #334155">
Tanggal
</th> </th>
{{-- Nama header --}} <th class="th-nama"
<th class="th-sticky th-nama" style="border:1px solid #E2E8F0;color:#374151;font-size:11px;font-weight:700;border-right:2px solid #CBD5E1">
style="min-width:130px;padding:8px 10px;text-align:left; Nama Santri
color:#94A3B8;font-size:10px;border-right:2px solid #334155">
Santri
</th> </th>
{{-- Kolom kegiatan UNIK, diurutkan waktu --}} <th class="th-kelas"
@foreach($kegiatanCols as $kg) style="border:1px solid #E2E8F0;color:#374151;font-size:11px;font-weight:700;border-right:2px solid #CBD5E1">
<th class="th-sticky" style="min-width:70px;vertical-align:bottom"> Kelas
<div class="th-wrap"> </th>
<span style="color:#F1F5F9;font-size:10px;font-weight:600"> @foreach($kegiatanHariIni as $kg)
<th class="th-keg" style="border:1px solid #E2E8F0">
<div class="th-keg-inner">
<span style="color:#1E293B;font-size:11px;font-weight:600;
white-space:normal;text-align:center;line-height:1.3">
{{ $kg['nama'] }} {{ $kg['nama'] }}
</span> </span>
<span style="color:#64748B;font-size:9px"> <span style="color:#64748B;font-size:9px">
@ -275,96 +326,97 @@ class="btn-act" style="background:#374151;color:#F1F5F9;text-decoration:none">
@endforeach @endforeach
</tr> </tr>
</thead> </thead>
{{-- Body: iterasi per tanggal, lalu per santri --}}
<tbody> <tbody>
@foreach($byTanggalSantri as $tgl => $santriRows) @foreach($santriListSorted as $idx => $h)
@php @php
$tglCarbon = Carbon::parse($tgl); $rowBg = ($idx % 2 === 0) ? '#ffffff' : '#F9FAFB';
$tglLabel = $tglCarbon->locale('id')->isoFormat('ddd, D MMM'); if ($h['match_status'] === 'NOT_MAPPED') $rowBg = '#FFF5F5';
$isOdd = ($loop->index % 2 === 1);
@endphp
{{-- Setiap tanggal: satu baris per santri --}}
@foreach($santriList as $key => $info)
@php
$data = $santriRows[$key] ?? null;
$rowBg = ($loop->index % 2 === 0) ? 'white' : '#FAFAFA';
if ($data && $data['match_status'] === 'NOT_MAPPED') $rowBg = '#FFF5F5';
@endphp @endphp
<tr style="background:{{ $rowBg }}"> <tr style="background:{{ $rowBg }}">
{{-- Kolom Tanggal (hanya tampil di baris pertama per tanggal) --}} {{-- No --}}
<td class="col-tgl" style="background:{{ $rowBg }}"> <td style="text-align:center;padding:6px 4px;
@if($loop->first) color:#9CA3AF;font-size:11px;border:1px solid #E5E7EB">
<strong style="color:#1E293B">{{ $tglLabel }}</strong> {{ $idx + 1 }}
</td>
{{-- Nama --}}
<td style="padding:6px 10px;border:1px solid #E5E7EB;border-right:2px solid #CBD5E1">
@if($h['match_status'] === 'NOT_MAPPED')
<div style="font-weight:700;color:#DC2626;font-size:11px"> BELUM MAP</div>
<div style="color:#9CA3AF;font-size:10px">{{ $h['nama_mesin'] }}</div>
@else
<div style="font-weight:600;color:#1F2937;font-size:12px">
{{ $h['nama_web'] ?? $h['nama_mesin'] }}
</div>
@if($h['is_pulang'] ?? false)
<div style="font-size:9px;color:#9A3412;background:#FFF7ED;
border-radius:4px;padding:1px 5px;display:inline-block;margin-top:1px">
🏠 Sedang Pulang
</div>
@endif
@endif @endif
</td> </td>
{{-- Kolom Nama --}} {{-- Kelas --}}
<td class="col-nama" style="background:{{ $rowBg }}"> <td style="padding:6px 10px;border:1px solid #E5E7EB;border-right:2px solid #CBD5E1;
@if($info['status'] === 'NOT_MAPPED') color:#6B7280;font-size:11px">
<div style="font-size:10px;font-weight:700;color:#DC2626"> BELUM MAP</div> {{ $h['kelas'] ?? '-' }}
<div style="font-size:10px;color:#9CA3AF">{{ $info['nama'] }}</div>
@else
<div style="font-weight:600;color:#1F2937;font-size:12px">
{{ $info['nama'] }}
</div>
<div style="font-size:10px;color:#9CA3AF">{{ $info['kelas'] }}</div>
@endif
</td> </td>
{{-- Kolom per kegiatan --}} {{-- Kolom per kegiatan --}}
@foreach($kegiatanCols as $kg) @foreach($kegiatanHariIni as $kg)
@php @php
$row = $data $row = collect($h['rows'])->firstWhere('kegiatan_id', $kg['kegiatan_id']);
? collect($data['rows'])->firstWhere('kegiatan_id', $kg['kegiatan_id'])
: null;
$sf = $row['status_final'] ?? null; $sf = $row['status_final'] ?? null;
$st = $sf ? ($statusStyle[$sf] ?? null) : null; $st = $sf ? ($statusStyle[$sf] ?? null) : null;
$isConf = $row['is_conflict'] ?? false; $isConf = $row['is_conflict'] ?? false;
$key2 = "{$kg['kegiatan_id']}_{$data['id_santri']}_{$tgl}"; $cKey = "{$kg['kegiatan_id']}_{$h['id_santri']}_{$tgl}";
@endphp @endphp
<td style="padding:0;text-align:center;vertical-align:middle;min-width:70px" <td style="padding:0;text-align:center;vertical-align:middle;
class="{{ $isConf ? 'conf-cell' : '' }}"> border:1px solid {{ $isConf ? '#FCA5A5' : '#E5E7EB' }};
{{ $isConf ? 'background:#FFF5F5;border-width:2px;' : '' }}">
@if(!$data || !$row || $sf === null) @if(!$row || $sf === null)
{{-- Tidak ada data --}} {{-- Tidak ada data --}}
<span style="color:#D1D5DB"></span> <span style="color:#D1D5DB;font-size:14px"></span>
@elseif($isConf) @elseif($isConf)
{{-- ── KONFLIK: 2 pilihan ── --}} {{-- ── KONFLIK: 2 pilihan ────────── --}}
@php @php
$ex = $row['existing']; $ex = $row['existing'];
$exSt = $statusStyle[$ex['status']] ?? ['bg'=>'#F9FAFB','c'=>'#6B7280','ic'=>'?']; $exSt = $statusStyle[$ex['status']] ?? ['bg'=>'#F9FAFB','c'=>'#6B7280','ic'=>'?'];
@endphp @endphp
<div class="conf-wrap" data-key="{{ $key2 }}"> <div class="conf-wrap" data-key="{{ $cKey }}">
{{-- Pilihan mesin --}} {{-- Pilihan: pakai data mesin --}}
<div class="conf-opt" data-ch="m" onclick="pick('{{ $key2 }}','m',this)"> <div class="conf-opt" data-ch="m"
<input type="radio" name="conflict_choices[{{ $key2 }}]" onclick="pick('{{ $cKey }}','m',this)">
value="mesin" id="cm_{{ $key2 }}" style="display:none"> <input type="radio" name="conflict_choices[{{ $cKey }}]"
value="mesin" id="cm_{{ $cKey }}" style="display:none">
<span>👆</span> <span>👆</span>
<div> <div>
<span class="pill" style="background:{{$st['bg']}};color:{{$st['c']}}"> <span class="pill"
style="background:{{$st['bg']}};color:{{$st['c']}}">
{{$st['ic']}} {{$sf}} {{$st['ic']}} {{$sf}}
</span> </span>
<div style="font-size:9px;color:#6B7280"> <div style="font-size:9px;color:#6B7280;margin-top:1px">
Mesin · {{ $row['jam_scan'] ?? '-' }} Mesin · {{ $row['jam_scan'] ?? '-' }}
</div> </div>
</div> </div>
</div> </div>
{{-- Pilihan lama --}} {{-- Pilihan: pertahankan data lama --}}
<div class="conf-opt" data-ch="e" onclick="pick('{{ $key2 }}','e',this)"> <div class="conf-opt" data-ch="e"
<input type="radio" name="conflict_choices[{{ $key2 }}]" onclick="pick('{{ $cKey }}','e',this)">
value="exist" id="ce_{{ $key2 }}" style="display:none"> <input type="radio" name="conflict_choices[{{ $cKey }}]"
value="exist" id="ce_{{ $cKey }}" style="display:none">
<span>🔒</span> <span>🔒</span>
<div> <div>
<span class="pill" style="background:{{$exSt['bg']}};color:{{$exSt['c']}}"> <span class="pill"
style="background:{{$exSt['bg']}};color:{{$exSt['c']}}">
{{$exSt['ic']}} {{$ex['status']}} {{$exSt['ic']}} {{$ex['status']}}
</span> </span>
<div style="font-size:9px;color:#6B7280"> <div style="font-size:9px;color:#6B7280;margin-top:1px">
{{ $ex['metode'] ?? 'Manual' }} {{ $ex['metode'] ?? 'Manual' }}
@if($ex['waktu']) · {{ substr($ex['waktu'],0,5) }} @endif @if($ex['waktu']) · {{ substr($ex['waktu'],0,5) }} @endif
</div> </div>
@ -377,13 +429,15 @@ class="{{ $isConf ? 'conf-cell' : '' }}">
</div> </div>
@else @else
{{-- ── Normal ── --}} {{-- ── Normal ─────────────────────── --}}
<div style="padding:5px 3px"> <div style="padding:6px 4px">
@if($st)
<span class="pill" style="background:{{$st['bg']}};color:{{$st['c']}}"> <span class="pill" style="background:{{$st['bg']}};color:{{$st['c']}}">
{{$st['ic']}} {{$sf}} {{$st['ic']}} {{$sf}}
</span> </span>
@if($row['jam_scan']) @endif
<div style="font-size:9px;color:#9CA3AF;margin-top:1px"> @if(!empty($row['jam_scan']))
<div style="font-size:9px;color:#9CA3AF;margin-top:2px">
{{ $row['jam_scan'] }} {{ $row['jam_scan'] }}
@if(($row['selisih_menit'] ?? 0) > 0) @if(($row['selisih_menit'] ?? 0) > 0)
<span style="color:#F59E0B">+{{ $row['selisih_menit'] }}m</span> <span style="color:#F59E0B">+{{ $row['selisih_menit'] }}m</span>
@ -394,43 +448,40 @@ class="{{ $isConf ? 'conf-cell' : '' }}">
@endif @endif
</td> </td>
@endforeach @endforeach
</tr>
@endforeach
</tr>
@endforeach @endforeach
</tbody> </tbody>
{{-- Repeat header di bawah untuk tabel panjang --}}
<tfoot>
<tr>
<th style="background:#1E293B;color:#94A3B8;font-size:10px;
padding:6px 10px;border-right:2px solid #334155;
position:sticky;left:0">Tanggal</th>
<th style="background:#1E293B;color:#94A3B8;font-size:10px;
padding:6px 10px;border-right:2px solid #334155;
position:sticky;left:90px">Santri</th>
@foreach($kegiatanCols as $kg)
<th style="background:#1E293B;color:#94A3B8;font-size:9px;padding:4px 6px">
{{ $kg['nama'] }}
</th>
@endforeach
</tr>
</tfoot>
</table> </table>
</div> </div>
{{-- Footer per hari: ringkasan kegiatan --}}
<div style="background:#F8FAFC;padding:6px 14px;font-size:10px;color:#6B7280;
border-top:1px solid #E5E7EB;display:flex;gap:10px;flex-wrap:wrap">
@foreach($kegiatanHariIni as $kg)
<span>📌 {{ $kg['nama'] }} ({{ $kg['waktu_mulai'] }})</span>
@endforeach
</div>
</div>
{{-- end day-block --}}
{{-- Footer stats --}} @endforeach
<div style="padding:8px 16px;background:#F8FAFC;border-top:1px solid #E5E7EB; {{-- end foreach $byTanggal --}}
font-size:11px;color:#6B7280;display:flex;gap:12px;flex-wrap:wrap">
<span>📊 {{ count($santriList) }} santri · {{ count($byTanggalSantri) }} hari</span> {{-- ══ FOOTER GLOBAL ═══════════════════════════════════════════════════════ --}}
<span> {{ $hadir }} Hadir</span> <div style="padding:10px 16px;background:#1E293B;
<span> {{ $terlambat }} Terlambat</span> font-size:11px;color:#94A3B8;display:flex;gap:14px;flex-wrap:wrap;
<span> {{ $alpa }} Alpa</span> margin-top:0;position:sticky;bottom:0;z-index:40;
box-shadow:0 -2px 8px rgba(0,0,0,.2)">
<span>📊 {{ $totalSantri }} santri · {{ count($byTanggal) }} hari</span>
<span style="color:#86EFAC"> {{ $hadirTotal }} Hadir</span>
<span style="color:#FDE68A"> {{ $terlambatTotal }} Terlambat</span>
<span style="color:#FCA5A5"> {{ $alpaTotal }} Alpa</span>
@if($totalKonflik > 0) @if($totalKonflik > 0)
<span style="color:#DC2626"> {{ $totalKonflik }} Konflik</span> <span style="color:#F87171"> <span id="footer-konflik">{{ $totalKonflik }}</span> Konflik</span>
@endif @endif
<span style="margin-left:auto"> {{-- Tampilkan toleransi dari form, bukan hardcode --}}
Toleransi: {{ $tolSebelum }}m sebelum / {{ $tolSesudah }}m sesudah <span style="margin-left:auto;color:#93C5FD">
Toleransi: {{ $tolSebelum }}m sebelum / {{ $tolSesudah }}m sesudah
</span> </span>
</div> </div>
@ -473,18 +524,22 @@ function updateUI() {
const btn = document.getElementById('saveBtn'); const btn = document.getElementById('saveBtn');
const lbl = document.getElementById('lbl'); const lbl = document.getElementById('lbl');
const chip = document.getElementById('chip'); const chip = document.getElementById('chip');
const fk = document.getElementById('footer-konflik');
if (rem <= 0) { if (rem <= 0) {
btn.disabled = false; btn.disabled = false;
btn.style.background = 'linear-gradient(135deg,#166534,#22C55E)'; btn.style.background = 'linear-gradient(135deg,#166534,#22C55E)';
btn.textContent = '💾 Simpan ke Database'; btn.textContent = '💾 Simpan ke Database';
if (lbl) lbl.innerHTML = '<span style="color:#86EFAC">✅ Semua konflik selesai</span>'; if (lbl) lbl.innerHTML = '<span style="color:#86EFAC">✅ Semua konflik selesai</span>';
if (chip) chip.textContent = '0'; if (chip) chip.textContent = '0';
if (fk) fk.textContent = '0';
} else { } else {
btn.disabled = true; btn.disabled = true;
btn.style.background = '#64748B'; btn.style.background = '#64748B';
btn.textContent = '⏳ Selesaikan ' + rem + ' konflik'; btn.textContent = '⏳ Selesaikan ' + rem + ' konflik';
if (lbl) lbl.innerHTML = '<span style="color:#FCA5A5">⚡ <span id="cnt">' + rem + '</span> konflik</span>'; if (lbl) lbl.innerHTML = '<span style="color:#FCA5A5">⚡ <span id="cnt">' + rem + '</span> konflik</span>';
if (chip) chip.textContent = rem; if (chip) chip.textContent = rem;
if (fk) fk.textContent = rem;
} }
} }
</script> </script>

View File

@ -55,7 +55,7 @@
<!-- Header --> <!-- Header -->
<div class="header"> <div class="header">
<h1>PONDOK PESANTREN PKPPS</h1> <h1>PKPPS RIYADLUL JANNAH</h1>
<h2>LAPORAN PEMBAYARAN SPP SANTRI</h2> <h2>LAPORAN PEMBAYARAN SPP SANTRI</h2>
<p>Tanggal Cetak: {{ date('d F Y, H:i') }} WIB</p> <p>Tanggal Cetak: {{ date('d F Y, H:i') }} WIB</p>
</div> </div>
@ -150,9 +150,5 @@
</tbody> </tbody>
</table> </table>
<!-- Footer -->
<div class="footer">
<p>&copy; {{ date('Y') }} Pondok Pesantren PKPPS. Laporan dicetak otomatis oleh sistem.</p>
</div>
</body> </body>
</html> </html>

View File

@ -55,9 +55,9 @@
<!-- Header --> <!-- Header -->
<div class="header"> <div class="header">
<h1>PONDOK PESANTREN PKPPS</h1> <h1>PKPPS RIYADLUL JANNAH</h1>
<h2>LAPORAN PEMBAYARAN SPP</h2> <h2>LAPORAN PEMBAYARAN SPP</h2>
<p>Tanggal Cetak: {{ date('d F Y, H:i') }} WIB</p> <p>Tanggal Cetak: {{ date('d F Y') }} WIB</p>
</div> </div>
<!-- Info Filter --> <!-- Info Filter -->
@ -159,11 +159,6 @@
</tbody> </tbody>
</table> </table>
<!-- Footer -->
<div class="footer">
<p>&copy; {{ date('Y') }} Pondok Pesantren PKPPS. Laporan dicetak otomatis oleh sistem.</p>
</div>
<script> <script>
// Auto print saat load (opsional) // Auto print saat load (opsional)
// window.onload = function() { window.print(); } // window.onload = function() { window.print(); }

View File

@ -20,7 +20,7 @@
<div class="content-box"> <div class="content-box">
{{-- ── Filter ── --}} {{-- ── Filter ── --}}
<div style="background:#f8f9fa;padding:14px;border-radius:8px;margin-bottom:14px;"> <div style="background:#f8f9fa;padding:14px;border-radius:8px;margin-bottom:14px;">
<form method="GET" action="{{ route('admin.pembayaran-spp.index') }}" style="display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end;"> <form method="GET" action="{{ route('admin.pembayaran-spp.index') }}" style="display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end;">
<input type="hidden" name="tab" value="{{ $tab }}"> <input type="hidden" name="tab" value="{{ $tab }}">
@ -66,7 +66,7 @@
</form> </form>
</div> </div>
{{-- ── KPI Cards ── --}} {{-- ── KPI Cards ── --}}
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px;margin-bottom:14px;"> <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px;margin-bottom:14px;">
<div class="kpi-card" style="background:linear-gradient(135deg,#667eea,#764ba2);"> <div class="kpi-card" style="background:linear-gradient(135deg,#667eea,#764ba2);">
<div><div class="kpi-label">Total Santri Aktif</div><div class="kpi-val">{{ $totalSantriAll }}</div><div class="kpi-sub">Periode ini</div></div> <div><div class="kpi-label">Total Santri Aktif</div><div class="kpi-val">{{ $totalSantriAll }}</div><div class="kpi-sub">Periode ini</div></div>
@ -90,7 +90,7 @@
</div> </div>
</div> </div>
{{-- ── Tab Navigation ── --}} {{-- ── Tab Navigation ── --}}
<div style="display:flex;gap:6px;margin-bottom:14px;border-bottom:2px solid #e0e0e0;flex-wrap:wrap;"> <div style="display:flex;gap:6px;margin-bottom:14px;border-bottom:2px solid #e0e0e0;flex-wrap:wrap;">
<a href="{{ route('admin.pembayaran-spp.index', array_merge(request()->except('tab'),['tab'=>'belum-bayar'])) }}" <a href="{{ route('admin.pembayaran-spp.index', array_merge(request()->except('tab'),['tab'=>'belum-bayar'])) }}"
class="spp-tab {{ $tab==='belum-bayar'?'spp-tab-danger':'spp-tab-outline-danger' }}"> class="spp-tab {{ $tab==='belum-bayar'?'spp-tab-danger':'spp-tab-outline-danger' }}">
@ -109,7 +109,7 @@ class="spp-tab {{ $tab==='sudah-bayar'?'spp-tab-success':'spp-tab-outline-succes
</a> </a>
</div> </div>
{{-- ── Action Buttons ── --}} {{-- ── Action Buttons ── --}}
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;flex-wrap:wrap;gap:8px;"> <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;flex-wrap:wrap;gap:8px;">
<div style="display:flex;gap:8px;flex-wrap:wrap;"> <div style="display:flex;gap:8px;flex-wrap:wrap;">
<a href="{{ route('admin.pembayaran-spp.generate') }}" class="btn btn-warning btn-sm"><i class="fas fa-cogs"></i> Generate SPP</a> <a href="{{ route('admin.pembayaran-spp.generate') }}" class="btn btn-warning btn-sm"><i class="fas fa-cogs"></i> Generate SPP</a>
@ -118,11 +118,11 @@ class="spp-tab {{ $tab==='sudah-bayar'?'spp-tab-success':'spp-tab-outline-succes
</div> </div>
<div style="font-size:11px;color:#666;"> <div style="font-size:11px;color:#666;">
Periode: <strong>{{ $bulanIndo[$bulan]??'' }} {{ $tahun }}</strong> Periode: <strong>{{ $bulanIndo[$bulan]??'' }} {{ $tahun }}</strong>
@if($tab==='sudah-bayar') &nbsp;·&nbsp; <i class="fas fa-sort-amount-down"></i> Terbaru bayar di atas @endif @if($tab==='sudah-bayar') &nbsp;·&nbsp; <i class="fas fa-sort-amount-down"></i> Terbaru bayar di atas @endif
</div> </div>
</div> </div>
{{-- ── Table ── --}} {{-- ── Table ── --}}
<div style="overflow-x:auto;"> <div style="overflow-x:auto;">
<div class="table-wrapper"> <div class="table-wrapper">
<table class="data-table"> <table class="data-table">
@ -195,7 +195,7 @@ class="spp-tab {{ $tab==='sudah-bayar'?'spp-tab-success':'spp-tab-outline-succes
</td> </td>
@endif @endif
{{-- ── Aksi (1 baris, tombol ikon) ── --}} {{-- ── Aksi (1 baris, tombol ikon) ── --}}
<td class="text-center" style="white-space:nowrap;"> <td class="text-center" style="white-space:nowrap;">
@if($item['pembayaran']) @if($item['pembayaran'])
{{-- Riwayat selalu ada --}} {{-- Riwayat selalu ada --}}
@ -206,8 +206,15 @@ class="spp-tab {{ $tab==='sudah-bayar'?'spp-tab-success':'spp-tab-outline-succes
<a href="{{ route('admin.pembayaran-spp.edit',$item['pembayaran']->id) }}" class="btn btn-sm btn-warning" title="Edit"><i class="fas fa-edit"></i></a> <a href="{{ route('admin.pembayaran-spp.edit',$item['pembayaran']->id) }}" class="btn btn-sm btn-warning" title="Edit"><i class="fas fa-edit"></i></a>
@elseif($tab==='cicilan') @elseif($tab==='cicilan')
{{-- FIX: gunakan route() helper, bukan hardcode URL --}}
<button type="button" class="btn btn-sm btn-purple" title="Catat Cicilan" <button type="button" class="btn btn-sm btn-purple" title="Catat Cicilan"
onclick="bukaCatatCicilan({{ $item['pembayaran']->id }},'{{ addslashes($item['nama_lengkap']) }}',{{ $item['nominal'] }},{{ $item['pembayaran']->nominal_terbayar }})"> onclick="bukaCatatCicilan(
{{ $item['pembayaran']->id }},
'{{ addslashes($item['nama_lengkap']) }}',
{{ $item['nominal'] }},
{{ $item['pembayaran']->nominal_terbayar }},
'{{ route('admin.pembayaran-spp.cicilan', $item['pembayaran']->id) }}'
)">
<i class="fas fa-coins"></i> <i class="fas fa-coins"></i>
</button> </button>
<form action="{{ route('admin.pembayaran-spp.bayar',$item['pembayaran']->id) }}" method="POST" style="display:inline;" <form action="{{ route('admin.pembayaran-spp.bayar',$item['pembayaran']->id) }}" method="POST" style="display:inline;"
@ -223,8 +230,15 @@ class="spp-tab {{ $tab==='sudah-bayar'?'spp-tab-success':'spp-tab-outline-succes
@csrf @csrf
<button type="submit" class="btn btn-sm btn-success" title="Tandai Lunas"><i class="fas fa-check"></i></button> <button type="submit" class="btn btn-sm btn-success" title="Tandai Lunas"><i class="fas fa-check"></i></button>
</form> </form>
{{-- FIX: gunakan route() helper, bukan hardcode URL --}}
<button type="button" class="btn btn-sm btn-purple" title="Catat Cicilan" <button type="button" class="btn btn-sm btn-purple" title="Catat Cicilan"
onclick="bukaCatatCicilan({{ $item['pembayaran']->id }},'{{ addslashes($item['nama_lengkap']) }}',{{ $item['nominal'] }},0)"> onclick="bukaCatatCicilan(
{{ $item['pembayaran']->id }},
'{{ addslashes($item['nama_lengkap']) }}',
{{ $item['nominal'] }},
0,
'{{ route('admin.pembayaran-spp.cicilan', $item['pembayaran']->id) }}'
)">
<i class="fas fa-coins"></i> <i class="fas fa-coins"></i>
</button> </button>
<a href="{{ route('admin.pembayaran-spp.edit',$item['pembayaran']->id) }}" class="btn btn-sm btn-warning" title="Edit"><i class="fas fa-edit"></i></a> <a href="{{ route('admin.pembayaran-spp.edit',$item['pembayaran']->id) }}" class="btn btn-sm btn-warning" title="Edit"><i class="fas fa-edit"></i></a>
@ -253,7 +267,7 @@ class="btn btn-sm btn-primary" title="Buat Tagihan"><i class="fas fa-plus"></i>
</div> </div>
</div> </div>
{{-- ── Pagination ── --}} {{-- ── Pagination ── --}}
@if($totalPages>1) @if($totalPages>1)
<div style="margin-top:14px;display:flex;justify-content:center;align-items:center;gap:10px;"> <div style="margin-top:14px;display:flex;justify-content:center;align-items:center;gap:10px;">
@if($currentPage>1) @if($currentPage>1)
@ -267,7 +281,7 @@ class="btn btn-sm btn-primary" title="Buat Tagihan"><i class="fas fa-plus"></i>
@endif @endif
</div> </div>
{{-- ── Modal Catat Cicilan ── --}} {{-- ── Modal Catat Cicilan ── --}}
<div id="modalCicilan" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:9999;align-items:center;justify-content:center;"> <div id="modalCicilan" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:9999;align-items:center;justify-content:center;">
<div style="background:#fff;border-radius:12px;padding:24px;width:100%;max-width:400px;box-shadow:0 20px 60px rgba(0,0,0,.3);margin:16px;"> <div style="background:#fff;border-radius:12px;padding:24px;width:100%;max-width:400px;box-shadow:0 20px 60px rgba(0,0,0,.3);margin:16px;">
<h4 style="margin:0 0 4px;"><i class="fas fa-coins" style="color:#9c27b0;"></i> Catat Cicilan</h4> <h4 style="margin:0 0 4px;"><i class="fas fa-coins" style="color:#9c27b0;"></i> Catat Cicilan</h4>
@ -305,7 +319,6 @@ class="btn btn-sm btn-primary" title="Buat Tagihan"><i class="fas fa-plus"></i>
.kpi-sub { font-size:11px;opacity:.8; } .kpi-sub { font-size:11px;opacity:.8; }
.kpi-icon { font-size:26px;opacity:.25; } .kpi-icon { font-size:26px;opacity:.25; }
/* Tabs */ /* Tabs */
.spp-tab { .spp-tab {
display:inline-flex; align-items:center; gap:6px; display:inline-flex; align-items:center; gap:6px;
padding:8px 14px; border-radius:8px 8px 0 0; padding:8px 14px; border-radius:8px 8px 0 0;
@ -350,19 +363,26 @@ class="btn btn-sm btn-primary" title="Buat Tagihan"><i class="fas fa-plus"></i>
<script> <script>
function fmt(n) { return 'Rp ' + parseInt(n).toLocaleString('id-ID'); } function fmt(n) { return 'Rp ' + parseInt(n).toLocaleString('id-ID'); }
function bukaCatatCicilan(id, nama, tagihan, terbayar) {
{{-- FIX: parameter ke-5 sekarang menerima URL dari route() helper Laravel --}}
function bukaCatatCicilan(id, nama, tagihan, terbayar, routeUrl) {
document.getElementById('modalNama').textContent = nama; document.getElementById('modalNama').textContent = nama;
document.getElementById('mTagihan').textContent = fmt(tagihan); document.getElementById('mTagihan').textContent = fmt(tagihan);
document.getElementById('mTerbayar').textContent = fmt(terbayar); document.getElementById('mTerbayar').textContent = fmt(terbayar);
document.getElementById('mSisa').textContent = fmt(tagihan - terbayar); document.getElementById('mSisa').textContent = fmt(tagihan - terbayar);
document.getElementById('inputNominal').max = tagihan - terbayar; document.getElementById('inputNominal').max = tagihan - terbayar;
document.getElementById('formCicilan').action = '/admin/pembayaran-spp/' + id + '/cicilan';
{{-- FIX: set action dari routeUrl yang sudah di-generate oleh blade, bukan hardcode --}}
document.getElementById('formCicilan').action = routeUrl;
var modal = document.getElementById('modalCicilan'); var modal = document.getElementById('modalCicilan');
modal.style.display = 'flex'; modal.style.display = 'flex';
} }
function tutupModal() { function tutupModal() {
document.getElementById('modalCicilan').style.display = 'none'; document.getElementById('modalCicilan').style.display = 'none';
} }
document.getElementById('modalCicilan').addEventListener('click', function(e) { document.getElementById('modalCicilan').addEventListener('click', function(e) {
if (e.target === this) tutupModal(); if (e.target === this) tutupModal();
}); });

View File

@ -50,39 +50,12 @@
<i class="fas fa-print"></i> Cetak Laporan <i class="fas fa-print"></i> Cetak Laporan
</button> </button>
</form> </form>
</div>
<!-- Laporan Per Santri -->
<div class="card card-success hover-lift">
<h3>Laporan Per Santri</h3>
<p style="margin: 10px 0; color: var(--text-light);">
Cetak laporan pembayaran SPP untuk santri tertentu
</p>
<form action="{{ route('admin.pembayaran-spp.cetak-laporan-santri', ':id') }}" method="GET" id="form-santri" target="_blank">
<div class="form-group">
<label><i class="fas fa-user form-icon"></i> Pilih Santri</label>
<select name="id_santri" id="select-santri" class="form-control" required>
<option value="">-- Pilih Santri --</option>
@foreach(\App\Models\Santri::orderBy('nama_lengkap')->get() as $santri)
<option value="{{ $santri->id_santri }}">
{{ $santri->nama_lengkap }} ({{ $santri->id_santri }})
</option>
@endforeach
</select>
</div>
<button type="submit" class="btn btn-success hover-shadow" style="width: 100%;">
<i class="fas fa-print"></i> Cetak Laporan Santri
</button>
</form>
</div>
</div>
<div class="content-box" style="margin-top: 25px;"> <div class="content-box" style="margin-top: 25px;">
<a href="{{ route('admin.pembayaran-spp.index') }}" class="btn btn-secondary"> <a href="{{ route('admin.pembayaran-spp.index') }}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali <i class="fas fa-arrow-left"></i> Kembali
</a> </a>
</div> </div>
</div>
@push('scripts') @push('scripts')
<script> <script>

View File

@ -44,7 +44,34 @@
<td>{{ $user->santri->nama_lengkap ?? '-' }}</td> <td>{{ $user->santri->nama_lengkap ?? '-' }}</td>
<td>{{ $user->santri->nis ?? '-' }}</td> <td>{{ $user->santri->nis ?? '-' }}</td>
<td><code>{{ $user->username }}</code></td> <td><code>{{ $user->username }}</code></td>
<td> <td style="white-space:nowrap;">
{{-- Tombol Kirim WA --}}
@if($user->santri && $user->santri->nomor_hp_ortu)
@php
$noHp = preg_replace('/[^0-9]/', '', $user->santri->nomor_hp_ortu);
if (str_starts_with($noHp, '0')) {
$noHp = '62' . substr($noHp, 1);
}
$pesan = rawurlencode(
"Halo, berikut informasi akun website PKPPS Riyadlul Jannah atas nama {$user->santri->nama_lengkap}.\n\n"
. "Username: {$user->username}\n"
. "Password: {$user->santri->nis}\n\n"
. "Silakan gunakan informasi di atas untuk login ke portal web PKPPS Riyadlul Jannah."
);
@endphp
<a href="https://wa.me/{{ $noHp }}?text={{ $pesan }}"
target="_blank"
class="btn btn-sm btn-success"
title="Kirim info akun via WhatsApp">
<i class="fas fa-share-alt"></i> Kirim
</a>
@else
<span class="text-muted" title="Nomor HP ortu belum diisi">
<i class="fas fa-share-alt"></i> -
</span>
@endif
{{-- Tombol Hapus --}}
<form action="{{ route('admin.users.santri_destroy', $user->id) }}" <form action="{{ route('admin.users.santri_destroy', $user->id) }}"
method="POST" style="display:inline;" method="POST" style="display:inline;"
onsubmit="return confirm('Yakin hapus akun santri {{ $user->santri->nama_lengkap ?? '' }}?')"> onsubmit="return confirm('Yakin hapus akun santri {{ $user->santri->nama_lengkap ?? '' }}?')">
@ -82,7 +109,6 @@
@endif @endif
<div class="table-wrapper"> <div class="table-wrapper">
<table class="data-table"> <table class="data-table">
<thead> <thead>
<tr> <tr>
@ -130,7 +156,6 @@
@endforelse @endforelse
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
@endsection @endsection

View File

@ -48,7 +48,34 @@
<td>{{ $user->santri->nama_orang_tua ?? '-' }}</td> <td>{{ $user->santri->nama_orang_tua ?? '-' }}</td>
<td>{{ $user->santri->nis ?? '-' }}</td> <td>{{ $user->santri->nis ?? '-' }}</td>
<td><code>{{ $user->username }}</code></td> <td><code>{{ $user->username }}</code></td>
<td> <td style="white-space:nowrap;">
{{-- Tombol Kirim WA --}}
@if($user->santri && $user->santri->nomor_hp_ortu)
@php
$noHp = preg_replace('/[^0-9]/', '', $user->santri->nomor_hp_ortu);
if (str_starts_with($noHp, '0')) {
$noHp = '62' . substr($noHp, 1);
}
$pesan = rawurlencode(
"Halo, berikut informasi akun mobile app PKPPS Riyadlul Jannah untuk wali dari {$user->santri->nama_lengkap}.\n\n"
. "Username: {$user->username}\n"
. "Password: {$user->santri->nis}\n\n"
. "Silakan gunakan informasi di atas untuk login ke aplikasi mobile PKPPS Riyadlul Jannah"
);
@endphp
<a href="https://wa.me/{{ $noHp }}?text={{ $pesan }}"
target="_blank"
class="btn btn-sm btn-success"
title="Kirim info akun via WhatsApp">
<i class="fas fa-share-alt"></i> Kirim
</a>
@else
<span class="text-muted" title="Nomor HP ortu belum diisi">
<i class="fas fa-share-alt"></i> -
</span>
@endif
{{-- Tombol Hapus --}}
<form action="{{ route('admin.users.wali_destroy', $user->id) }}" <form action="{{ route('admin.users.wali_destroy', $user->id) }}"
method="POST" style="display:inline;" method="POST" style="display:inline;"
onsubmit="return confirm('Yakin hapus akun wali {{ $user->santri->nama_lengkap ?? '' }}?')"> onsubmit="return confirm('Yakin hapus akun wali {{ $user->santri->nama_lengkap ?? '' }}?')">
@ -86,8 +113,6 @@
@endif @endif
@php @php
// Kumpulkan nama ortu yang sudah dipakai di akun existing
// untuk preview username yang akan dibuat
$namaOrtuSudahAda = \App\Models\SantriAccount::where('role', 'wali') $namaOrtuSudahAda = \App\Models\SantriAccount::where('role', 'wali')
->pluck('username') ->pluck('username')
->toArray(); ->toArray();
@ -95,7 +120,6 @@
@endphp @endphp
<div class="table-wrapper"> <div class="table-wrapper">
<table class="data-table"> <table class="data-table">
<thead> <thead>
<tr> <tr>
@ -111,7 +135,6 @@
<tbody> <tbody>
@forelse ($santris_tanpa_wali as $santri) @forelse ($santris_tanpa_wali as $santri)
@php @php
// Preview username: sama persis dgn logika resolveUsernameWali() di controller
$previewUsername = null; $previewUsername = null;
if ($santri->nama_orang_tua) { if ($santri->nama_orang_tua) {
$usernameDefault = $santri->nama_orang_tua; $usernameDefault = $santri->nama_orang_tua;
@ -172,7 +195,6 @@
@endforelse @endforelse
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
@endsection @endsection

View File

@ -48,7 +48,12 @@
.kg-badge.fire { background:linear-gradient(135deg,#f59e0b,#f97316); border:none; } .kg-badge.fire { background:linear-gradient(135deg,#f59e0b,#f97316); border:none; }
/* ── KPI CARDS ── */ /* ── KPI CARDS ── */
.kg-kpi-row { display:grid; grid-template-columns:repeat(5,1fr); gap:10px; margin-bottom:16px; } .kg-kpi-row {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 10px;
margin-bottom: 16px;
}
.kg-kpi { background:white; border-radius:12px; padding:14px 12px; box-shadow:var(--sh); text-align:center; border-top:3px solid transparent; transition:transform 0.18s,box-shadow 0.18s; } .kg-kpi { background:white; border-radius:12px; padding:14px 12px; box-shadow:var(--sh); text-align:center; border-top:3px solid transparent; transition:transform 0.18s,box-shadow 0.18s; }
.kg-kpi:hover { transform:translateY(-3px); box-shadow:var(--shl); } .kg-kpi:hover { transform:translateY(-3px); box-shadow:var(--shl); }
.kg-kpi.c-green { border-top-color:#2bbd8e; } .kg-kpi.c-green { border-top-color:#2bbd8e; }
@ -87,8 +92,8 @@
.kg-preset-btn { padding:6px 12px; border:1.5px solid var(--br); border-radius:8px; background:white; font-size:0.79rem; font-weight:600; color:var(--mu); cursor:pointer; transition:all 0.15s; white-space:nowrap; } .kg-preset-btn { padding:6px 12px; border:1.5px solid var(--br); border-radius:8px; background:white; font-size:0.79rem; font-weight:600; color:var(--mu); cursor:pointer; transition:all 0.15s; white-space:nowrap; }
.kg-preset-btn:hover { border-color:var(--m); color:var(--g); background:var(--sf); } .kg-preset-btn:hover { border-color:var(--m); color:var(--g); background:var(--sf); }
.kg-preset-btn.active { border-color:var(--g); background:var(--g); color:white; } .kg-preset-btn.active { border-color:var(--g); background:var(--g); color:white; }
.kg-date-range { display:flex; align-items:center; gap:5px; } .kg-date-range { display:flex; align-items:center; gap:5px; flex-wrap:wrap; }
.kg-date-range input[type=date] { padding:6px 9px; border:1.5px solid var(--br); border-radius:8px; font-size:0.8rem; color:var(--tx); background:white; } .kg-date-range input[type=date] { padding:6px 9px; border:1.5px solid var(--br); border-radius:8px; font-size:0.8rem; color:var(--tx); background:white; min-width:0; max-width:140px; width:100%; }
.kg-date-range input[type=date]:focus { outline:none; border-color:var(--m); } .kg-date-range input[type=date]:focus { outline:none; border-color:var(--m); }
.kg-date-range span { color:var(--mu); font-size:0.79rem; font-weight:600; } .kg-date-range span { color:var(--mu); font-size:0.79rem; font-weight:600; }
.kg-apply-btn { padding:7px 15px; background:var(--g); color:white; border:none; border-radius:8px; font-size:0.81rem; font-weight:700; cursor:pointer; display:inline-flex; align-items:center; gap:5px; } .kg-apply-btn { padding:7px 15px; background:var(--g); color:white; border:none; border-radius:8px; font-size:0.81rem; font-weight:700; cursor:pointer; display:inline-flex; align-items:center; gap:5px; }
@ -100,7 +105,7 @@
.kg-jadwal-group { margin-bottom:14px; } .kg-jadwal-group { margin-bottom:14px; }
.kg-hari-label { font-size:0.77rem; font-weight:700; text-transform:uppercase; letter-spacing:0.8px; color:var(--g); padding:5px 11px; background:var(--sf); border-radius:8px; margin-bottom:8px; display:inline-flex; align-items:center; gap:5px; } .kg-hari-label { font-size:0.77rem; font-weight:700; text-transform:uppercase; letter-spacing:0.8px; color:var(--g); padding:5px 11px; background:var(--sf); border-radius:8px; margin-bottom:8px; display:inline-flex; align-items:center; gap:5px; }
.kg-hari-label.today-label { background:var(--g); color:white; } .kg-hari-label.today-label { background:var(--g); color:white; }
.kg-jadwal-card { background:white; border-radius:11px; padding:13px 15px; box-shadow:var(--sh); display:flex; align-items:center; gap:12px; border-left:4px solid var(--br); margin-bottom:7px; transition:transform 0.16s; } .kg-jadwal-card { background:white; border-radius:11px; padding:13px 15px; box-shadow:var(--sh); display:flex; align-items:center; gap:12px; border-left:4px solid var(--br); margin-bottom:7px; transition:transform 0.16s; flex-wrap:wrap; }
.kg-jadwal-card:hover { transform:translateX(3px); } .kg-jadwal-card:hover { transform:translateX(3px); }
.kg-jadwal-card.s-hadir { border-left-color:#2bbd8e; } .kg-jadwal-card.s-hadir { border-left-color:#2bbd8e; }
.kg-jadwal-card.s-terlambat { border-left-color:#f59e0b; } .kg-jadwal-card.s-terlambat { border-left-color:#f59e0b; }
@ -109,7 +114,7 @@
.kg-jadwal-card.s-alpa { border-left-color:#e53e3e; } .kg-jadwal-card.s-alpa { border-left-color:#e53e3e; }
.kg-jadwal-card.s-pulang { border-left-color:#0d9488; } .kg-jadwal-card.s-pulang { border-left-color:#0d9488; }
.kg-jadwal-card.s-belum { border-left-color:#f5a623; } .kg-jadwal-card.s-belum { border-left-color:#f5a623; }
.kg-time { min-width:58px; text-align:center; } .kg-time { min-width:58px; text-align:center; flex-shrink:0; }
.kg-time-main { font-size:0.93rem; font-weight:700; color:var(--g); } .kg-time-main { font-size:0.93rem; font-weight:700; color:var(--g); }
.kg-time-end { font-size:0.71rem; color:var(--mu); font-weight:500; } .kg-time-end { font-size:0.71rem; color:var(--mu); font-weight:500; }
.kg-divider { width:1px; height:34px; background:var(--br); flex-shrink:0; } .kg-divider { width:1px; height:34px; background:var(--br); flex-shrink:0; }
@ -126,7 +131,7 @@
.kg-detail-btn:hover { background:#155c47; } .kg-detail-btn:hover { background:#155c47; }
/* Pill status */ /* Pill status */
.kpill { padding:3px 11px; border-radius:20px; font-size:0.75rem; font-weight:700; flex-shrink:0; } .kpill { padding:3px 11px; border-radius:20px; font-size:0.75rem; font-weight:700; flex-shrink:0; white-space:nowrap; }
.kpill.hadir { background:#d1fae5; color:#065f46; } .kpill.hadir { background:#d1fae5; color:#065f46; }
.kpill.terlambat { background:#fef3c7; color:#92400e; } .kpill.terlambat { background:#fef3c7; color:#92400e; }
.kpill.belum { background:#fef3c7; color:#92400e; } .kpill.belum { background:#fef3c7; color:#92400e; }
@ -140,6 +145,17 @@
.kg-chart-box { background:white; border-radius:12px; padding:18px; box-shadow:var(--sh); } .kg-chart-box { background:white; border-radius:12px; padding:18px; box-shadow:var(--sh); }
.kg-chart-title { font-size:0.86rem; font-weight:700; color:var(--tx); margin-bottom:14px; display:flex; align-items:center; gap:6px; } .kg-chart-title { font-size:0.86rem; font-weight:700; color:var(--tx); margin-bottom:14px; display:flex; align-items:center; gap:6px; }
/* ── ABSENSI TERBARU + KALENDER GRID ──
Ini yang diperbaiki: pakai class bukan inline style
agar bisa di-override via media query */
.kg-recent-cal-grid {
display: grid;
grid-template-columns: 1fr 220px;
gap: 14px;
margin-bottom: 14px;
align-items: start;
}
/* ── RECENT ABSENSI ── */ /* ── RECENT ABSENSI ── */
.kg-recent-list { display:flex; flex-direction:column; gap:6px; } .kg-recent-list { display:flex; flex-direction:column; gap:6px; }
.kg-recent-item { .kg-recent-item {
@ -172,7 +188,10 @@
.kg-recent-date { font-size:0.69rem; color:var(--mu); opacity:0.7; margin-top:3px; } .kg-recent-date { font-size:0.69rem; color:var(--mu); opacity:0.7; margin-top:3px; }
/* ── MINI CALENDAR ── */ /* ── MINI CALENDAR ── */
.kg-cal-mini { width:220px; flex-shrink:0; } .kg-cal-mini {
flex-shrink: 0;
/* width dikontrol oleh grid-column di atas, tidak perlu fixed width */
}
.kg-cal-mini-grid { display:grid; grid-template-columns:repeat(7,1fr); gap:2px; } .kg-cal-mini-grid { display:grid; grid-template-columns:repeat(7,1fr); gap:2px; }
.kg-cal-mini-dname { text-align:center; font-size:0.6rem; font-weight:700; color:var(--mu); padding-bottom:3px; text-transform:uppercase; } .kg-cal-mini-dname { text-align:center; font-size:0.6rem; font-weight:700; color:var(--mu); padding-bottom:3px; text-transform:uppercase; }
.kg-cal-mini-cell { aspect-ratio:1; border-radius:4px; display:flex; align-items:center; justify-content:center; font-size:0.63rem; font-weight:600; cursor:default; transition:transform 0.1s; } .kg-cal-mini-cell { aspect-ratio:1; border-radius:4px; display:flex; align-items:center; justify-content:center; font-size:0.63rem; font-weight:600; cursor:default; transition:transform 0.1s; }
@ -189,9 +208,84 @@
.kg-empty { text-align:center; padding:36px 20px; color:var(--mu); background:white; border-radius:12px; box-shadow:var(--sh); } .kg-empty { text-align:center; padding:36px 20px; color:var(--mu); background:white; border-radius:12px; box-shadow:var(--sh); }
.kg-empty i { font-size:2.8rem; opacity:0.2; display:block; margin-bottom:10px; } .kg-empty i { font-size:2.8rem; opacity:0.2; display:block; margin-bottom:10px; }
@media (max-width:768px) { /* ════════════════════════════════════
RESPONSIVE
════════════════════════════════════ */
/* Tablet (≤ 900px) */
@media (max-width: 900px) {
.kg-kpi-row { grid-template-columns: repeat(3, 1fr); } .kg-kpi-row { grid-template-columns: repeat(3, 1fr); }
/* Kalender turun ke bawah absensi terbaru */
.kg-recent-cal-grid {
grid-template-columns: 1fr;
}
/* Kalender full width saat di bawah */
.kg-cal-mini {
width: 100%;
}
/* Grid kalender isi penuh */
.kg-cal-mini-grid {
max-width: 320px;
margin: 0 auto;
}
}
/* Tablet kecil / HP landscape (≤ 768px) */
@media (max-width: 768px) {
.kg-kpi-row { grid-template-columns: repeat(3, 1fr); gap: 8px; }
.kg-stat-grid { grid-template-columns: 1fr; } .kg-stat-grid { grid-template-columns: 1fr; }
.kg-hero { padding: 18px 16px 16px; }
.kg-hero-title { font-size: 1.05rem; }
.kg-tab-filter { padding: 10px 12px; gap: 6px; }
.kg-fg { width: 100%; }
.kg-date-range { width: 100%; }
.kg-date-range input[type=date] { flex: 1; max-width: none; }
.kg-apply-btn { width: 100%; justify-content: center; }
.kg-filter-label { width: 100%; justify-content: center; }
/* Jadwal card: susun vertikal di HP */
.kg-jadwal-card { gap: 8px; }
.kg-divider { display: none; }
}
/* HP portrait (≤ 480px) */
@media (max-width: 480px) {
.kg-kpi-row {
grid-template-columns: repeat(2, 1fr);
gap: 8px;
}
/* Nilai KPI sedikit lebih kecil biar muat */
.kg-kpi-v { font-size: 1.35rem; }
.kg-kpi-l { font-size: 0.66rem; }
.kg-kpi { padding: 11px 8px; }
.kg-kpi-ic { width: 30px; height: 30px; font-size: 0.8rem; }
.kg-hero { padding: 14px 13px 13px; }
.kg-hero-title { font-size: 0.95rem; }
.kg-hero-sub { font-size: 0.77rem; }
/* Recent item: sembunyikan icon di HP kecil agar nama tidak terpotong */
.kg-recent-ic { display: none; }
.kg-recent-item { gap: 8px; padding: 8px 10px; }
.kg-recent-name { font-size: 0.8rem; }
.kg-recent-meta { font-size: 0.67rem; gap: 5px; }
.kpill { font-size: 0.68rem; padding: 2px 7px; }
.kg-chart-box { padding: 13px; }
.kg-jadwal-card { padding: 10px 12px; }
.kg-jname { font-size: 0.82rem; }
}
/* Sangat kecil (≤ 360px) */
@media (max-width: 360px) {
.kg-kpi-row { grid-template-columns: repeat(2, 1fr); gap: 6px; }
.kg-kpi-v { font-size: 1.2rem; }
.kg-kpi { padding: 9px 6px; }
} }
</style> </style>
@ -254,7 +348,7 @@
</div> </div>
</div> </div>
{{-- ── TABS 2 tab saja ── --}} {{-- ── TABS ── --}}
<div class="kg-tabs"> <div class="kg-tabs">
<button class="kg-tab {{ $activeTab === 'statistik' ? 'active' : '' }}" onclick="switchTab('statistik',this)"> <button class="kg-tab {{ $activeTab === 'statistik' ? 'active' : '' }}" onclick="switchTab('statistik',this)">
<i class="fas fa-chart-bar"></i> Statistik <i class="fas fa-chart-bar"></i> Statistik
@ -309,7 +403,9 @@
<div class="kg-chart-box"> <div class="kg-chart-box">
<div class="kg-chart-title"> <div class="kg-chart-title">
<i class="fas fa-chart-line" style="color:var(--m);"></i> Tren Kehadiran <i class="fas fa-chart-line" style="color:var(--m);"></i> Tren Kehadiran
<span style="margin-left:auto;font-size:0.73rem;color:var(--mu);font-weight:500;">{{ $diffDays<=31?'Harian':'Mingguan' }}</span> <span style="margin-left:auto;font-size:0.73rem;color:var(--mu);font-weight:500;">
{{ $diffDays <= 31 ? 'Harian' : 'Mingguan' }}
</span>
</div> </div>
<canvas id="chartTren" style="max-height:220px;"></canvas> <canvas id="chartTren" style="max-height:220px;"></canvas>
</div> </div>
@ -319,8 +415,10 @@
</div> </div>
</div> </div>
{{-- Absensi Terbaru + Kalender --}} {{-- ── Absensi Terbaru + Kalender ──
<div style="display:grid; grid-template-columns:1fr auto; gap:14px; margin-bottom:14px; align-items:start;"> Pakai class .kg-recent-cal-grid (bukan inline style)
agar breakpoint CSS bisa meng-override ke 1 kolom --}}
<div class="kg-recent-cal-grid">
{{-- Catatan Absensi Terbaru --}} {{-- Catatan Absensi Terbaru --}}
<div class="kg-chart-box" style="min-width:0;"> <div class="kg-chart-box" style="min-width:0;">
@ -457,7 +555,9 @@
<div class="kg-jadwal-group"> <div class="kg-jadwal-group">
<div class="kg-hari-label {{ $hari === $hariIni ? 'today-label' : '' }}"> <div class="kg-hari-label {{ $hari === $hariIni ? 'today-label' : '' }}">
<i class="fas fa-calendar-day"></i> {{ $hari }} <i class="fas fa-calendar-day"></i> {{ $hari }}
@if($hari === $hariIni) <span style="font-size:0.66rem;opacity:0.85;">(Hari Ini)</span> @endif @if($hari === $hariIni)
<span style="font-size:0.66rem;opacity:0.85;">(Hari Ini)</span>
@endif
</div> </div>
@foreach($jadwals as $jadwal) @foreach($jadwals as $jadwal)
@php @php
@ -481,7 +581,6 @@
@endif @endif
</div> </div>
</div> </div>
{{-- Status pill --}}
@if($statusAbsen) @if($statusAbsen)
<span class="kpill {{ strtolower($statusAbsen) }}"> <span class="kpill {{ strtolower($statusAbsen) }}">
@if($statusAbsen === 'Terlambat') <i class="fas fa-clock"></i> @if($statusAbsen === 'Terlambat') <i class="fas fa-clock"></i>
@ -492,7 +591,6 @@
@elseif($hari === $hariIni) @elseif($hari === $hariIni)
<span class="kpill belum"><i class="fas fa-hourglass-half"></i> Belum</span> <span class="kpill belum"><i class="fas fa-hourglass-half"></i> Belum</span>
@endif @endif
{{-- Tombol Detail ke show() --}}
<a href="{{ route('santri.kegiatan.show', $jadwal->kegiatan_id) }}?from_tab=jadwal" <a href="{{ route('santri.kegiatan.show', $jadwal->kegiatan_id) }}?from_tab=jadwal"
class="kg-detail-btn"> class="kg-detail-btn">
<i class="fas fa-chart-bar"></i> Detail <i class="fas fa-chart-bar"></i> Detail
@ -511,7 +609,6 @@ class="kg-detail-btn">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script> <script>
// ── TAB SWITCHER ─────────────────────────────────
function switchTab(name, el) { function switchTab(name, el) {
document.querySelectorAll('.kg-tab').forEach(t => t.classList.remove('active')); document.querySelectorAll('.kg-tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.kg-panel').forEach(p => p.classList.remove('active')); document.querySelectorAll('.kg-panel').forEach(p => p.classList.remove('active'));
@ -520,7 +617,6 @@ function switchTab(name, el) {
if (name === 'statistik' && !window._chartsInit) { initCharts(); window._chartsInit = true; } if (name === 'statistik' && !window._chartsInit) { initCharts(); window._chartsInit = true; }
} }
// ── PRESET SETTER ────────────────────────────────
function setPreset(scope, val) { function setPreset(scope, val) {
document.querySelectorAll('#' + scope + 'Presets .kg-preset-btn').forEach(b => b.classList.remove('active')); document.querySelectorAll('#' + scope + 'Presets .kg-preset-btn').forEach(b => b.classList.remove('active'));
event.target.classList.add('active'); event.target.classList.add('active');
@ -539,7 +635,6 @@ function setCustom(scope) {
document.querySelectorAll('#' + scope + 'Presets .kg-preset-btn').forEach(b => b.classList.remove('active')); document.querySelectorAll('#' + scope + 'Presets .kg-preset-btn').forEach(b => b.classList.remove('active'));
} }
// ── CHARTS ───────────────────────────────────────
function initCharts() { function initCharts() {
const trenLabels = @json(collect($dataGrafik)->pluck('label')); const trenLabels = @json(collect($dataGrafik)->pluck('label'));
const trenHadir = @json(collect($dataGrafik)->pluck('hadir')); const trenHadir = @json(collect($dataGrafik)->pluck('hadir'));
@ -611,7 +706,6 @@ function initCharts() {
}); });
} }
// ── INIT ─────────────────────────────────────────
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
var tab = new URLSearchParams(window.location.search).get('tab') || 'statistik'; var tab = new URLSearchParams(window.location.search).get('tab') || 'statistik';
var map = { statistik: 0, jadwal: 1 }; var map = { statistik: 0, jadwal: 1 };

View File

@ -0,0 +1 @@
a:4:{s:6:"_token";s:40:"Rogr1HsMSukvmYR2m3b7pPraVOehwZvcU2GYYNaA";s:9:"_previous";a:1:{s:3:"url";s:44:"http://127.0.0.1:8000/admin/laporan-kegiatan";}s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}s:50:"login_web_59ba36addc2b2f9401580f014c7f58ea4e30989d";i:1;}

View File

@ -0,0 +1 @@
a:3:{s:6:"_token";s:40:"z2Q3wuWmkF9oCYl0WHpsIaXywzR0FjwyltHaEHA1";s:9:"_previous";a:1:{s:3:"url";s:34:"http://127.0.0.1:8000/santri/login";}s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}}

View File

@ -0,0 +1 @@
a:4:{s:6:"_token";s:40:"TiMKyzlAzRLRL9vdvNjuuT4zMOD7QGCBKyJKG7lC";s:3:"url";a:1:{s:8:"intended";s:58:"http://localhost/admin/laporan-kegiatan?periode=minggu_ini";}s:9:"_previous";a:1:{s:3:"url";s:58:"http://localhost/admin/laporan-kegiatan?periode=minggu_ini";}s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}}

View File

@ -1 +1 @@
a:3:{s:6:"_token";s:40:"TPUzTdhC3a0zTqKnoC2h8FNhcf5pYPmSXvPiSVKO";s:6:"_flash";a:2:{s:3:"new";a:0:{}s:3:"old";a:0:{}}s:9:"_previous";a:1:{s:3:"url";s:33:"http://127.0.0.1:8000/admin/login";}} a:3:{s:6:"_token";s:40:"38E76quLNOyMUAX08jBlb63KKtrUj910NO6H7reC";s:6:"_flash";a:2:{s:3:"new";a:0:{}s:3:"old";a:0:{}}s:9:"_previous";a:1:{s:3:"url";s:33:"http://127.0.0.1:8000/admin/login";}}

View File

@ -0,0 +1 @@
a:4:{s:6:"_token";s:40:"JkoSzSFooBHlizoZQ1QgxXKBUyzQsoduDjvLAUrc";s:9:"_previous";a:1:{s:3:"url";s:38:"http://127.0.0.1:8000/admin/kepulangan";}s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}s:50:"login_web_59ba36addc2b2f9401580f014c7f58ea4e30989d";i:1;}

View File

@ -1 +0,0 @@
a:3:{s:6:"_token";s:40:"sl0M4vZdqyldTB5GLbTu6mj3iC3fdQImAkTcALm1";s:6:"_flash";a:2:{s:3:"new";a:0:{}s:3:"old";a:0:{}}s:9:"_previous";a:1:{s:3:"url";s:34:"http://127.0.0.1:8000/santri/login";}}

View File

@ -1,285 +0,0 @@
<?php $__env->startSection('content'); ?>
<style>
.access-hero {
border-radius: 14px;
padding: 24px 28px;
margin-bottom: 18px;
display: flex;
align-items: center;
gap: 20px;
position: relative;
overflow: hidden;
}
.access-hero.open { background: linear-gradient(135deg, #e8f5e9, #c8e6c9); border: 2px solid #66bb6a; }
.access-hero.closed { background: linear-gradient(135deg, #fff3e0, #ffe0b2); border: 2px solid #ffa726; }
.access-hero .ah-icon { font-size: 3.5rem; flex-shrink: 0; }
.access-hero h3 { margin: 0 0 5px; font-size: 1.15rem; }
.access-hero p { margin: 0; font-size: 0.85rem; color: #555; }
.status-badge-big {
display: inline-flex; align-items: center; gap: 8px;
padding: 8px 22px; border-radius: 25px; font-weight: 800;
font-size: 1rem; margin-bottom: 10px;
}
.status-badge-big.open { background: #2e7d32; color: #fff; }
.status-badge-big.closed { background: #e65100; color: #fff; }
.info-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 12px;
margin-bottom: 18px;
}
.info-box {
background: #fff;
border-radius: 10px;
padding: 14px 16px;
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
border-left: 4px solid;
}
.info-box .ib-label { font-size: 0.72rem; color: #999; text-transform: uppercase; margin-bottom: 4px; }
.info-box .ib-val { font-size: 0.92rem; font-weight: 700; color: #333; }
.form-card {
background: #fff;
border-radius: 12px;
padding: 22px;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
margin-bottom: 16px;
border: 1px solid #e8f0ec;
}
.form-card h4 { margin: 0 0 16px; color: var(--primary-dark); font-size: 1rem; }
.toggle-btn {
display: inline-flex; align-items: center; gap: 8px;
padding: 11px 28px; border-radius: 10px; border: none;
font-weight: 700; font-size: 0.9rem; cursor: pointer;
transition: all .2s;
}
.toggle-btn:hover { transform: translateY(-2px); box-shadow: 0 6px 18px rgba(0,0,0,0.15); }
.toggle-btn.open-btn { background: linear-gradient(135deg, #43a047, #2e7d32); color: #fff; }
.toggle-btn.close-btn { background: linear-gradient(135deg, #ef5350, #c62828); color: #fff; }
.countdown-bar {
height: 10px; background: #f0f0f0;
border-radius: 20px; overflow: hidden; margin-top: 8px;
}
.countdown-fill {
height: 100%; border-radius: 20px;
background: linear-gradient(90deg, #66bb6a, #2e7d32);
transition: width .5s;
}
</style>
<div class="page-header" style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:10px;">
<h2><i class="fas fa-unlock-alt"></i> Kelola Akses Input Capaian Santri</h2>
<a href="<?php echo e(route('admin.capaian.index')); ?>" class="btn btn-secondary" style="padding:7px 16px;">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success"><i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?></div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger"><i class="fas fa-exclamation-circle"></i> <?php echo e(session('error')); ?></div>
<?php endif; ?>
<div class="access-hero <?php echo e($isOpen ? 'open' : 'closed'); ?>">
<div class="ah-icon"><?php echo e($isOpen ? '🔓' : '🔒'); ?></div>
<div style="flex:1;">
<div class="status-badge-big <?php echo e($isOpen ? 'open' : 'closed'); ?>">
<i class="fas fa-<?php echo e($isOpen ? 'lock-open' : 'lock'); ?>"></i>
<?php echo e($isOpen ? 'AKSES DIBUKA' : 'AKSES DITUTUP'); ?>
</div>
<h3>
<?php if($isOpen): ?>
Santri sedang bisa menginputkan capaian mereka
<?php else: ?>
Santri belum bisa menginputkan capaian
<?php endif; ?>
</h3>
<p>
<?php if($isOpen): ?>
Dibuka oleh <strong><?php echo e($config['opened_by'] ?? '-'); ?></strong>
pada <?php echo e($config['opened_at'] ? \Carbon\Carbon::parse($config['opened_at'])->isoFormat('D MMM YYYY, HH:mm') : '-'); ?>
<?php if($config['id_semester']): ?>
&bull; Semester: <strong><?php echo e(\App\Models\Semester::where('id_semester', $config['id_semester'])->value('nama_semester') ?? '-'); ?></strong>
<?php else: ?>
&bull; Semua semester diizinkan
<?php endif; ?>
<?php if($sisaWaktu): ?>
&bull; Sisa waktu: <strong><?php echo e($sisaWaktu); ?></strong>
<?php endif; ?>
<?php else: ?>
<?php if($config['closed_at']): ?>
Ditutup pada <?php echo e(\Carbon\Carbon::parse($config['closed_at'])->isoFormat('D MMM YYYY, HH:mm')); ?>
<?php else: ?>
Belum pernah dibuka
<?php endif; ?>
<?php endif; ?>
</p>
<?php if(!empty($config['catatan'])): ?>
<p style="margin-top:6px;font-style:italic;"><i class="fas fa-sticky-note"></i> "<?php echo e($config['catatan']); ?>"</p>
<?php endif; ?>
</div>
</div>
<div class="info-row">
<div class="info-box" style="border-color:#66bb6a;">
<div class="ib-label">Status</div>
<div class="ib-val" style="color:<?php echo e($isOpen ? '#2e7d32' : '#c62828'); ?>;">
<i class="fas fa-<?php echo e($isOpen ? 'check-circle' : 'times-circle'); ?>"></i>
<?php echo e($isOpen ? 'Terbuka' : 'Tertutup'); ?>
</div>
</div>
<div class="info-box" style="border-color:#81C6E8;">
<div class="ib-label">Dibuka Oleh</div>
<div class="ib-val"><?php echo e($config['opened_by'] ?? '-'); ?></div>
</div>
<div class="info-box" style="border-color:#FFD56B;">
<div class="ib-label">Semester</div>
<div class="ib-val">
<?php if($config['id_semester']): ?>
<?php echo e(\App\Models\Semester::where('id_semester', $config['id_semester'])->value('nama_semester') ?? '-'); ?>
<?php else: ?>
Semua Semester
<?php endif; ?>
</div>
</div>
<div class="info-box" style="border-color:#B39DDB;">
<div class="ib-label">Auto-Close</div>
<div class="ib-val">
<?php if($config['auto_close_at']): ?>
<?php echo e(\Carbon\Carbon::parse($config['auto_close_at'])->isoFormat('D MMM HH:mm')); ?>
<?php else: ?>
Manual
<?php endif; ?>
</div>
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:18px;">
<div class="form-card">
<h4 style="color:#2e7d32;"><i class="fas fa-lock-open"></i> Buka Akses Input Capaian</h4>
<form method="POST" action="<?php echo e(route('admin.capaian.akses-santri.buka')); ?>">
<?php echo csrf_field(); ?>
<div class="form-group" style="margin-bottom:12px;">
<label style="font-size:.83rem;font-weight:600;color:#555;display:block;margin-bottom:4px;">
<i class="fas fa-calendar-alt"></i> Semester yang Dibuka
</label>
<select name="id_semester" class="form-control" style="font-size:.84rem;">
<option value="">-- Semua Semester --</option>
<?php $__currentLoopData = $semesters; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $sem): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($sem->id_semester); ?>"
<?php echo e(($semesterAktif && $sem->id_semester == $semesterAktif->id_semester) ? 'selected' : ''); ?>>
<?php echo e($sem->nama_semester); ?><?php echo e($sem->is_active ? ' ★ (Aktif)' : ''); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
<small style="color:#999;font-size:.74rem;">Kosongkan = santri bisa input di semua semester</small>
</div>
<div class="form-group" style="margin-bottom:12px;">
<label style="font-size:.83rem;font-weight:600;color:#555;display:block;margin-bottom:4px;">
<i class="fas fa-clock"></i> Durasi Otomatis Tutup (opsional)
</label>
<div style="display:flex;align-items:center;gap:8px;">
<input type="number" name="durasi_jam" min="1" max="720"
class="form-control" style="width:110px;font-size:.84rem;"
placeholder="cth: 24">
<span style="font-size:.84rem;color:#555;">jam</span>
</div>
<small style="color:#999;font-size:.74rem;">Kosongkan = harus ditutup manual oleh admin</small>
</div>
<div class="form-group" style="margin-bottom:16px;">
<label style="font-size:.83rem;font-weight:600;color:#555;display:block;margin-bottom:4px;">
<i class="fas fa-sticky-note"></i> Catatan untuk Santri (opsional)
</label>
<input type="text" name="catatan" class="form-control" style="font-size:.84rem;"
placeholder="cth: Deadline input: Jumat 17.00 WIB" maxlength="255">
</div>
<button type="submit" class="toggle-btn open-btn">
<i class="fas fa-lock-open"></i> Buka Akses Sekarang
</button>
</form>
</div>
<div class="form-card">
<h4 style="color:#c62828;"><i class="fas fa-lock"></i> Tutup Akses Input Capaian</h4>
<?php if($isOpen): ?>
<div style="background:#fbe9e7;border-radius:9px;padding:14px;margin-bottom:16px;">
<p style="margin:0;font-size:.84rem;color:#555;">
<i class="fas fa-info-circle" style="color:#ef5350;"></i>
Saat ini akses <strong>sedang dibuka</strong>. Klik tombol di bawah untuk menutup akses input capaian santri segera.
</p>
<?php if($sisaWaktu): ?>
<p style="margin:8px 0 0;font-size:.8rem;color:#777;">
<i class="fas fa-hourglass-half"></i> Sisa waktu auto-close: <strong><?php echo e($sisaWaktu); ?></strong>
</p>
<?php endif; ?>
</div>
<form method="POST" action="<?php echo e(route('admin.capaian.akses-santri.tutup')); ?>"
onsubmit="return confirm('Yakin ingin menutup akses input capaian santri?')">
<?php echo csrf_field(); ?>
<button type="submit" class="toggle-btn close-btn">
<i class="fas fa-lock"></i> Tutup Akses Sekarang
</button>
</form>
<?php else: ?>
<div style="background:#f5f5f5;border-radius:9px;padding:14px;text-align:center;color:#aaa;">
<i class="fas fa-lock" style="font-size:2rem;display:block;margin-bottom:8px;"></i>
Akses saat ini sudah tertutup.<br>
<span style="font-size:.8rem;">Gunakan form di sebelah kiri untuk membuka akses.</span>
</div>
<?php endif; ?>
</div>
</div>
<div class="form-card" style="background:#f0f9ff;border:1px solid #b3e0ff;">
<h4 style="color:#0277bd;"><i class="fas fa-info-circle"></i> Alur Penggunaan</h4>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px;font-size:.83rem;color:#555;">
<div style="display:flex;gap:10px;">
<div style="background:#1565c0;color:#fff;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:800;flex-shrink:0;">1</div>
<div><strong>Admin membuka akses</strong><br>Pilih semester & opsional durasi waktu lalu klik "Buka Akses".</div>
</div>
<div style="display:flex;gap:10px;">
<div style="background:#2e7d32;color:#fff;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:800;flex-shrink:0;">2</div>
<div><strong>Santri input capaian</strong><br>Santri login ke web-nya dan bisa input capaian sesuai materi kelasnya.</div>
</div>
<div style="display:flex;gap:10px;">
<div style="background:#e65100;color:#fff;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:800;flex-shrink:0;">3</div>
<div><strong>Data langsung masuk</strong><br>Data capaian santri langsung terlihat di dashboard admin & riwayat santri.</div>
</div>
<div style="display:flex;gap:10px;">
<div style="background:#6a1b9a;color:#fff;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:800;flex-shrink:0;">4</div>
<div><strong>Admin menutup akses</strong><br>Setelah selesai, tutup akses manual atau biarkan auto-close berjalan.</div>
</div>
</div>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/capaian/akses-santri.blade.php ENDPATH**/ ?>

View File

@ -1,274 +0,0 @@

<?php $__env->startSection('title', 'Riwayat Pelanggaran'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-history"></i> Riwayat Pelanggaran Santri</h2>
</div>
<!-- Alert Messages -->
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger">
<i class="fas fa-exclamation-circle"></i> <?php echo e(session('error')); ?>
</div>
<?php endif; ?>
<!-- Statistik Cards -->
<div class="row-cards">
<div class="card card-primary">
<h3><i class="fas fa-list"></i> Total Pelanggaran</h3>
<div class="card-value"><?php echo e($totalPelanggaran); ?></div>
<p style="margin: 0; color: var(--text-light);">Semua Riwayat</p>
<i class="fas fa-clipboard-list card-icon"></i>
</div>
<div class="card card-warning">
<h3><i class="fas fa-calendar-alt"></i> Bulan Ini</h3>
<div class="card-value"><?php echo e($pelanggaranBulanIni); ?></div>
<p style="margin: 0; color: var(--text-light);"><?php echo e(\Carbon\Carbon::now()->format('F Y')); ?></p>
<i class="fas fa-calendar-check card-icon"></i>
</div>
<div class="card card-danger">
<h3><i class="fas fa-star"></i> Total Poin</h3>
<div class="card-value"><?php echo e($totalPoin); ?></div>
<p style="margin: 0; color: var(--text-light);">Akumulasi Poin</p>
<i class="fas fa-fire card-icon"></i>
</div>
</div>
<!-- Filter & Search -->
<div class="content-box" style="margin-bottom: 22px;">
<h3 style="margin-bottom: 14px; color: var(--primary-color);">
<i class="fas fa-filter"></i> Filter & Pencarian
</h3>
<form method="GET" action="<?php echo e(route('admin.riwayat-pelanggaran.index')); ?>">
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 11px; margin-bottom: 14px;">
<!-- Search -->
<div class="form-group" style="margin-bottom: 0;">
<label for="search">
<i class="fas fa-search form-icon"></i>
Pencarian
</label>
<input type="text"
name="search"
id="search"
class="form-control"
value="<?php echo e(request('search')); ?>"
placeholder="Cari santri, kategori...">
</div>
<!-- Filter Santri -->
<div class="form-group" style="margin-bottom: 0;">
<label for="id_santri">
<i class="fas fa-user form-icon"></i>
Santri
</label>
<select name="id_santri" id="id_santri" class="form-control">
<option value="">-- Semua Santri --</option>
<?php $__currentLoopData = $santriList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $santri): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($santri->id_santri); ?>"
<?php echo e(request('id_santri') == $santri->id_santri ? 'selected' : ''); ?>>
<?php echo e($santri->nama_lengkap); ?> (<?php echo e($santri->id_santri); ?>)
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<!-- Filter Kategori -->
<div class="form-group" style="margin-bottom: 0;">
<label for="id_kategori">
<i class="fas fa-tags form-icon"></i>
Kategori
</label>
<select name="id_kategori" id="id_kategori" class="form-control">
<option value="">-- Semua Kategori --</option>
<?php $__currentLoopData = $kategoriList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kategori): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($kategori->id_kategori); ?>"
<?php echo e(request('id_kategori') == $kategori->id_kategori ? 'selected' : ''); ?>>
<?php echo e($kategori->nama_pelanggaran); ?> (<?php echo e($kategori->poin); ?> poin)
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<!-- Tanggal Mulai -->
<div class="form-group" style="margin-bottom: 0;">
<label for="tanggal_mulai">
<i class="fas fa-calendar form-icon"></i>
Tanggal Mulai
</label>
<input type="date"
name="tanggal_mulai"
id="tanggal_mulai"
class="form-control"
value="<?php echo e(request('tanggal_mulai')); ?>">
</div>
<!-- Tanggal Selesai -->
<div class="form-group" style="margin-bottom: 0;">
<label for="tanggal_selesai">
<i class="fas fa-calendar-check form-icon"></i>
Tanggal Selesai
</label>
<input type="date"
name="tanggal_selesai"
id="tanggal_selesai"
class="form-control"
value="<?php echo e(request('tanggal_selesai')); ?>">
</div>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-primary">
<i class="fas fa-search"></i> Cari
</button>
<a href="<?php echo e(route('admin.riwayat-pelanggaran.index')); ?>" class="btn btn-secondary">
<i class="fas fa-redo"></i> Reset
</a>
<label style="display: inline-flex; align-items: center; margin-left: 20px;">
<input type="checkbox" name="bulan_ini" value="1" <?php echo e(request('bulan_ini') ? 'checked' : ''); ?> style="margin-right: 8px;">
<span>Bulan Ini Saja</span>
</label>
</div>
</form>
</div>
<!-- Tabel Data -->
<div class="content-box">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px;">
<h3 style="margin: 0; color: var(--primary-color);">
<i class="fas fa-table"></i> Daftar Riwayat Pelanggaran
</h3>
<a href="<?php echo e(route('admin.riwayat-pelanggaran.create')); ?>" class="btn btn-primary">
<i class="fas fa-plus"></i> Tambah Riwayat
</a>
</div>
<?php if($data->isNotEmpty()): ?>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">No</th>
<th style="width: 110px;">ID Riwayat</th>
<th style="width: 120px;">Tanggal</th>
<th>Santri</th>
<th>Kategori Pelanggaran</th>
<th style="width: 100px; text-align: center;">Poin</th>
<th style="width: 200px; text-align: center;">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $data; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($data->firstItem() + $index); ?></td>
<td>
<span class="badge badge-secondary"><?php echo e($item->id_riwayat); ?></span>
</td>
<td>
<i class="fas fa-calendar" style="color: var(--text-light);"></i>
<?php echo e(\Carbon\Carbon::parse($item->tanggal)->format('d M Y')); ?>
</td>
<td>
<?php if($item->santri): ?>
<strong><?php echo e($item->santri->nama_lengkap); ?></strong><br>
<small style="color: var(--text-light);">
<i class="fas fa-id-card"></i> <?php echo e($item->id_santri); ?>
</small>
<?php else: ?>
<span style="color: var(--danger-color);">Santri tidak ditemukan</span>
<?php endif; ?>
</td>
<td>
<?php if($item->kategori): ?>
<strong><?php echo e($item->kategori->nama_pelanggaran); ?></strong><br>
<small style="color: var(--text-light);">
<i class="fas fa-tag"></i> <?php echo e($item->id_kategori); ?>
</small>
<?php else: ?>
<span style="color: var(--danger-color);">Kategori tidak ditemukan</span>
<?php endif; ?>
</td>
<td style="text-align: center;">
<span class="badge badge-danger" style="font-size: 1em; padding: 8px 12px;">
<i class="fas fa-fire"></i> <?php echo e($item->poin); ?>
</span>
</td>
<td style="text-align: center;">
<div style="display: flex; justify-content: center; gap: 8px;">
<a href="<?php echo e(route('admin.riwayat-pelanggaran.show', $item)); ?>"
class="btn btn-sm btn-success"
title="Detail">
<i class="fas fa-eye"></i>
</a>
<a href="<?php echo e(route('admin.riwayat-pelanggaran.edit', $item)); ?>"
class="btn btn-sm btn-warning"
title="Edit">
<i class="fas fa-edit"></i>
</a>
<form action="<?php echo e(route('admin.riwayat-pelanggaran.destroy', $item)); ?>"
method="POST"
style="display: inline;"
onsubmit="return confirm('Yakin ingin menghapus riwayat ini?');">
<?php echo csrf_field(); ?>
<?php echo method_field('DELETE'); ?>
<button type="submit"
class="btn btn-sm btn-danger"
title="Hapus">
<i class="fas fa-trash"></i>
</button>
</form>
</div>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<!-- Pagination -->
<div style="margin-top: 14px;">
<?php echo e($data->links()); ?>
</div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-folder-open"></i>
<h3>Belum ada riwayat pelanggaran</h3>
<p>Silakan tambah riwayat pelanggaran baru menggunakan tombol di atas.</p>
<a href="<?php echo e(route('admin.riwayat-pelanggaran.create')); ?>" class="btn btn-primary">
<i class="fas fa-plus"></i> Tambah Riwayat
</a>
</div>
<?php endif; ?>
</div>
<script>
// Auto hide alerts after 5 seconds
setTimeout(function() {
const alerts = document.querySelectorAll('.alert');
alerts.forEach(alert => {
alert.style.transition = 'opacity 0.5s';
alert.style.opacity = '0';
setTimeout(() => alert.remove(), 500);
});
}, 5000);
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/riwayat_pelanggaran/index.blade.php ENDPATH**/ ?>

View File

@ -1,196 +0,0 @@

<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-calendar-alt"></i> Jadwal Kegiatan Santri</h2>
<div style="display: flex; gap: 8px;">
<a href="<?php echo e(route('admin.kegiatan.create')); ?>" class="btn btn-success btn-sm">
<i class="fas fa-plus"></i> Tambah Kegiatan
</a>
<a href="<?php echo e(route('admin.kategori-kegiatan.index')); ?>" class="btn btn-info btn-sm">
<i class="fas fa-tags"></i> Kategori
</a>
</div>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div>
<?php endif; ?>
<div class="content-box" style="margin-bottom: 14px;">
<form method="GET" class="filter-form-inline">
<div class="filter-form-inline" style="gap: 8px;">
<label style="font-weight: 600; white-space: nowrap; margin: 0;">
<i class="fas fa-calendar-day"></i> Hari:
</label>
<select name="hari" class="form-control" onchange="this.form.submit()" style="max-width: 160px;">
<option value="">Semua Hari</option>
<?php $__currentLoopData = $hariList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $hari): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($hari); ?>" <?php echo e(request('hari') == $hari ? 'selected' : ''); ?>><?php echo e($hari); ?></option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div class="filter-form-inline" style="gap: 8px;">
<label style="font-weight: 600; white-space: nowrap; margin: 0;">
<i class="fas fa-tags"></i> Kategori:
</label>
<select name="kategori_id" class="form-control" onchange="this.form.submit()" style="max-width: 180px;">
<option value="">Semua Kategori</option>
<?php $__currentLoopData = $kategoris; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kat): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($kat->kategori_id); ?>" <?php echo e(request('kategori_id') == $kat->kategori_id ? 'selected' : ''); ?>>
<?php echo e($kat->nama_kategori); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div class="filter-form-inline" style="gap: 8px;">
<label style="font-weight: 600; white-space: nowrap; margin: 0;">
<i class="fas fa-school"></i> Kelas:
</label>
<select name="kelas_id" class="form-control" onchange="this.form.submit()" style="max-width: 200px;">
<option value="">Semua Kelas</option>
<option value="umum" <?php echo e(request('kelas_id') === 'umum' ? 'selected' : ''); ?>>Kegiatan Umum</option>
<?php $__currentLoopData = $kelasList->groupBy('kelompok.nama_kelompok'); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelompokNama => $kelasGroup): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<optgroup label="<?php echo e($kelompokNama); ?>">
<?php $__currentLoopData = $kelasGroup; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelas): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($kelas->id); ?>" <?php echo e(request('kelas_id') == $kelas->id ? 'selected' : ''); ?>>
<?php echo e($kelas->nama_kelas); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</optgroup>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div class="filter-form-inline" style="gap: 8px;">
<label style="font-weight: 600; white-space: nowrap; margin: 0;">
<i class="fas fa-search"></i>
</label>
<input type="text" name="search" class="form-control" placeholder="Cari kegiatan..."
value="<?php echo e(request('search')); ?>" style="max-width: 180px;">
</div>
<button type="submit" class="btn btn-primary btn-sm">
<i class="fas fa-filter"></i> Filter
</button>
<?php if(request()->hasAny(['hari', 'kategori_id', 'kelas_id', 'search'])): ?>
<a href="<?php echo e(route('admin.kegiatan.jadwal')); ?>" class="btn btn-secondary btn-sm">
<i class="fas fa-times"></i> Reset
</a>
<?php endif; ?>
</form>
</div>
<?php
$kegiatanPerHari = $kegiatans->groupBy('hari');
$urutanHari = ['Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu', 'Ahad'];
?>
<?php if($kegiatans->count() > 0): ?>
<?php $__currentLoopData = $urutanHari; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $hari): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$kegiatanHari = $kegiatanPerHari->get($hari, collect());
?>
<?php if($kegiatanHari->count() > 0): ?>
<div class="content-box" style="margin-bottom: 16px;">
<h4 style="margin: 0 0 14px; color: var(--primary-color); display: flex; align-items: center; gap: 8px;">
<i class="fas fa-calendar-day"></i> <?php echo e($hari); ?>
<span class="badge badge-primary"><?php echo e($kegiatanHari->count()); ?> kegiatan</span>
</h4>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">No</th>
<th>Nama Kegiatan</th>
<th style="width: 130px;">Waktu</th>
<th style="width: 140px;">Kategori</th>
<th>Kelas</th>
<th style="width: 100px;">Materi</th>
<th style="width: 120px; text-align: center;">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $kegiatanHari->sortBy('waktu_mulai'); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $kegiatan): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($index + 1); ?></td>
<td><strong><?php echo e($kegiatan->nama_kegiatan); ?></strong></td>
<td>
<i class="fas fa-clock" style="color: var(--primary-color);"></i>
<?php echo e(date('H:i', strtotime($kegiatan->waktu_mulai))); ?> &ndash; <?php echo e(date('H:i', strtotime($kegiatan->waktu_selesai))); ?>
</td>
<td>
<span class="badge badge-info"><?php echo e($kegiatan->kategori->nama_kategori); ?></span>
</td>
<td>
<?php if($kegiatan->kelasKegiatan->isEmpty()): ?>
<span class="badge badge-secondary"><i class="fas fa-users"></i> Umum</span>
<?php else: ?>
<?php $__currentLoopData = $kegiatan->kelasKegiatan->take(3); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kls): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<span class="badge badge-primary"><?php echo e($kls->nama_kelas); ?></span>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<?php if($kegiatan->kelasKegiatan->count() > 3): ?>
<span class="badge badge-light">+<?php echo e($kegiatan->kelasKegiatan->count() - 3); ?></span>
<?php endif; ?>
<?php endif; ?>
</td>
<td><?php echo e(Str::limit($kegiatan->materi, 30) ?: '-'); ?></td>
<td class="text-center">
<div style="display: flex; gap: 4px; justify-content: center;">
<a href="<?php echo e(route('admin.kegiatan.edit', $kegiatan)); ?>" class="btn btn-sm btn-warning" title="Edit">
<i class="fas fa-edit"></i>
</a>
<a href="<?php echo e(route('admin.kegiatan.show', $kegiatan)); ?>" class="btn btn-sm btn-info" title="Detail">
<i class="fas fa-eye"></i>
</a>
<form action="<?php echo e(route('admin.kegiatan.destroy', $kegiatan)); ?>" method="POST"
onsubmit="return confirm('Yakin hapus kegiatan ini?');" style="display: inline;">
<?php echo csrf_field(); ?>
<?php echo method_field('DELETE'); ?>
<button type="submit" class="btn btn-sm btn-danger" title="Hapus">
<i class="fas fa-trash"></i>
</button>
</form>
</div>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<div style="margin-top: 14px;">
<?php echo e($kegiatans->links()); ?>
</div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-calendar-times"></i>
<h3>Belum Ada Jadwal Kegiatan</h3>
<p>Silakan tambahkan kegiatan terlebih dahulu.</p>
<a href="<?php echo e(route('admin.kegiatan.create')); ?>" class="btn btn-success">
<i class="fas fa-plus"></i> Tambah Kegiatan
</a>
</div>
<?php endif; ?>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kegiatan/data/index.blade.php ENDPATH**/ ?>

View File

@ -0,0 +1,417 @@

<?php $__env->startSection('content'); ?>
<style>
/* =====================================================
DETAIL SANTRI Riwayat Kehadiran
===================================================== */
.ds-header { display:flex; justify-content:space-between; align-items:flex-start; gap:12px;
margin-bottom:18px; flex-wrap:wrap; }
.ds-header h2 { margin:0; font-size:1.3rem; color:var(--primary-dark); display:flex; align-items:center; gap:9px; }
/* Info santri */
.ds-info-box { background:#fff; border-radius:12px; padding:16px 20px; margin-bottom:14px;
box-shadow:0 2px 10px rgba(0,0,0,0.06); display:flex; justify-content:space-between;
align-items:center; flex-wrap:wrap; gap:12px; }
.ds-info-box h3 { margin:0 0 5px; color:var(--primary-color); font-size:1.1rem; }
.ds-info-meta { font-size:0.83rem; color:#64748b; display:flex; flex-wrap:wrap; gap:10px; }
.ds-info-meta span { display:inline-flex; align-items:center; gap:4px; }
/* KPI cards */
.ds-kpi-grid { display:grid; grid-template-columns:repeat(5,1fr); gap:10px; margin-bottom:14px; }
@media(max-width:900px) { .ds-kpi-grid { grid-template-columns:repeat(3,1fr); } }
@media(max-width:540px) { .ds-kpi-grid { grid-template-columns:repeat(2,1fr); } }
.ds-kpi { background:#fff; border-radius:10px; padding:12px 14px;
box-shadow:0 2px 8px rgba(0,0,0,0.06); display:flex; align-items:center; gap:10px; }
.ds-kpi .ico { width:36px; height:36px; border-radius:9px; display:flex; align-items:center;
justify-content:center; font-size:1.1rem; flex-shrink:0; }
.ds-kpi.hadir .ico { background:#d1fae5; color:#065f46; }
.ds-kpi.terlambat .ico { background:#fff3e0; color:#e65100; }
.ds-kpi.izin .ico { background:#fef3c7; color:#92400e; }
.ds-kpi.sakit .ico { background:#dbeafe; color:#1e40af; }
.ds-kpi.alpa .ico { background:#fee2e2; color:#991b1b; }
.ds-kpi .cnt { font-size:1.4rem; font-weight:800; color:var(--primary-dark); line-height:1; }
.ds-kpi .lbl { font-size:0.74rem; color:#94a3b8; margin-top:2px; }
/* Terlambat note */
.ds-terlambat-note { font-size:0.76rem; color:#6b7280; background:#fff7ed; border:1px solid #fed7aa;
border-radius:8px; padding:6px 12px; margin-bottom:14px;
display:flex; align-items:center; gap:6px; }
.ds-terlambat-note i { color:#ea580c; }
/* Tren chart box */
.ds-chart-box { background:#fff; border-radius:12px; padding:16px 18px; margin-bottom:14px;
box-shadow:0 2px 10px rgba(0,0,0,0.06); }
.ds-chart-box h4 { margin:0 0 14px; color:var(--primary-color); font-size:0.95rem;
display:flex; align-items:center; gap:7px; }
/* Riwayat lengkap dengan tabs */
.ds-riwayat-box { background:#fff; border-radius:12px; overflow:hidden; margin-bottom:14px;
box-shadow:0 2px 10px rgba(0,0,0,0.06); }
.ds-riwayat-head { padding:14px 18px 0; border-bottom:2px solid #f1f5f9; }
.ds-riwayat-head h4 { margin:0 0 12px; color:var(--primary-dark); font-size:0.95rem;
display:flex; align-items:center; gap:7px; }
/* Tabs */
.ds-tabs { display:flex; gap:0; overflow-x:auto; -webkit-overflow-scrolling:touch; }
.ds-tabs::-webkit-scrollbar { height:0; }
.ds-tab { padding:9px 16px; font-size:0.82rem; font-weight:600; border:none; background:transparent;
cursor:pointer; white-space:nowrap; color:#64748b; border-bottom:3px solid transparent;
transition:all 0.15s; text-decoration:none; display:inline-flex; align-items:center; gap:6px; }
.ds-tab:hover { color:var(--primary-color); background:#f0fdf4; }
.ds-tab.active { color:var(--primary-color); border-bottom-color:var(--primary-color); background:#f0fdf4; }
.ds-tab .tab-cnt { background:#e8f7f2; color:var(--primary-color); padding:1px 7px; border-radius:10px;
font-size:0.72rem; font-weight:700; }
.ds-tab.active .tab-cnt { background:var(--primary-color); color:#fff; }
.ds-tab .tab-hadir { background:#d1fae5; color:#065f46; padding:1px 7px; border-radius:10px;
font-size:0.7rem; font-weight:700; }
/* Per-page toolbar */
.ds-toolbar { display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap;
gap:8px; padding:10px 18px; background:#fafafa; border-bottom:1px solid #f1f5f9; }
.ds-toolbar-left { font-size:0.8rem; color:#64748b; }
.ds-toolbar-right { display:flex; align-items:center; gap:8px; font-size:0.8rem; color:#64748b; }
.ds-perpage-group { display:flex; gap:4px; }
.ds-pp-btn { padding:4px 10px; border:1.5px solid #e2e8f0; border-radius:6px; background:#fff;
font-size:0.78rem; font-weight:600; color:#64748b; cursor:pointer;
text-decoration:none; transition:all 0.15s; }
.ds-pp-btn:hover { border-color:var(--primary-color); color:var(--primary-color); }
.ds-pp-btn.active { background:var(--primary-color); color:#fff; border-color:var(--primary-color); }
/* Table */
.ds-table-wrap { overflow-x:auto; }
.ds-table { width:100%; border-collapse:collapse; min-width:540px; }
.ds-table thead th { padding:9px 14px; text-align:left; font-size:0.78rem; font-weight:600;
color:#64748b; background:#f8fafc; border-bottom:1px solid #e2e8f0; }
.ds-table tbody td { padding:9px 14px; font-size:0.83rem; border-bottom:1px solid #f8fafc; vertical-align:middle; }
.ds-table tbody tr:last-child td { border-bottom:none; }
.ds-table tbody tr:hover { background:#f8fafc; }
/* Status badges (inline fallback jika status_badge tidak ada) */
.s-hadir { background:#d1fae5; color:#065f46; padding:3px 9px; border-radius:9px; font-size:0.74rem; font-weight:700; }
.s-terlambat { background:#fff3e0; color:#e65100; padding:3px 9px; border-radius:9px; font-size:0.74rem; font-weight:700; }
.s-izin { background:#fef3c7; color:#92400e; padding:3px 9px; border-radius:9px; font-size:0.74rem; font-weight:700; }
.s-sakit { background:#dbeafe; color:#1e40af; padding:3px 9px; border-radius:9px; font-size:0.74rem; font-weight:700; }
.s-alpa { background:#fee2e2; color:#991b1b; padding:3px 9px; border-radius:9px; font-size:0.74rem; font-weight:700; }
.s-pulang { background:#f3e8ff; color:#6b21a8; padding:3px 9px; border-radius:9px; font-size:0.74rem; font-weight:700; }
/* Button back */
.btn-ds-back { padding:8px 16px; background:#6b7280; color:#fff; border-radius:8px; font-size:0.82rem;
font-weight:600; text-decoration:none; display:inline-flex; align-items:center; gap:6px;
transition:background 0.18s; }
.btn-ds-back:hover { background:#4b5563; color:#fff; }
/* Empty */
.ds-empty { text-align:center; padding:30px; color:#94a3b8; }
.ds-empty i { font-size:2.5rem; display:block; margin-bottom:10px; opacity:0.35; }
</style>
<?php
$totalHadirEfektif = $stats['_hadir_efektif'] ?? 0;
$totalHadir = $stats['Hadir'] ?? 0;
$totalTerlambat = $stats['Terlambat'] ?? 0;
$totalIzin = $stats['Izin'] ?? 0;
$totalSakit = $stats['Sakit'] ?? 0;
$totalAlpa = $stats['Alpa'] ?? 0;
$persenHadir = ($totalHadirEfektif + $totalIzin + $totalSakit + $totalAlpa) > 0
? round($totalHadirEfektif / ($totalHadirEfektif + $totalIzin + $totalSakit + $totalAlpa) * 100, 1)
: 0;
?>
<div class="ds-header">
<h2><i class="fas fa-user-clock" style="color:var(--primary-color);"></i>
Riwayat Kehadiran: <?php echo e($santri->nama_lengkap); ?>
</h2>
<a href="<?php echo e(route('admin.riwayat-kegiatan.index')); ?>" class="btn-ds-back">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
<div class="ds-info-box">
<div>
<h3><?php echo e($santri->nama_lengkap); ?></h3>
<div class="ds-info-meta">
<span><i class="fas fa-id-card"></i> <strong><?php echo e($santri->id_santri); ?></strong></span>
<span><i class="fas fa-school"></i> <?php echo e($santri->kelas); ?></span>
<span><i class="fas fa-circle" style="font-size:0.5rem; color:#22c55e;"></i>
<span class="badge badge-success" style="font-size:0.76rem;"><?php echo e($santri->status); ?></span>
</span>
<?php if($persenHadir > 0): ?>
<span style="font-weight:700; color:<?php echo e($persenHadir >= 85 ? '#059669' : ($persenHadir >= 70 ? '#d97706' : '#dc2626')); ?>;">
<i class="fas fa-chart-pie"></i> Kehadiran <?php echo e($persenHadir); ?>%
</span>
<?php endif; ?>
</div>
</div>
</div>
<?php if($totalTerlambat > 0): ?>
<div class="ds-terlambat-note">
<i class="fas fa-info-circle"></i>
<strong><?php echo e($totalTerlambat); ?>x Terlambat</strong> dihitung sebagai <strong>Hadir</strong> (bukan Alpa).
Total hadir efektif: <strong><?php echo e($totalHadirEfektif); ?></strong> kali
(<?php echo e($totalHadir); ?> hadir tepat waktu + <?php echo e($totalTerlambat); ?> terlambat).
</div>
<?php endif; ?>
<div class="ds-kpi-grid">
<div class="ds-kpi hadir">
<div class="ico"><i class="fas fa-check-circle"></i></div>
<div>
<div class="cnt"><?php echo e($totalHadirEfektif); ?></div>
<div class="lbl">Hadir Efektif</div>
<?php if($totalTerlambat > 0): ?>
<div style="font-size:0.68rem; color:#94a3b8;"><?php echo e($totalHadir); ?>+<?php echo e($totalTerlambat); ?>tl</div>
<?php endif; ?>
</div>
</div>
<div class="ds-kpi terlambat">
<div class="ico"><i class="fas fa-clock"></i></div>
<div><div class="cnt"><?php echo e($totalTerlambat); ?></div><div class="lbl">Terlambat</div></div>
</div>
<div class="ds-kpi izin">
<div class="ico"><i class="fas fa-envelope"></i></div>
<div><div class="cnt"><?php echo e($totalIzin); ?></div><div class="lbl">Izin</div></div>
</div>
<div class="ds-kpi sakit">
<div class="ico"><i class="fas fa-heartbeat"></i></div>
<div><div class="cnt"><?php echo e($totalSakit); ?></div><div class="lbl">Sakit</div></div>
</div>
<div class="ds-kpi alpa">
<div class="ico"><i class="fas fa-times-circle"></i></div>
<div><div class="cnt"><?php echo e($totalAlpa); ?></div><div class="lbl">Alpa</div></div>
</div>
</div>
<?php if($riwayat30Hari->count() > 0): ?>
<div class="ds-chart-box">
<h4><i class="fas fa-chart-line"></i> Tren Kehadiran 30 Hari Terakhir
<span style="font-size:0.76rem; font-weight:400; color:#94a3b8; margin-left:4px;">
(Hadir + Terlambat)
</span>
</h4>
<canvas id="chartTren" style="max-height:220px;"></canvas>
</div>
<?php endif; ?>
<div class="ds-riwayat-box">
<div class="ds-riwayat-head">
<h4><i class="fas fa-list-alt" style="color:var(--primary-color);"></i> Riwayat Lengkap per Kategori</h4>
<?php if($kategoriList->count() > 0): ?>
<div class="ds-tabs" role="tablist">
<?php $__currentLoopData = $kategoriList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kat): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$tabParams = array_merge(request()->query(), [
'tab_kat' => $kat->kategori_id,
'per_page' => $perPage,
'page' => 1,
]);
$isActive = ($activeKategori == $kat->kategori_id);
$pctKat = $kat->total > 0 ? round($kat->hadir_efektif / $kat->total * 100) : 0;
?>
<a href="<?php echo e(route('admin.riwayat-kegiatan.detail-santri', $santri->id_santri)); ?>?<?php echo e(http_build_query($tabParams)); ?>"
class="ds-tab <?php echo e($isActive ? 'active' : ''); ?>"
role="tab">
<i class="fas fa-tag" style="font-size:0.72rem;"></i>
<?php echo e($kat->nama_kategori); ?>
<span class="tab-cnt"><?php echo e($kat->total); ?></span>
<?php if($kat->hadir_efektif > 0): ?>
<span class="tab-hadir" title="Hadir efektif"><?php echo e($pctKat); ?>%</span>
<?php endif; ?>
</a>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
<?php endif; ?>
</div>
<?php if($riwayats->count() > 0): ?>
<div class="ds-toolbar">
<div class="ds-toolbar-left">
<?php if(!$showAll): ?>
Menampilkan
<strong><?php echo e($riwayats->firstItem()); ?><?php echo e($riwayats->lastItem()); ?></strong>
dari <strong><?php echo e($riwayats->total()); ?></strong> riwayat
<?php else: ?>
Menampilkan <strong>semua <?php echo e($riwayats->total()); ?></strong> riwayat
<?php endif; ?>
<?php $activeKat = $kategoriList->firstWhere('kategori_id', $activeKategori); ?>
<?php if($activeKat): ?>
&mdash; <span style="color:var(--primary-color); font-weight:600;"><?php echo e($activeKat->nama_kategori); ?></span>
<?php endif; ?>
</div>
<div class="ds-toolbar-right">
Tampilkan:
<div class="ds-perpage-group">
<?php $__currentLoopData = [15, 50, 100]; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $pp): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php $ppParams = array_merge(request()->query(), ['per_page' => $pp, 'page' => 1]); ?>
<a href="<?php echo e(route('admin.riwayat-kegiatan.detail-santri', $santri->id_santri)); ?>?<?php echo e(http_build_query($ppParams)); ?>"
class="ds-pp-btn <?php echo e((!$showAll && $perPage == $pp) ? 'active' : ''); ?>">
<?php echo e($pp); ?>
</a>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<?php $allParams = array_merge(request()->query(), ['per_page' => 'all', 'page' => 1]); ?>
<a href="<?php echo e(route('admin.riwayat-kegiatan.detail-santri', $santri->id_santri)); ?>?<?php echo e(http_build_query($allParams)); ?>"
class="ds-pp-btn <?php echo e($showAll ? 'active' : ''); ?>"
title="Tampilkan semua data sekaligus (bisa lambat jika data banyak)">
Semua
</a>
</div>
</div>
</div>
<div class="ds-table-wrap">
<table class="ds-table">
<thead>
<tr>
<th style="width:50px;">No</th>
<th style="width:110px;">Tanggal</th>
<th>Nama Kegiatan</th>
<th style="width:115px; text-align:center;">Status</th>
<th style="width:90px; text-align:center;">Waktu</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $riwayats; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $idx => $riwayat): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td style="color:#94a3b8; font-size:0.78rem;"><?php echo e($riwayats->firstItem() + $idx); ?></td>
<td style="font-size:0.81rem; color:#64748b;">
<?php echo e($riwayat->tanggal->format('d/m/Y')); ?>
<div style="font-size:0.71rem; color:#94a3b8;">
<?php echo e($riwayat->tanggal->locale('id')->isoFormat('ddd')); ?>
</div>
</td>
<td>
<strong style="font-size:0.85rem;"><?php echo e($riwayat->kegiatan->nama_kegiatan); ?></strong>
<div style="font-size:0.74rem; color:#94a3b8; margin-top:1px;">
<i class="fas fa-clock"></i>
<?php echo e(date('H:i', strtotime($riwayat->kegiatan->waktu_mulai))); ?><?php echo e(date('H:i', strtotime($riwayat->kegiatan->waktu_selesai))); ?>
</div>
</td>
<td style="text-align:center;">
<?php if(method_exists($riwayat, 'getStatusBadgeAttribute') || isset($riwayat->status_badge)): ?>
<?php echo $riwayat->status_badge; ?>
<?php else: ?>
<?php $st = $riwayat->status; ?>
<span class="s-<?php echo e(strtolower($st)); ?>"><?php echo e($st); ?></span>
<?php endif; ?>
</td>
<td style="text-align:center; font-size:0.81rem; color:#64748b;">
<?php echo e($riwayat->waktu_absen ? date('H:i', strtotime($riwayat->waktu_absen)) : ''); ?>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<?php if(!$showAll && $riwayats->lastPage() > 1): ?>
<div style="padding:12px 16px;">
<?php echo e($riwayats->links()); ?>
</div>
<?php elseif($showAll): ?>
<div style="padding:10px 16px; font-size:0.78rem; color:#94a3b8; background:#fafafa; border-top:1px solid #f1f5f9;">
<i class="fas fa-info-circle"></i> Semua <strong><?php echo e($riwayats->total()); ?></strong> data ditampilkan.
&nbsp;
<?php $backPaged = array_merge(request()->query(), ['per_page' => 15, 'page' => 1]); ?>
<a href="<?php echo e(route('admin.riwayat-kegiatan.detail-santri', $santri->id_santri)); ?>?<?php echo e(http_build_query($backPaged)); ?>"
style="color:var(--primary-color);">Kembali ke paginasi</a>
</div>
<?php endif; ?>
<?php elseif($kategoriList->count() > 0): ?>
<div class="ds-empty">
<i class="fas fa-inbox"></i>
<p>Belum ada riwayat untuk kategori ini.</p>
</div>
<?php else: ?>
<div class="ds-empty">
<i class="fas fa-inbox"></i>
<p>Santri ini belum memiliki riwayat kehadiran apapun.</p>
</div>
<?php endif; ?>
</div>
<?php if($riwayat30Hari->count() > 0): ?>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
(function() {
var ctx = document.getElementById('chartTren');
if (!ctx) return;
var labels = <?php echo json_encode($riwayat30Hari->pluck('tanggal')->map(fn($d) => date('d/m', strtotime($d)))); ?>;
var hadir = <?php echo json_encode($riwayat30Hari->pluck('hadir')); ?>;
var total = <?php echo json_encode($riwayat30Hari->pluck('total')); ?>;
new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [
{
label: 'Hadir (termasuk terlambat)',
data: hadir,
borderColor: '#6FBA9D',
backgroundColor: 'rgba(111,186,157,0.12)',
tension: 0.4,
fill: true,
pointRadius: 4,
pointBackgroundColor: '#6FBA9D',
},
{
label: 'Total Kegiatan',
data: total,
borderColor: '#cbd5e1',
backgroundColor: 'transparent',
borderDash: [5, 5],
tension: 0.4,
fill: false,
pointRadius: 0,
}
]
},
options: {
responsive: true,
maintainAspectRatio: true,
interaction: { mode: 'index', intersect: false },
plugins: {
legend: { position: 'bottom', labels: { boxWidth: 12, font: { size: 11 } } }
},
scales: {
y: { beginAtZero: true, ticks: { stepSize: 1 }, grid: { color: '#f1f5f9' } },
x: { grid: { display: false }, ticks: { font: { size: 10 } } }
}
}
});
})();
</script>
<?php endif; ?>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kegiatan/riwayat/detail-santri.blade.php ENDPATH**/ ?>

View File

@ -1,116 +0,0 @@

<?php $__env->startSection('title', 'Klasifikasi Pelanggaran'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-tags"></i> Klasifikasi Pelanggaran</h2>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger">
<i class="fas fa-exclamation-circle"></i> <?php echo e(session('error')); ?>
</div>
<?php endif; ?>
<div class="content-box">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px;">
<h3 style="margin: 0; color: var(--primary-color);">
<i class="fas fa-list"></i> Daftar Klasifikasi
</h3>
<div style="display: flex; gap: 10px;">
<a href="<?php echo e(route('admin.kategori-pelanggaran.index')); ?>" class="btn btn-info">
<i class="fas fa-list-ul"></i> Kategori Pelanggaran
</a>
<a href="<?php echo e(route('admin.klasifikasi-pelanggaran.create')); ?>" class="btn btn-primary">
<i class="fas fa-plus-circle"></i> Tambah Klasifikasi
</a>
</div>
</div>
<?php if($data->isNotEmpty()): ?>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">No</th>
<th style="width: 100px;">ID</th>
<th>Nama Klasifikasi</th>
<th style="width: 120px; text-align: center;">Jumlah Pelanggaran</th>
<th style="width: 80px; text-align: center;">Urutan</th>
<th style="width: 100px; text-align: center;">Status</th>
<th style="width: 200px; text-align: center;">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $data; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($index + 1); ?></td>
<td><span class="badge badge-primary"><?php echo e($item->id_klasifikasi); ?></span></td>
<td>
<strong><?php echo e($item->nama_klasifikasi); ?></strong>
<?php if($item->deskripsi): ?>
<br><small style="color: var(--text-light);"><?php echo e(Str::limit($item->deskripsi, 80)); ?></small>
<?php endif; ?>
</td>
<td style="text-align: center;">
<span class="badge badge-info"><?php echo e($item->pelanggarans_count); ?></span>
</td>
<td style="text-align: center;"><?php echo e($item->urutan); ?></td>
<td style="text-align: center;">
<?php if($item->is_active): ?>
<span class="badge badge-success">Aktif</span>
<?php else: ?>
<span class="badge badge-secondary">Nonaktif</span>
<?php endif; ?>
</td>
<td style="text-align: center;">
<div style="display: flex; justify-content: center; gap: 8px;">
<a href="<?php echo e(route('admin.klasifikasi-pelanggaran.show', $item)); ?>"
class="btn btn-sm btn-success"
title="Detail">
<i class="fas fa-eye"></i>
</a>
<a href="<?php echo e(route('admin.klasifikasi-pelanggaran.edit', $item)); ?>"
class="btn btn-sm btn-warning"
title="Edit">
<i class="fas fa-edit"></i>
</a>
<form action="<?php echo e(route('admin.klasifikasi-pelanggaran.destroy', $item)); ?>"
method="POST"
style="display: inline;"
onsubmit="return confirm('Yakin ingin menghapus?');">
<?php echo csrf_field(); ?>
<?php echo method_field('DELETE'); ?>
<button type="submit" class="btn btn-sm btn-danger" title="Hapus">
<i class="fas fa-trash"></i>
</button>
</form>
</div>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-folder-open"></i>
<h3>Belum ada klasifikasi</h3>
<p>Mulai dengan menambahkan klasifikasi pelanggaran.</p>
<a href="<?php echo e(route('admin.klasifikasi-pelanggaran.create')); ?>" class="btn btn-primary">
<i class="fas fa-plus"></i> Tambah Klasifikasi
</a>
</div>
<?php endif; ?>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/klasifikasi_pelanggaran/index.blade.php ENDPATH**/ ?>

View File

@ -1,600 +0,0 @@

<?php $__env->startSection('content'); ?>
<?php
// -- Day-tab calculations --
$isoDay = $selectedDate->dayOfWeekIso;
$monOfWeek = $selectedDate->copy()->subDays($isoDay - 1);
$hariMapTab = [
'Senin' => 'Senin','Selasa' => 'Selasa','Rabu' => 'Rabu',
'Kamis' => 'Kamis','Jumat' => 'Jumat','Sabtu' => 'Sabtu','Minggu' => 'Ahad'
];
$activeTab = $hariMapTab[$selectedDate->locale('id')->isoFormat('dddd')] ?? 'Senin';
$todayHari = $hariMapTab[now()->locale('id')->isoFormat('dddd')] ?? 'Senin';
$tabHari = [
['nama' => 'Senin', 'offset' => 0],
['nama' => 'Selasa', 'offset' => 1],
['nama' => 'Rabu', 'offset' => 2],
['nama' => 'Kamis', 'offset' => 3],
['nama' => 'Jumat', 'offset' => 4],
['nama' => 'Sabtu', 'offset' => 5],
['nama' => 'Minggu', 'offset' => 6],
];
$kelompokGroups = $kelasList->groupBy('kelompok.nama_kelompok');
?>
<div class="page-header" style="display:flex; align-items:center; justify-content:space-between;">
<h2><i class="fas fa-tachometer-alt"></i> Dashboard Absensi</h2>
<div style="display:flex; gap:8px;">
<a href="<?php echo e(route('admin.mesin.mapping-santri.index')); ?>"
class="btn btn-sm btn-secondary">
<i class="fas fa-link"></i> Mapping Fingerprint
</a>
<a href="<?php echo e(route('admin.mesin.import.index')); ?>"
class="btn btn-sm btn-success"
style="background:#0F7B6C; border-color:#0F7B6C;">
<i class="fas fa-file-import"></i> Import
</a>
</div>
</div>
<p style="color: var(--text-light); margin-top: 5px; margin-bottom: 14px;">
<?php echo e($selectedDate->locale('id')->isoFormat('dddd, D MMMM Y')); ?>
</p>
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div>
<?php endif; ?>
<div class="kpi-grid-kegiatan">
<div class="kpi-kegiatan bg-primary">
<i class="fas fa-calendar-day kpi-icon"></i>
<div class="kpi-value"><?php echo e($totalKegiatanHariIni); ?></div>
<div class="kpi-label">Total Kegiatan</div>
<div class="kpi-sub">
<i class="fas fa-<?php echo e($comparisonTotal >= 0 ? 'arrow-up' : 'arrow-down'); ?>"></i>
<?php echo e(abs($comparisonTotal)); ?> vs minggu lalu
</div>
</div>
<div class="kpi-kegiatan bg-success">
<i class="fas fa-check-circle kpi-icon"></i>
<div class="kpi-value"><?php echo e($kegiatanSelesai); ?></div>
<div class="kpi-label">Kegiatan Selesai</div>
<div class="kpi-sub">dari <?php echo e($totalKegiatanHariIni); ?> kegiatan</div>
</div>
<div class="kpi-kegiatan bg-warning">
<i class="fas fa-chart-line kpi-icon"></i>
<div class="kpi-value"><?php echo e($avgKehadiran); ?>%</div>
<div class="kpi-label">Rata-rata Kehadiran</div>
<div class="kpi-sub">
<i class="fas fa-<?php echo e($comparisonAvg >= 0 ? 'arrow-up' : 'arrow-down'); ?>"></i>
<?php echo e(abs($comparisonAvg)); ?>% vs minggu lalu
</div>
</div>
<div class="kpi-kegiatan bg-info">
<i class="fas fa-clock kpi-icon"></i>
<div class="kpi-value"><?php echo e($kegiatanBerlangsung); ?></div>
<div class="kpi-label">Sedang Berlangsung</div>
<?php if($kegiatanBerlangsung > 0): ?>
<div class="kpi-sub"><i class="fas fa-circle" style="color: #90ee90;"></i> Live Now</div>
<?php else: ?>
<div class="kpi-sub">Tidak ada kegiatan</div>
<?php endif; ?>
</div>
</div>
<div class="content-box">
<div class="day-tabs">
<?php $__currentLoopData = $tabHari; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $tab): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$tabDate = $monOfWeek->copy()->addDays($tab['offset']);
$tabDateStr = $tabDate->format('Y-m-d');
$isActive = ($activeTab === $tab['nama']);
$isToday = ($todayHari === $tab['nama'] && now()->format('W') === $selectedDate->format('W'));
$params = array_merge(
request()->only(['kelas', 'kategori_id']),
['tanggal' => $tabDateStr]
);
?>
<a href="<?php echo e(route('admin.kegiatan.index', $params)); ?>"
class="day-tab <?php echo e($isActive ? 'active' : ''); ?> <?php echo e($isToday ? 'today-tab' : ''); ?>">
<span class="day-name"><?php echo e($tab['nama']); ?></span>
<span class="day-date"><?php echo e($tabDate->format('d/m')); ?></span>
</a>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
<form method="GET" action="<?php echo e(route('admin.kegiatan.index')); ?>" id="filterForm" class="filter-form-inline" style="margin-top: 10px;">
<input type="hidden" name="kelas" id="kelasInput" value="<?php echo e($selectedKelasId); ?>">
<div class="filter-form-inline" style="gap: 8px;">
<label style="font-weight: 600; white-space: nowrap; margin: 0;">
<i class="fas fa-calendar"></i> Tanggal:
</label>
<input type="date" name="tanggal" class="form-control"
value="<?php echo e($selectedDate->format('Y-m-d')); ?>"
onchange="this.form.submit()" style="max-width: 170px;">
</div>
<div class="filter-form-inline" style="gap: 8px;">
<label style="font-weight: 600; white-space: nowrap; margin: 0;">
<i class="fas fa-tags"></i> Kategori:
</label>
<select name="kategori_id" class="form-control" onchange="this.form.submit()" style="max-width: 180px;">
<option value="">Semua Kategori</option>
<?php $__currentLoopData = $kategoris; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kat): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($kat->kategori_id); ?>" <?php echo e(request('kategori_id') == $kat->kategori_id ? 'selected' : ''); ?>>
<?php echo e($kat->nama_kategori); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div class="filter-form-inline" style="gap: 8px;">
<label style="font-weight: 600; white-space: nowrap; margin: 0;">
<i class="fas fa-school"></i> Kelas:
</label>
<select name="kelas" class="form-control" onchange="this.form.submit()" style="max-width: 200px;">
<option value="">Semua Kelas</option>
<option value="umum" <?php echo e($selectedKelasId === 'umum' ? 'selected' : ''); ?>>Kegiatan Umum</option>
<?php $__currentLoopData = $kelompokGroups; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelompokNama => $kelasGroup): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<optgroup label="<?php echo e($kelompokNama); ?>">
<?php $__currentLoopData = $kelasGroup; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelas): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($kelas->id); ?>" <?php echo e($selectedKelasId == $kelas->id ? 'selected' : ''); ?>>
<?php echo e($kelas->nama_kelas); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</optgroup>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<button type="button" class="btn btn-sm btn-primary" onclick="setToday()">
<i class="fas fa-calendar-day"></i> Hari Ini
</button>
<button type="button" class="btn btn-sm btn-secondary" onclick="prevDay()">
<i class="fas fa-chevron-left"></i>
</button>
<button type="button" class="btn btn-sm btn-secondary" onclick="nextDay()">
<i class="fas fa-chevron-right"></i>
</button>
</form>
</div>
<?php if(count($insights) > 0): ?>
<div class="content-box" style="margin-top: 14px;">
<h4 style="margin: 0 0 12px; color: var(--primary-color);">
<i class="fas fa-lightbulb"></i> Insight Hari Ini
</h4>
<?php $__currentLoopData = $insights; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $insight): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div class="insight-item <?php echo e($insight['type']); ?>">
<div class="insight-content">
<div class="insight-message">
<i class="fas fa-<?php echo e($insight['icon']); ?>"></i> <?php echo e($insight['message']); ?>
</div>
<div class="insight-detail"><?php echo e($insight['detail']); ?></div>
</div>
<?php if($insight['action_url']): ?>
<a href="<?php echo e($insight['action_url']); ?>" class="btn btn-sm btn-<?php echo e($insight['type']); ?>">
<?php echo e($insight['action_text']); ?>
</a>
<?php endif; ?>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
<?php endif; ?>
<div class="layout-kegiatan" style="margin-top: 14px;">
<div>
<?php if($kegiatanHariIni->count() > 0): ?>
<div class="kegiatan-list">
<?php $__currentLoopData = $kegiatanHariIni; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kegiatan): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div class="kegiatan-card">
<div class="kegiatan-card-header">
<div class="kegiatan-info">
<h3 class="kegiatan-title">
<i class="fas fa-calendar" style="color: var(--primary-color);"></i>
<?php echo e($kegiatan->nama_kegiatan); ?>
</h3>
<div class="kegiatan-meta">
<span>
<i class="fas fa-clock"></i>
<?php echo e(date('H:i', strtotime($kegiatan->waktu_mulai))); ?> &ndash;
<?php echo e(date('H:i', strtotime($kegiatan->waktu_selesai))); ?>
</span>
<span class="badge badge-info">
<i class="fas fa-tag"></i>
<?php echo e($kegiatan->kategori->nama_kategori); ?>
</span>
<?php if($kegiatan->materi): ?>
<span>
<i class="fas fa-book"></i>
<?php echo e(Str::limit($kegiatan->materi, 40)); ?>
</span>
<?php endif; ?>
<span>
<i class="fas fa-layer-group"></i>
<?php if($kegiatan->kelasKegiatan->isEmpty()): ?>
<span class="badge badge-secondary">Kegiatan Umum</span>
<?php else: ?>
<?php echo e($kegiatan->kelasKegiatan->pluck('nama_kelas')->implode(', ')); ?>
<?php endif; ?>
</span>
</div>
</div>
<span class="status-badge status-<?php echo e($kegiatan->status_kegiatan); ?>">
<?php if($kegiatan->status_kegiatan == 'belum'): ?>
<i class="fas fa-hourglass-start"></i> Belum Dimulai
<?php elseif($kegiatan->status_kegiatan == 'berlangsung'): ?>
<i class="fas fa-play-circle"></i> Berlangsung
<?php else: ?>
<i class="fas fa-check-circle"></i> Selesai
<?php endif; ?>
</span>
</div>
<?php
$persen = $kegiatan->persen_kehadiran;
$pClass = $persen >= 85 ? 'p-success' : ($persen >= 70 ? 'p-warning' : ($persen >= 50 ? 'p-orange' : 'p-danger'));
$denominator = $kegiatan->total_absensi > 0 ? $kegiatan->total_absensi : $totalSantriAktif;
?>
<div class="kegiatan-progress">
<div class="kegiatan-progress-header">
<span style="font-weight: 500;">
<i class="fas fa-users"></i> Kehadiran
</span>
<span style="font-weight: 700;">
<?php echo e($kegiatan->total_hadir); ?>/<?php echo e($denominator); ?>
(<?php echo e($persen); ?>%)
</span>
</div>
<div class="kegiatan-progress-bar">
<div class="kegiatan-progress-fill <?php echo e($pClass); ?>"
data-width="<?php echo e($persen); ?>">
<?php echo e($persen); ?>%
</div>
</div>
</div>
<div class="kegiatan-actions">
<a href="<?php echo e(route('admin.absensi-kegiatan.input', $kegiatan->kegiatan_id)); ?>?tanggal=<?php echo e($selectedDate->format('Y-m-d')); ?>"
class="btn btn-sm btn-primary">
<i class="fas fa-clipboard-check"></i> Input Absensi
</a>
<button type="button" class="btn btn-sm btn-info"
data-id="<?php echo e($kegiatan->kegiatan_id); ?>"
data-tanggal="<?php echo e($selectedDate->format('Y-m-d')); ?>"
onclick="showDetailModal(this.getAttribute('data-id'), this.getAttribute('data-tanggal'))">
<i class="fas fa-eye"></i> Lihat Detail
</button>
<a href="<?php echo e(route('admin.absensi-kegiatan.rekap', $kegiatan->kegiatan_id)); ?>?tanggal=<?php echo e($selectedDate->format('Y-m-d')); ?>"
class="btn btn-sm btn-secondary">
<i class="fas fa-chart-bar"></i> Rekap
</a>
</div>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-calendar-times"></i>
<h3>Tidak Ada Kegiatan Dijadwalkan</h3>
<p>Tidak ada kegiatan untuk
<?php echo e($selectedKelasId ? 'kelas ini' : 'hari ini'); ?>
pada <?php echo e($selectedDate->locale('id')->isoFormat('dddd, D MMMM Y')); ?>
</p>
<a href="<?php echo e(route('admin.kegiatan.create')); ?>" class="btn btn-success">
<i class="fas fa-plus"></i> Buat Kegiatan Baru
</a>
</div>
<?php endif; ?>
</div>
<div>
<div class="heatmap-calendar">
<div class="heatmap-header">
<i class="fas fa-calendar-alt"></i>
<span>Kalender Kehadiran</span>
</div>
<div class="filter-form-inline" style="margin-bottom: 12px;">
<button type="button" class="btn btn-sm btn-secondary" style="padding: 4px 8px;"
onclick="changeHeatmapMonth(-1)">
<i class="fas fa-chevron-left"></i>
</button>
<select id="heatmapMonth" onchange="updateHeatmap()" class="form-control" style="flex: 1;">
<?php for($m = 1; $m <= 12; $m++): ?>
<option value="<?php echo e($m); ?>" <?php echo e($m == now()->month ? 'selected' : ''); ?>>
<?php echo e(\Carbon\Carbon::create(null, $m, 1)->locale('id')->isoFormat('MMMM')); ?>
</option>
<?php endfor; ?>
</select>
<select id="heatmapYear" onchange="updateHeatmap()" class="form-control" style="width: 80px;">
<?php for($y = now()->year - 2; $y <= now()->year + 1; $y++): ?>
<option value="<?php echo e($y); ?>" <?php echo e($y == now()->year ? 'selected' : ''); ?>><?php echo e($y); ?></option>
<?php endfor; ?>
</select>
<button type="button" class="btn btn-sm btn-secondary" style="padding: 4px 8px;"
onclick="changeHeatmapMonth(1)">
<i class="fas fa-chevron-right"></i>
</button>
</div>
<div style="text-align: center; font-weight: 600; color: var(--primary-color); margin-bottom: 10px;"
id="heatmapMonthName">
<?php echo e(now()->locale('id')->isoFormat('MMMM Y')); ?>
</div>
<div class="heatmap-days">
<div class="heatmap-day-label">Sen</div>
<div class="heatmap-day-label">Sel</div>
<div class="heatmap-day-label">Rab</div>
<div class="heatmap-day-label">Kam</div>
<div class="heatmap-day-label">Jum</div>
<div class="heatmap-day-label">Sab</div>
<div class="heatmap-day-label">Ahd</div>
</div>
<div class="heatmap-grid" id="heatmapGrid">
<?php $__currentLoopData = $heatmapData; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $day): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div class="heatmap-cell heatmap-level-<?php echo e($day['level']); ?> <?php echo e($day['is_today'] ? 'today' : ''); ?>"
data-date="<?php echo e($day['date']); ?>"
data-percentage="<?php echo e($day['percentage']); ?>"
title="<?php echo e(\Carbon\Carbon::parse($day['date'])->locale('id')->isoFormat('dddd, D MMM Y')); ?>: <?php echo e($day['percentage']); ?>%">
<?php echo e(\Carbon\Carbon::parse($day['date'])->format('j')); ?>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
<div class="heatmap-legend">
<div class="heatmap-legend-title">Legend:</div>
<div class="heatmap-legend-items">
<div class="heatmap-legend-item">
<div class="heatmap-legend-box heatmap-level-4"></div>
<span>&gt;90%</span>
</div>
<div class="heatmap-legend-item">
<div class="heatmap-legend-box heatmap-level-3"></div>
<span>80-90%</span>
</div>
<div class="heatmap-legend-item">
<div class="heatmap-legend-box heatmap-level-2"></div>
<span>70-80%</span>
</div>
<div class="heatmap-legend-item">
<div class="heatmap-legend-box heatmap-level-1"></div>
<span>&lt;70%</span>
</div>
<div class="heatmap-legend-item">
<div class="heatmap-legend-box heatmap-level-0"></div>
<span>No data</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="detailModal" class="modal-kegiatan">
<div class="modal-kegiatan-panel">
<div class="modal-kegiatan-head">
<h3><i class="fas fa-info-circle"></i> Detail Absensi Kegiatan</h3>
<button class="modal-kegiatan-close" onclick="closeModal()">&times;</button>
</div>
<div class="modal-kegiatan-body" id="modalBody">
<div style="text-align: center; padding: 22px;">
<i class="fas fa-spinner fa-spin" style="font-size: 2rem; color: var(--primary-color);"></i>
<p style="margin-top: 10px;">Memuat data...</p>
</div>
</div>
</div>
</div>
<script>
// -- Date Navigation --
function setToday() {
var dateInput = document.querySelector('input[name="tanggal"]');
var now = new Date();
var y = now.getFullYear();
var m = ('0' + (now.getMonth() + 1)).slice(-2);
var d = ('0' + now.getDate()).slice(-2);
dateInput.value = y + '-' + m + '-' + d;
document.getElementById('filterForm').submit();
}
function prevDay() {
var currentDate = new Date('<?php echo e($selectedDate->format("Y-m-d")); ?>');
currentDate.setDate(currentDate.getDate() - 1);
document.querySelector('input[name="tanggal"]').value = currentDate.toISOString().split('T')[0];
document.getElementById('filterForm').submit();
}
function nextDay() {
var currentDate = new Date('<?php echo e($selectedDate->format("Y-m-d")); ?>');
currentDate.setDate(currentDate.getDate() + 1);
document.querySelector('input[name="tanggal"]').value = currentDate.toISOString().split('T')[0];
document.getElementById('filterForm').submit();
}
function goToDate(date) {
document.querySelector('input[name="tanggal"]').value = date;
document.getElementById('filterForm').submit();
}
// -- Show Detail Modal (AJAX) --
function showDetailModal(kegiatanId, tanggal) {
var modal = document.getElementById('detailModal');
var modalBody = document.getElementById('modalBody');
modal.classList.add('active');
var baseUrl = '<?php echo e(route("admin.kegiatan.detail-modal", ":id")); ?>';
var url = baseUrl.replace(':id', kegiatanId) + '?tanggal=' + tanggal;
fetch(url)
.then(function(response) { return response.text(); })
.then(function(html) { modalBody.innerHTML = html; })
.catch(function() {
modalBody.innerHTML =
'<div style="text-align:center;padding:22px;">' +
'<i class="fas fa-exclamation-circle" style="font-size:2.2rem;color:var(--danger-color);"></i>' +
'<h4 style="margin:20px 0 10px;color:var(--danger-color);">Gagal Memuat Data</h4>' +
'<p style="color:var(--text-light);">Terjadi kesalahan saat memuat detail absensi.</p>' +
'<button class="btn btn-primary" onclick="closeModal()">Tutup</button>' +
'</div>';
});
}
function closeModal() {
document.getElementById('detailModal').classList.remove('active');
}
// -- Close modal on backdrop / Escape --
window.onclick = function(event) {
var modal = document.getElementById('detailModal');
if (event.target === modal) { closeModal(); }
};
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape') { closeModal(); }
});
// -- Progress bar width animation --
document.querySelectorAll('.kegiatan-progress-fill[data-width]').forEach(function(el) {
el.style.width = el.getAttribute('data-width') + '%';
});
// -- Heatmap: delegated click for cells --
document.getElementById('heatmapGrid').addEventListener('click', function(e) {
var cell = e.target.closest('.heatmap-cell');
if (cell && cell.dataset.date) {
goToDate(cell.dataset.date);
}
});
// -- Heatmap: month navigation --
function changeHeatmapMonth(delta) {
var monthSelect = document.getElementById('heatmapMonth');
var yearSelect = document.getElementById('heatmapYear');
var month = parseInt(monthSelect.value) + delta;
var year = parseInt(yearSelect.value);
if (month > 12) { month = 1; year++; }
else if (month < 1) { month = 12; year--; }
monthSelect.value = month;
yearSelect.value = year;
updateHeatmap();
}
// -- Heatmap: AJAX reload --
function updateHeatmap() {
var month = document.getElementById('heatmapMonth').value;
var year = document.getElementById('heatmapYear').value;
var kelasId = document.getElementById('kelasInput').value;
var monthNames = [
'Januari','Februari','Maret','April','Mei','Juni',
'Juli','Agustus','September','Oktober','November','Desember'
];
document.getElementById('heatmapMonthName').textContent = monthNames[month - 1] + ' ' + year;
var url = '<?php echo e(route("admin.kegiatan.index")); ?>' +
'?heatmap=1&month=' + month + '&year=' + year + '&kelas=' + kelasId;
fetch(url)
.then(function(response) { return response.json(); })
.then(function(data) {
var grid = document.getElementById('heatmapGrid');
grid.innerHTML = '';
// -- Empty cells for first week alignment --
var firstDay = new Date(year, month - 1, 1).getDay();
var startDay = firstDay === 0 ? 6 : firstDay - 1;
var i;
for (i = 0; i < startDay; i++) {
var empty = document.createElement('div');
empty.className = 'heatmap-cell';
empty.style.visibility = 'hidden';
grid.appendChild(empty);
}
// -- Render calendar cells --
data.heatmapData.forEach(function(day) {
var cell = document.createElement('div');
var date = new Date(day.date);
var today = new Date();
var isToday = date.toDateString() === today.toDateString();
cell.className = 'heatmap-cell heatmap-level-' + day.level + (isToday ? ' today' : '');
cell.setAttribute('data-date', day.date);
cell.setAttribute('data-percentage', day.percentage);
cell.setAttribute('title', day.title);
cell.onclick = function() { goToDate(day.date); };
cell.textContent = date.getDate();
grid.appendChild(cell);
});
})
.catch(function(err) {
console.error('Error loading heatmap:', err);
});
}
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kegiatan/data/dashboard.blade.php ENDPATH**/ ?>

View File

@ -1,144 +0,0 @@

<?php $__env->startSection('title', 'Pembinaan & Sanksi'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-book-open"></i> Tata Tertib</h2>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger">
<i class="fas fa-exclamation-circle"></i> <?php echo e(session('error')); ?>
</div>
<?php endif; ?>
<div class="content-box">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px;">
<h3 style="margin: 0; color: var(--primary-color);">
<i class="fas fa-list"></i> Daftar Konten
</h3>
<div style="display: flex; gap: 10px;">
<a href="<?php echo e(route('admin.pembinaan-sanksi.create')); ?>" class="btn btn-primary">
<i class="fas fa-plus-circle"></i> Tambah Konten
</a>
</div>
</div>
<?php if($data->isNotEmpty()): ?>
<div class="alert alert-info" style="margin-bottom: 14px;">
<i class="fas fa-info-circle"></i>
<strong>Info:</strong> Konten akan ditampilkan sesuai urutan. Drag atau ubah nomor urutan untuk mengatur tampilan.
</div>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">No</th>
<th style="width: 100px;">ID</th>
<th>Judul</th>
<th style="width: 300px;">Preview Konten</th>
<th style="width: 80px; text-align: center;">Urutan</th>
<th style="width: 100px; text-align: center;">Status</th>
<th style="width: 200px; text-align: center;">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $data; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($index + 1); ?></td>
<td><span class="badge badge-primary"><?php echo e($item->id_pembinaan); ?></span></td>
<td>
<strong style="font-size: 1.05em;"><?php echo e($item->judul); ?></strong><br>
<small style="color: var(--text-light);">
<i class="fas fa-clock"></i> Diubah: <?php echo e($item->updated_at->diffForHumans()); ?>
</small>
</td>
<td>
<div style="max-height: 60px; overflow: hidden; color: var(--text-light); font-size: 0.9em; line-height: 1.5;">
<?php echo e(Str::limit(strip_tags($item->konten), 100)); ?>
</div>
</td>
<td style="text-align: center;">
<span class="badge badge-info" style="font-size: 1em;"><?php echo e($item->urutan); ?></span>
</td>
<td style="text-align: center;">
<?php if($item->is_active): ?>
<span class="badge badge-success">
<i class="fas fa-check-circle"></i> Aktif
</span>
<?php else: ?>
<span class="badge badge-secondary">
<i class="fas fa-times-circle"></i> Nonaktif
</span>
<?php endif; ?>
</td>
<td style="text-align: center;">
<div style="display: flex; justify-content: center; gap: 8px;">
<a href="<?php echo e(route('admin.pembinaan-sanksi.show', $item)); ?>"
class="btn btn-sm btn-success"
title="Detail & Preview">
<i class="fas fa-eye"></i>
</a>
<a href="<?php echo e(route('admin.pembinaan-sanksi.edit', $item)); ?>"
class="btn btn-sm btn-warning"
title="Edit Konten">
<i class="fas fa-edit"></i>
</a>
<form action="<?php echo e(route('admin.pembinaan-sanksi.destroy', $item)); ?>"
method="POST"
style="display: inline;"
onsubmit="return confirm('Yakin ingin menghapus konten \'<?php echo e($item->judul); ?>\'?\n\nKonten yang dihapus tidak dapat dikembalikan.');">
<?php echo csrf_field(); ?>
<?php echo method_field('DELETE'); ?>
<button type="submit" class="btn btn-sm btn-danger" title="Hapus">
<i class="fas fa-trash"></i>
</button>
</form>
</div>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-folder-open"></i>
<h3>Belum ada konten</h3>
<p>Mulai dengan menambahkan konten baru menggunakan Rich Text Editor.</p>
<p style="color: var(--text-light); margin-bottom: 14px;">
Anda dapat membuat peraturan, tata tertib, pembinaan, atau sanksi dengan format yang rapi.
</p>
<a href="<?php echo e(route('admin.pembinaan-sanksi.create')); ?>" class="btn btn-primary">
<i class="fas fa-plus"></i> Tambah Konten Pertama
</a>
</div>
<?php endif; ?>
</div>
<script>
setTimeout(function() {
const alerts = document.querySelectorAll('.alert');
alerts.forEach(alert => {
alert.style.transition = 'opacity 0.5s';
alert.style.opacity = '0';
setTimeout(() => alert.remove(), 500);
});
}, 5000);
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/pembinaan_sanksi/index.blade.php ENDPATH**/ ?>

View File

@ -0,0 +1,107 @@
<?php
$totalSantri = $kegiatan->total_absensi;
$hdr = $kegiatan->hadir ?? 0;
$tlb = $kegiatan->terlambat ?? 0;
$izn = $kegiatan->izin ?? 0;
$skt = $kegiatan->sakit ?? 0;
$alp = $kegiatan->alpa ?? 0;
$plg = $kegiatan->pulang ?? 0;
$tot = $kegiatan->total_absensi ?? 0;
$pct = fn($n) => $tot > 0 ? round($n / $tot * 100) : 0;
$isUmum = $kegiatan->kelasKegiatan->isEmpty();
?>
<div class="rw-card">
<div class="rw-card-head">
<div style="flex: 1; min-width: 0;">
<div class="rw-card-title">
<i class="fas fa-clipboard-list"></i>
<?php echo e($kegiatan->nama_kegiatan); ?>
</div>
<div class="rw-card-meta">
<span><i class="fas fa-clock"></i>
<?php echo e(date('H:i', strtotime($kegiatan->waktu_mulai))); ?><?php echo e(date('H:i', strtotime($kegiatan->waktu_selesai))); ?>
</span>
<span class="rw-kat-tag"><i class="fas fa-tag"></i> <?php echo e($kegiatan->kategori->nama_kategori); ?></span>
<?php if($isUmum): ?>
<span class="rw-umum-tag"><i class="fas fa-globe"></i> Umum</span>
<?php else: ?>
<?php $__currentLoopData = $kegiatan->kelasKegiatan->take(3); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kls): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<span class="rw-kelas-tag"><?php echo e($kls->nama_kelas); ?></span>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<?php if($kegiatan->kelasKegiatan->count() > 3): ?>
<span class="rw-umum-tag">+<?php echo e($kegiatan->kelasKegiatan->count() - 3); ?> kelas</span>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
<?php if(isset($passParams) && $passParams['mode'] === 'hari_ini'): ?>
<div style="font-size: 0.75rem; color: var(--primary-color); font-weight: 700;
background: #f0fdf4; padding: 4px 10px; border-radius: 20px; border: 1px solid #bbf7d0;
white-space: nowrap; flex-shrink: 0;">
<i class="fas fa-calendar-day"></i> <?php echo e($kegiatan->hari); ?>
</div>
<?php endif; ?>
</div>
<div class="rw-card-body">
<?php if($tot > 0): ?>
<div class="rw-stats-row">
<?php if($hdr > 0): ?> <span class="rw-chip hadir"><i class="fas fa-check"></i> <?php echo e($hdr); ?> Hadir</span> <?php endif; ?>
<?php if($tlb > 0): ?> <span class="rw-chip terlambat"><i class="fas fa-clock"></i> <?php echo e($tlb); ?> Terlambat</span> <?php endif; ?>
<?php if($izn > 0): ?> <span class="rw-chip izin"><i class="fas fa-envelope"></i> <?php echo e($izn); ?> Izin</span> <?php endif; ?>
<?php if($skt > 0): ?> <span class="rw-chip sakit"><i class="fas fa-heartbeat"></i> <?php echo e($skt); ?> Sakit</span> <?php endif; ?>
<?php if($alp > 0): ?> <span class="rw-chip alpa"><i class="fas fa-times"></i> <?php echo e($alp); ?> Alpa</span> <?php endif; ?>
<?php if($plg > 0): ?> <span class="rw-chip pulang"><i class="fas fa-home"></i> <?php echo e($plg); ?> Pulang</span> <?php endif; ?>
</div>
<div class="rw-progress-wrap">
<?php if($hdr > 0): ?> <div class="rw-prog-hadir" style="width:<?php echo e($pct($hdr)); ?>%;" title="Hadir <?php echo e($hdr); ?>"></div> <?php endif; ?>
<?php if($tlb > 0): ?> <div class="rw-prog-terlambat" style="width:<?php echo e($pct($tlb)); ?>%;" title="Terlambat <?php echo e($tlb); ?>"></div> <?php endif; ?>
<?php if($izn > 0): ?> <div class="rw-prog-izin" style="width:<?php echo e($pct($izn)); ?>%;" title="Izin <?php echo e($izn); ?>"></div> <?php endif; ?>
<?php if($skt > 0): ?> <div class="rw-prog-sakit" style="width:<?php echo e($pct($skt)); ?>%;" title="Sakit <?php echo e($skt); ?>"></div> <?php endif; ?>
<?php if($alp > 0): ?> <div class="rw-prog-alpa" style="width:<?php echo e($pct($alp)); ?>%;" title="Alpa <?php echo e($alp); ?>"></div> <?php endif; ?>
<?php if($plg > 0): ?> <div class="rw-prog-pulang" style="width:<?php echo e($pct($plg)); ?>%;" title="Pulang <?php echo e($plg); ?>"></div> <?php endif; ?>
</div>
<div style="font-size: 0.74rem; color: #94a3b8;">
Total tercatat: <strong style="color:#374151;"><?php echo e($tot); ?></strong> santri
</div>
<?php else: ?>
<span class="rw-chip none"><i class="fas fa-inbox"></i> Belum ada data absensi</span>
<?php endif; ?>
</div>
<div class="rw-card-foot">
<div class="rw-total-txt">
<?php if($tot > 0): ?>
<i class="fas fa-users" style="color:var(--primary-color);"></i>
<strong><?php echo e($hdr + $tlb); ?></strong> hadir dari <strong><?php echo e($tot); ?></strong> tercatat
<?php else: ?>
<span style="color:#cbd5e1;"><i class="fas fa-info-circle"></i> Belum ada absensi diinput</span>
<?php endif; ?>
</div>
<?php
$detailParams = array_merge($passParams ?? [], ['kategori_id' => request('kategori_id')]);
?>
<a href="<?php echo e(route('admin.riwayat-kegiatan.show', $kegiatan->id)); ?>?<?php echo e(http_build_query($detailParams)); ?>"
class="btn-rw-detail">
<i class="fas fa-users"></i> Lihat Santri
</a>
</div>
</div><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kegiatan/riwayat/_card.blade.php ENDPATH**/ ?>

View File

@ -1,330 +0,0 @@

<?php $__env->startSection('title', 'Riwayat Pelanggaran'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-exclamation-circle"></i> Riwayat Pelanggaran Saya</h2>
</div>
<?php
$tingkatPoin = '';
$warnaPoin = '';
if ($totalPoin >= 50) {
$tingkatPoin = 'Berat';
$warnaPoin = 'var(--danger-color)';
} elseif ($totalPoin >= 20) {
$tingkatPoin = 'Sedang';
$warnaPoin = '#e67e22';
} elseif ($totalPoin > 0) {
$tingkatPoin = 'Ringan';
$warnaPoin = 'var(--warning-color)';
}
?>
<?php if($totalPoin >= 50): ?>
<div style="background: linear-gradient(135deg, #dc3545 0%, #a71d2a 100%); color: white; padding: 16px 20px; border-radius: var(--border-radius); margin-bottom: 18px; display: flex; align-items: center; gap: 14px; box-shadow: 0 4px 15px rgba(220,53,69,0.3);">
<i class="fas fa-exclamation-triangle" style="font-size: 2em; opacity: 0.9;"></i>
<div>
<strong style="font-size: 1.05em;">⚠️ Perhatian! Akumulasi poin Anda sudah tinggi (<?php echo e($totalPoin); ?> poin)</strong><br>
<span style="opacity: 0.9; font-size: 0.9em;">Harap segera hubungi pengurus pondok untuk konsultasi dan penyelesaian kafaroh yang ada.</span>
</div>
</div>
<?php elseif($totalPoin >= 20): ?>
<div style="background: linear-gradient(135deg, #e67e22 0%, #ca6f1e 100%); color: white; padding: 16px 20px; border-radius: var(--border-radius); margin-bottom: 18px; display: flex; align-items: center; gap: 14px; box-shadow: 0 4px 15px rgba(230,126,34,0.3);">
<i class="fas fa-exclamation-circle" style="font-size: 2em; opacity: 0.9;"></i>
<div>
<strong style="font-size: 1.05em;">Catatan: Poin pelanggaran Anda mulai bertambah (<?php echo e($totalPoin); ?> poin)</strong><br>
<span style="opacity: 0.9; font-size: 0.9em;">Jaga perilaku dan taati peraturan pondok agar poin tidak terus bertambah.</span>
</div>
</div>
<?php endif; ?>
<div class="row-cards">
<div class="card card-danger">
<h3>Total Pelanggaran</h3>
<div class="card-value"><?php echo e($totalPelanggaran); ?></div>
<p style="margin: 4px 0 0; color: var(--text-light); font-size: 0.85em;">Sepanjang waktu</p>
<i class="fas fa-clipboard-list card-icon"></i>
</div>
<div class="card card-warning">
<h3>Total Poin</h3>
<div class="card-value"><?php echo e($totalPoin); ?></div>
<p style="margin: 4px 0 0; color: var(--text-light); font-size: 0.85em;">
<?php if($tingkatPoin): ?>
Tingkat: <strong><?php echo e($tingkatPoin); ?></strong>
<?php else: ?>
Belum ada poin
<?php endif; ?>
</p>
<i class="fas fa-star card-icon"></i>
</div>
<div class="card card-info">
<h3>Bulan Ini</h3>
<div class="card-value"><?php echo e($pelanggaranBulanIni); ?></div>
<p style="margin: 4px 0 0; color: var(--text-light); font-size: 0.85em;"><?php echo e(\Carbon\Carbon::now()->isoFormat('MMMM YYYY')); ?></p>
<i class="fas fa-calendar-alt card-icon"></i>
</div>
</div>
<?php if($totalPoin > 0): ?>
<div class="content-box" style="margin-bottom: 18px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
<h4 style="margin: 0; color: var(--primary-color);">
<i class="fas fa-chart-bar"></i> Akumulasi Poin Pelanggaran
</h4>
<span style="font-size: 0.85em; color: var(--text-light);">Batas perhatian: 20 poin | Batas berat: 50 poin</span>
</div>
<?php
$maxPoin = max(50, $totalPoin); // skala dinamis
$persenBar = min(100, round(($totalPoin / $maxPoin) * 100));
if ($totalPoin < 20) {
$colorBar = 'var(--success-color)';
} elseif ($totalPoin < 50) {
$colorBar = '#e67e22';
} else {
$colorBar = 'var(--danger-color)';
}
?>
<div style="background: #f0f0f0; border-radius: 50px; height: 22px; overflow: hidden; position: relative; margin-bottom: 8px;">
<div style="position: absolute; left: <?php echo e(round((20 / $maxPoin) * 100)); ?>%; top: 0; bottom: 0; width: 2px; background: rgba(0,0,0,0.2); z-index: 1;"></div>
<?php if($maxPoin >= 50): ?>
<div style="position: absolute; left: <?php echo e(round((50 / $maxPoin) * 100)); ?>%; top: 0; bottom: 0; width: 2px; background: rgba(0,0,0,0.2); z-index: 1;"></div>
<?php endif; ?>
<div style="height: 100%; width: <?php echo e($persenBar); ?>%; background: <?php echo e($colorBar); ?>; border-radius: 50px; transition: width 0.8s ease; display: flex; align-items: center; justify-content: flex-end; padding-right: 10px;">
<span style="color: white; font-size: 0.78em; font-weight: 700; white-space: nowrap;"><?php echo e($totalPoin); ?> poin</span>
</div>
</div>
<div style="display: flex; justify-content: space-between; font-size: 0.78em; color: var(--text-light);">
<span>0</span>
<span style="margin-left: <?php echo e(round((20/$maxPoin)*100)); ?>%">20</span>
<?php if($maxPoin >= 50): ?><span>50+</span><?php endif; ?>
</div>
</div>
<?php endif; ?>
<div class="content-box" style="margin-bottom: 14px;">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 11px;">
<form method="GET" action="<?php echo e(route('santri.pelanggaran.index')); ?>" style="display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end;">
<div>
<label style="font-size: 0.82em; color: var(--text-light); display: block; margin-bottom: 4px;">
<i class="fas fa-calendar-day"></i> Tanggal Mulai
</label>
<input type="date" name="tanggal_mulai" class="form-control" style="width: auto;"
value="<?php echo e(request('tanggal_mulai')); ?>">
</div>
<div>
<label style="font-size: 0.82em; color: var(--text-light); display: block; margin-bottom: 4px;">
<i class="fas fa-calendar-check"></i> Tanggal Selesai
</label>
<input type="date" name="tanggal_selesai" class="form-control" style="width: auto;"
value="<?php echo e(request('tanggal_selesai')); ?>">
</div>
<div style="display: flex; gap: 8px; padding-top: 2px;">
<button type="submit" class="btn btn-primary btn-sm">
<i class="fas fa-filter"></i> Filter
</button>
<a href="<?php echo e(route('santri.pelanggaran.index')); ?>" class="btn btn-secondary btn-sm">
<i class="fas fa-redo"></i> Reset
</a>
<a href="<?php echo e(route('santri.pelanggaran.index', ['bulan_ini' => 1])); ?>"
class="btn btn-sm <?php echo e(request('bulan_ini') ? 'btn-info' : 'btn-secondary'); ?>"
style="<?php echo e(request('bulan_ini') ? '' : 'border: 1px solid var(--primary-color); color: var(--primary-color); background: transparent;'); ?>">
<i class="fas fa-calendar-check"></i> Bulan Ini
</a>
</div>
</form>
<div style="display: flex; gap: 8px; flex-wrap: wrap;">
<a href="<?php echo e(route('santri.pelanggaran.kategori')); ?>" class="btn btn-warning btn-sm">
<i class="fas fa-list-ul"></i> Kategori & Poin
</a>
<a href="<?php echo e(route('santri.pembinaan.index')); ?>" class="btn btn-sm"
style="background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark, #1a4980) 100%);
color: white; border: none;">
<i class="fas fa-book-open"></i> Pembinaan & Sanksi
</a>
</div>
</div>
</div>
<div class="content-box">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px;">
<h3 style="margin: 0; color: var(--primary-color);">
<i class="fas fa-history"></i> Daftar Riwayat Pelanggaran
</h3>
<?php if(request()->hasAny(['tanggal_mulai', 'tanggal_selesai', 'bulan_ini'])): ?>
<span class="badge badge-info" style="font-size: 0.85em;">
<i class="fas fa-filter"></i> Filter aktif — <?php echo e($riwayat->total()); ?> data
</span>
<?php endif; ?>
</div>
<?php if($riwayat->count() > 0): ?>
<div style="overflow-x: auto;">
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 5%;">No</th>
<th style="width: 10%;">ID</th>
<th style="width: 13%;">Tanggal</th>
<th style="width: 28%;">Jenis Pelanggaran</th>
<th style="width: 9%; text-align: center;">Poin</th>
<th style="width: 25%;">Keterangan</th>
<th style="width: 10%; text-align: center;">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $riwayat; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr style="transition: background 0.2s;">
<td><?php echo e($riwayat->firstItem() + $index); ?></td>
<td>
<span class="badge badge-secondary" style="font-size: 0.8em;">
<?php echo e($item->id_riwayat); ?>
</span>
</td>
<td>
<div style="white-space: nowrap;">
<i class="fas fa-calendar-day" style="color: var(--text-light); font-size: 0.85em;"></i>
<span style="font-size: 0.9em;"><?php echo e(\Carbon\Carbon::parse($item->tanggal)->isoFormat('D MMM YYYY')); ?></span>
</div>
</td>
<td>
<strong><?php echo e($item->kategori->nama_pelanggaran ?? '-'); ?></strong>
<?php if($item->kategori && $item->kategori->id_kategori): ?>
<br><small style="color: var(--text-light);">
<i class="fas fa-tag"></i> <?php echo e($item->kategori->id_kategori); ?>
</small>
<?php endif; ?>
</td>
<td style="text-align: center;">
<?php $poin = $item->poin; ?>
<span class="badge badge-danger"
style="font-size: 0.9em; padding: 5px 10px;
<?php echo e($poin >= 20 ? 'background: linear-gradient(135deg, #dc3545, #a71d2a);' : ''); ?>">
<i class="fas fa-fire"></i> <?php echo e($poin); ?>
</span>
</td>
<td>
<?php if($item->keterangan): ?>
<div style="max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
font-size: 0.88em; color: var(--text-color);"
title="<?php echo e($item->keterangan); ?>">
<?php echo e($item->keterangan); ?>
</div>
<?php else: ?>
<span style="color: var(--text-light); font-size: 0.85em; font-style: italic;">Tidak ada keterangan</span>
<?php endif; ?>
</td>
<td style="text-align: center;">
<a href="<?php echo e(route('santri.pelanggaran.show', $item->id)); ?>"
class="btn btn-info btn-sm"
title="Lihat Detail">
<i class="fas fa-eye"></i> Detail
</a>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
</div>
<div style="margin-top: 14px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px;">
<p style="margin: 0; color: var(--text-light); font-size: 0.88em;">
Menampilkan <?php echo e($riwayat->firstItem()); ?>-<?php echo e($riwayat->lastItem()); ?> dari <?php echo e($riwayat->total()); ?> data
</p>
<?php echo e($riwayat->links()); ?>
</div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-check-circle" style="color: var(--success-color);"></i>
<h3>Tidak Ada Riwayat Pelanggaran</h3>
<?php if(request()->hasAny(['tanggal_mulai', 'tanggal_selesai', 'bulan_ini'])): ?>
<p>Tidak ditemukan data dengan filter yang dipilih.</p>
<a href="<?php echo e(route('santri.pelanggaran.index')); ?>" class="btn btn-secondary">
<i class="fas fa-redo"></i> Hapus Filter
</a>
<?php else: ?>
<p>Alhamdulillah, Anda belum memiliki catatan pelanggaran. Pertahankan!</p>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<?php if($totalPelanggaran > 0): ?>
<div class="content-box" style="margin-top: 18px;">
<h3 style="margin-bottom: 18px; color: var(--primary-color);">
<i class="fas fa-chart-pie"></i> Ringkasan Analisis
</h3>
<div class="grid-auto-fill">
<div style="background: var(--primary-light); padding: 16px; border-radius: var(--border-radius-sm); text-align: center;">
<i class="fas fa-calculator" style="font-size: 1.8em; color: var(--primary-color); margin-bottom: 8px;"></i>
<div style="font-size: 1.6em; font-weight: 700; color: var(--primary-dark);">
<?php echo e($totalPelanggaran > 0 ? number_format($totalPoin / $totalPelanggaran, 1) : 0); ?>
</div>
<p style="margin: 4px 0 0; color: var(--text-light); font-size: 0.85em;">Rata-rata Poin/Pelanggaran</p>
</div>
<div style="background: <?php echo e($totalPoin >= 50 ? 'var(--danger-color)' : ($totalPoin >= 20 ? '#fdebd0' : '#eafaf1')); ?>;
padding: 16px; border-radius: var(--border-radius-sm); text-align: center;">
<i class="fas fa-signal" style="font-size: 1.8em; color: <?php echo e($totalPoin >= 50 ? 'white' : ($totalPoin >= 20 ? '#ca6f1e' : 'var(--success-color)')); ?>; margin-bottom: 8px;"></i>
<div style="font-size: 1.4em; font-weight: 700; color: <?php echo e($totalPoin >= 50 ? 'white' : ($totalPoin >= 20 ? '#ca6f1e' : 'var(--success-color)')); ?>;">
<?php if($totalPoin >= 50): ?> Berat
<?php elseif($totalPoin >= 20): ?> Sedang
<?php else: ?> Ringan
<?php endif; ?>
</div>
<p style="margin: 4px 0 0; color: <?php echo e($totalPoin >= 50 ? 'rgba(255,255,255,0.8)' : 'var(--text-light)'); ?>; font-size: 0.85em;">Tingkat Pelanggaran</p>
</div>
<div style="background: #f8f9fa; padding: 16px; border-radius: var(--border-radius-sm); text-align: center;">
<i class="fas fa-calendar-day" style="font-size: 1.8em; color: var(--primary-color); margin-bottom: 8px;"></i>
<div style="font-size: 1em; font-weight: 600; color: var(--text-color);">
<?php if($riwayat->first()): ?>
<?php echo e(\Carbon\Carbon::parse($riwayat->first()->tanggal)->isoFormat('D MMM YYYY')); ?>
<?php else: ?>
—
<?php endif; ?>
</div>
<p style="margin: 4px 0 0; color: var(--text-light); font-size: 0.85em;">Pelanggaran Terakhir</p>
</div>
<div style="background: #fff3cd; padding: 16px; border-radius: var(--border-radius-sm); text-align: center;">
<i class="fas fa-calendar-check" style="font-size: 1.8em; color: #856404; margin-bottom: 8px;"></i>
<div style="font-size: 1.6em; font-weight: 700; color: #856404;">
<?php echo e($pelanggaranBulanIni); ?>
</div>
<p style="margin: 4px 0 0; color: #856404; font-size: 0.85em;">Pelanggaran Bulan Ini</p>
</div>
</div>
</div>
<?php endif; ?>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/santri/pelanggaran/index.blade.php ENDPATH**/ ?>

View File

@ -1,118 +0,0 @@
<?php $__env->startSection('title', 'Pembinaan & Sanksi'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-book-open"></i> Pembinaan & Sanksi</h2>
</div>
<div style="background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark, #1a4980) 100%);
color: white; padding: 22px 26px; border-radius: var(--border-radius); margin-bottom: 20px;
box-shadow: 0 4px 15px rgba(0,0,0,0.15); position: relative; overflow: hidden;">
<div style="position: absolute; right: -30px; top: -30px; width: 130px; height: 130px;
background: rgba(255,255,255,0.07); border-radius: 50%;"></div>
<div style="position: absolute; right: 50px; bottom: -40px; width: 90px; height: 90px;
background: rgba(255,255,255,0.05); border-radius: 50%;"></div>
<div style="position: relative; z-index: 1;">
<div style="display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap;">
<div style="background: rgba(255,255,255,0.15); padding: 14px 16px; border-radius: 12px; flex-shrink: 0;">
<i class="fas fa-scroll" style="font-size: 2em;"></i>
</div>
<div>
<h3 style="margin: 0 0 6px; font-size: 1.2em;">Panduan Tata Tertib Pondok</h3>
<p style="margin: 0; opacity: 0.88; font-size: 0.92em; line-height: 1.6;">
Berikut adalah panduan pembinaan dan ketentuan sanksi yang berlaku di pondok.
Baca dan pahami setiap poin dengan baik. Ketaatan pada aturan mencerminkan akhlak mulia.
</p>
<?php if($pembinaanList->count() > 0): ?>
<div style="margin-top: 10px; display: flex; gap: 10px; flex-wrap: wrap;">
<span style="background: rgba(255,255,255,0.2); padding: 4px 12px; border-radius: 50px; font-size: 0.85em;">
<i class="fas fa-file-alt"></i> <?php echo e($pembinaanList->count()); ?> dokumen tersedia
</span>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
<?php if($pembinaanList->count() > 0): ?>
<div style="display: grid; gap: 14px;">
<?php $__currentLoopData = $pembinaanList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div style="background: white; border: 1px solid #e8eaed; border-radius: var(--border-radius);
transition: box-shadow 0.2s, transform 0.2s; overflow: hidden;"
onmouseover="this.style.boxShadow='0 4px 20px rgba(0,0,0,0.1)'; this.style.transform='translateY(-1px)';"
onmouseout="this.style.boxShadow='none'; this.style.transform='translateY(0)';">
<a href="<?php echo e(route('santri.pembinaan.show', $item->id_pembinaan)); ?>"
style="display: flex; align-items: stretch; text-decoration: none; color: inherit;">
<div style="background: var(--primary-light); color: var(--primary-color);
padding: 0 20px; display: flex; align-items: center; justify-content: center;
min-width: 64px; font-size: 1.4em; font-weight: 800; flex-shrink: 0;">
<?php echo e(str_pad($index + 1, 2, '0', STR_PAD_LEFT)); ?>
</div>
<div style="padding: 16px 20px; flex: 1; min-width: 0;">
<div style="display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap;">
<div style="flex: 1; min-width: 0;">
<h4 style="margin: 0 0 6px; color: var(--primary-color); font-size: 1.05em;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
<?php echo e($item->judul); ?>
</h4>
<p style="margin: 0; color: var(--text-light); font-size: 0.88em; line-height: 1.5;
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;">
<?php echo e(\Illuminate\Support\Str::limit(strip_tags($item->konten), 140)); ?>
</p>
</div>
<div style="display: flex; align-items: center; gap: 10px; flex-shrink: 0;">
<div style="text-align: right;">
<span class="badge badge-primary" style="font-size: 0.78em; display: block; margin-bottom: 4px;">
<?php echo e($item->id_pembinaan); ?>
</span>
<span style="color: var(--text-light); font-size: 0.78em;">
<i class="fas fa-clock"></i>
<?php echo e($item->updated_at->diffForHumans()); ?>
</span>
</div>
<i class="fas fa-chevron-right" style="color: var(--primary-color); opacity: 0.5; font-size: 1.1em;"></i>
</div>
</div>
</div>
</a>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
<div class="info-box" style="margin-top: 20px;">
<p style="margin: 0;">
<i class="fas fa-info-circle"></i>
Jika ada pertanyaan tentang isi tata tertib ini, silakan hubungi pengurus atau bagian administrasi pondok.
</p>
</div>
<?php else: ?>
<div class="content-box">
<div class="empty-state">
<i class="fas fa-book-open" style="color: var(--primary-color); opacity: 0.4;"></i>
<h3>Belum Ada Konten</h3>
<p>Panduan pembinaan & sanksi belum tersedia. Silakan hubungi pengurus pondok untuk informasi lebih lanjut.</p>
</div>
</div>
<?php endif; ?>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/santri/pembinaan/index.blade.php ENDPATH**/ ?>

View File

@ -1,364 +0,0 @@

<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-wallet"></i> Manajemen Uang Saku Santri</h2>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success"><i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?></div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger"><i class="fas fa-exclamation-circle"></i> <?php echo e(session('error')); ?></div>
<?php endif; ?>
<div class="content-box" style="margin-bottom:16px;">
<form method="GET" action="<?php echo e(route('admin.uang-saku.index')); ?>" id="filterForm"
style="display:flex; flex-wrap:wrap; gap:10px; align-items:flex-end; margin-bottom:18px;">
<?php if(request('search')): ?> <input type="hidden" name="search" value="<?php echo e(request('search')); ?>"> <?php endif; ?>
<?php if(request('sort')): ?> <input type="hidden" name="sort" value="<?php echo e(request('sort')); ?>"> <?php endif; ?>
<div>
<label style="font-size:.78rem;color:var(--text-light);display:block;margin-bottom:3px;">Dari Tanggal</label>
<input type="date" name="dari" class="form-control" value="<?php echo e($dari); ?>" style="width:155px;">
</div>
<div>
<label style="font-size:.78rem;color:var(--text-light);display:block;margin-bottom:3px;">Sampai Tanggal</label>
<input type="date" name="sampai" class="form-control" value="<?php echo e($sampai); ?>" style="width:155px;">
</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;align-self:flex-end;">
<?php
$bulanIniDari = now()->startOfMonth()->format('Y-m-d');
$bulanIniSampai = now()->endOfMonth()->format('Y-m-d');
$isBulanIni = $dari === $bulanIniDari && $sampai === $bulanIniSampai;
$isHariIni = $dari === now()->format('Y-m-d') && $sampai === now()->format('Y-m-d');
?>
<button type="button" onclick="setPreset('today')"
class="btn btn-sm <?php echo e($isHariIni ? 'btn-primary' : 'btn-secondary'); ?>">
Hari Ini
</button>
<button type="button" onclick="setPreset('month')"
class="btn btn-sm <?php echo e($isBulanIni ? 'btn-primary' : 'btn-secondary'); ?>">
Bulan Ini
</button>
<button type="submit" class="btn btn-primary btn-sm">
<i class="fas fa-filter"></i> Terapkan
</button>
</div>
</form>
<div class="row-cards row-cards-4" style="margin-bottom:10px;">
<div class="card card-info">
<h3>Total Transaksi</h3>
<p class="card-value"><?php echo e($kpi['total_transaksi']); ?></p>
<span class="card-sub">dari <?php echo e($kpi['total_santri']); ?> santri</span>
<i class="fas fa-exchange-alt card-icon"></i>
</div>
<div class="card card-success">
<h3>Total Pemasukan</h3>
<p class="card-value" style="font-size:1.05rem;">Rp <?php echo e(number_format($kpi['total_pemasukan'], 0, ',', '.')); ?></p>
<span class="card-sub">
<?php echo e(\Carbon\Carbon::parse($dari)->format('d M')); ?> &ndash; <?php echo e(\Carbon\Carbon::parse($sampai)->format('d M Y')); ?>
</span>
<i class="fas fa-arrow-circle-down card-icon"></i>
</div>
<div class="card card-warning">
<h3>Total Pengeluaran</h3>
<p class="card-value" style="font-size:1.05rem;">Rp <?php echo e(number_format($kpi['total_pengeluaran'], 0, ',', '.')); ?></p>
<span class="card-sub">
<?php echo e(\Carbon\Carbon::parse($dari)->format('d M')); ?> &ndash; <?php echo e(\Carbon\Carbon::parse($sampai)->format('d M Y')); ?>
</span>
<i class="fas fa-arrow-circle-up card-icon"></i>
</div>
<div class="card <?php echo e($kpi['selisih'] >= 0 ? 'card-success' : 'card-danger'); ?>">
<h3>
Selisih Periode
<span title="Selisih = Total Pemasukan dikurangi Total Pengeluaran pada periode yang dipilih. Surplus berarti lebih banyak uang masuk; Defisit berarti lebih banyak uang keluar."
style="cursor:help;font-size:.75rem;color:var(--text-light);">
<i class="fas fa-question-circle"></i>
</span>
</h3>
<p class="card-value" style="font-size:1.05rem;">
<?php echo e($kpi['selisih'] >= 0 ? '+' : '-'); ?> Rp <?php echo e(number_format(abs($kpi['selisih']), 0, ',', '.')); ?>
</p>
<span class="card-sub"><?php echo e($kpi['selisih'] >= 0 ? '✓ Surplus periode ini' : '✗ Defisit periode ini'); ?></span>
<i class="fas fa-balance-scale card-icon"></i>
</div>
</div>
<div class="row-cards row-cards-1">
<div class="card card-primary" style="border-left: 4px solid var(--primary-color); position:relative;">
<div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap;justify-content:space-between;">
<div>
<h3 style="margin:0 0 4px;">
Total Saldo Seluruh Santri
</h3>
<p class="card-value" style="font-size:1.4rem;margin:0;color:var(--primary-color);">
Rp <?php echo e(number_format($kpi['total_saldo_realtime'], 0, ',', '.')); ?>
</p>
</div>
<div style="text-align:right;">
<span class="badge badge-info" style="font-size:.8rem;padding:5px 10px;">
<i class="fas fa-clock"></i> Real-time — tidak terpengaruh filter tanggal
</span>
</div>
</div>
<i class="fas fa-piggy-bank card-icon"></i>
</div>
</div>
</div>
<div class="content-box">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:14px; flex-wrap:wrap; gap:10px;">
<a href="<?php echo e(route('admin.uang-saku.create')); ?>" class="btn btn-primary">
<i class="fas fa-plus"></i> Tambah Transaksi
</a>
<div style="display:flex; gap:8px; flex-wrap:wrap; align-items:center;">
<form method="GET" action="<?php echo e(route('admin.uang-saku.index')); ?>" id="sortForm" style="display:flex;gap:6px;align-items:center;">
<input type="hidden" name="dari" value="<?php echo e($dari); ?>">
<input type="hidden" name="sampai" value="<?php echo e($sampai); ?>">
<?php if(request('search')): ?> <input type="hidden" name="search" value="<?php echo e(request('search')); ?>"> <?php endif; ?>
<label style="font-size:.79rem;color:var(--text-light);white-space:nowrap;">
<i class="fas fa-sort"></i> Urut:
</label>
<select name="sort" class="form-control form-control-sm" onchange="this.form.submit()" style="width:auto;">
<option value="nama" <?php echo e($sort==='nama' ? 'selected' : ''); ?>>Nama A–Z</option>
<option value="saldo_asc" <?php echo e($sort==='saldo_asc' ? 'selected' : ''); ?>>Saldo Terendah</option>
<option value="saldo_desc" <?php echo e($sort==='saldo_desc' ? 'selected' : ''); ?>>Saldo Tertinggi</option>
<option value="transaksi_desc" <?php echo e($sort==='transaksi_desc'? 'selected' : ''); ?>>Transaksi Terbanyak</option>
<option value="terakhir" <?php echo e($sort==='terakhir' ? 'selected' : ''); ?>>Transaksi Terbaru</option>
</select>
</form>
<form method="GET" action="<?php echo e(route('admin.uang-saku.index')); ?>" style="display:flex;gap:6px;">
<input type="hidden" name="dari" value="<?php echo e($dari); ?>">
<input type="hidden" name="sampai" value="<?php echo e($sampai); ?>">
<input type="hidden" name="sort" value="<?php echo e($sort); ?>">
<input type="text" name="search" class="form-control form-control-sm"
placeholder="Cari nama / ID santri..."
value="<?php echo e(request('search')); ?>" style="width:210px;">
<button type="submit" class="btn btn-primary btn-sm"><i class="fas fa-search"></i></button>
<?php if(request('search')): ?>
<a href="<?php echo e(route('admin.uang-saku.index', ['dari'=>$dari,'sampai'=>$sampai,'sort'=>$sort])); ?>"
class="btn btn-secondary btn-sm"><i class="fas fa-times"></i></a>
<?php endif; ?>
</form>
</div>
</div>
<div style="display:flex;gap:14px;margin-bottom:12px;flex-wrap:wrap;font-size:.78rem;color:var(--text-light);">
<span><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:#6FBA9D;margin-right:4px;"></span>Saldo ≥ Rp 100rb</span>
<span><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:#f5a623;margin-right:4px;"></span>Saldo Rp 20rb – 99rb</span>
<span><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:#FF8B94;margin-right:4px;"></span>Saldo &lt; Rp 20rb</span>
</div>
<?php if($santriList->count() > 0): ?>
<?php $__currentLoopData = $santriList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $santri): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$saldoColor = $santri->saldo_terakhir >= 100000 ? '#6FBA9D'
: ($santri->saldo_terakhir >= 20000 ? '#f5a623' : '#FF8B94');
$saldoDot = $saldoColor;
?>
<div class="content-box us-row" style="margin-bottom:10px;padding:0;overflow:hidden;">
<div class="us-row-header"
onclick="toggleDetail('detail-<?php echo e($santri->id_santri); ?>', this)"
style="display:flex;align-items:center;gap:0;cursor:pointer;padding:13px 16px;flex-wrap:wrap;gap:10px;">
<div style="display:flex;align-items:center;gap:10px;flex:1;min-width:160px;">
<i class="fas fa-chevron-right toggle-arrow"
style="transition:transform .2s;color:var(--text-light);font-size:.8rem;flex-shrink:0;"></i>
<div>
<div style="font-weight:700;font-size:.93rem;"><?php echo e($santri->nama_lengkap); ?></div>
<div style="font-size:.76rem;color:var(--text-light);"><?php echo e($santri->id_santri); ?></div>
</div>
</div>
<div style="display:flex;flex-direction:column;align-items:center;min-width:120px;">
<div style="font-size:.7rem;color:var(--text-light);margin-bottom:2px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;">Saldo</div>
<div style="font-size:1.05rem;font-weight:800;color:<?php echo e($saldoColor); ?>;display:flex;align-items:center;gap:5px;">
<span style="width:8px;height:8px;border-radius:50%;background:<?php echo e($saldoDot); ?>;flex-shrink:0;display:inline-block;"></span>
Rp <?php echo e(number_format($santri->saldo_terakhir, 0, ',', '.')); ?>
</div>
</div>
<div style="width:1px;height:36px;background:var(--primary-light);flex-shrink:0;"></div>
<div style="display:flex;flex-direction:column;align-items:center;min-width:100px;">
<div style="font-size:.7rem;color:var(--text-light);margin-bottom:2px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;">Masuk Bln Ini</div>
<div style="font-size:.85rem;font-weight:700;color:#6FBA9D;">
+ Rp <?php echo e(number_format($santri->pemasukan_bulan, 0, ',', '.')); ?>
</div>
</div>
<div style="display:flex;flex-direction:column;align-items:center;min-width:100px;">
<div style="font-size:.7rem;color:var(--text-light);margin-bottom:2px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;">Keluar Bln Ini</div>
<div style="font-size:.85rem;font-weight:700;color:#FF8B94;">
- Rp <?php echo e(number_format($santri->pengeluaran_bulan, 0, ',', '.')); ?>
</div>
</div>
<div style="width:1px;height:36px;background:var(--primary-light);flex-shrink:0;"></div>
<div style="display:flex;flex-direction:column;align-items:center;min-width:90px;">
<div style="font-size:.7rem;color:var(--text-light);margin-bottom:2px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;">Transaksi</div>
<span class="badge badge-info" style="font-size:.74rem;"><?php echo e($santri->transaksi_bulan_ini); ?>x bln ini</span>
<?php if($santri->transaksi_terakhir_tgl): ?>
<div style="font-size:.7rem;color:var(--text-light);margin-top:3px;">
terakhir <?php echo e(\Carbon\Carbon::parse($santri->transaksi_terakhir_tgl)->format('d/m/Y')); ?>
</div>
<?php endif; ?>
</div>
<div style="display:flex;gap:5px;flex-shrink:0;" onclick="event.stopPropagation()">
<a href="<?php echo e(route('admin.uang-saku.create')); ?>?id_santri=<?php echo e($santri->id_santri); ?>"
class="btn btn-success btn-sm" title="Tambah Transaksi">
<i class="fas fa-plus"></i>
</a>
<a href="<?php echo e(route('admin.uang-saku.riwayat', $santri->id_santri)); ?>"
class="btn btn-primary btn-sm" title="Riwayat Lengkap">
<i class="fas fa-history"></i>
</a>
</div>
</div>
<div id="detail-<?php echo e($santri->id_santri); ?>"
style="display:none;border-top:1px solid var(--primary-light);padding:12px 16px;">
<?php if($santri->transaksi_terbaru->isNotEmpty()): ?>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>Tanggal</th>
<th>Jenis</th>
<th>Nominal</th>
<th>Keterangan</th>
<th>Saldo</th>
<th class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $santri->transaksi_terbaru; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $tx): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($tx->tanggal_transaksi->format('d/m/Y')); ?></td>
<td>
<?php if($tx->jenis_transaksi === 'pemasukan'): ?>
<span class="badge badge-success"><i class="fas fa-arrow-down"></i> Masuk</span>
<?php else: ?>
<span class="badge badge-danger"><i class="fas fa-arrow-up"></i> Keluar</span>
<?php endif; ?>
</td>
<td class="nominal-highlight"><?php echo e($tx->nominal_format); ?></td>
<td><div class="content-preview"><?php echo e($tx->keterangan ?? '-'); ?></div></td>
<td style="font-weight:600;color:<?php echo e($tx->saldo_sesudah >= 0 ? '#6FBA9D' : '#FF8B94'); ?>;">
Rp <?php echo e(number_format($tx->saldo_sesudah, 0, ',', '.')); ?>
</td>
<td class="text-center">
<div style="display:flex;gap:4px;justify-content:center;">
<a href="<?php echo e(route('admin.uang-saku.show', $tx->id)); ?>" class="btn btn-primary btn-sm"><i class="fas fa-eye"></i></a>
<a href="<?php echo e(route('admin.uang-saku.edit', $tx->id)); ?>" class="btn btn-warning btn-sm"><i class="fas fa-edit"></i></a>
<form action="<?php echo e(route('admin.uang-saku.destroy', $tx->id)); ?>" method="POST"
style="display:inline;" onsubmit="return confirm('Yakin hapus transaksi ini?')">
<?php echo csrf_field(); ?> <?php echo method_field('DELETE'); ?>
<button class="btn btn-danger btn-sm"><i class="fas fa-trash"></i></button>
</form>
</div>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<?php if($santri->transaksi_terbaru->count() >= 5): ?>
<div style="text-align:center;margin-top:10px;">
<a href="<?php echo e(route('admin.uang-saku.riwayat', $santri->id_santri)); ?>"
class="btn btn-secondary btn-sm">
<i class="fas fa-arrow-right"></i> Lihat Semua Riwayat
</a>
</div>
<?php endif; ?>
<?php else: ?>
<p class="text-muted" style="margin:0;">Belum ada transaksi.</p>
<?php endif; ?>
</div>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<div style="margin-top:14px;"><?php echo e($santriList->links()); ?></div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-wallet"></i>
<h3>Belum Ada Data</h3>
<p>Belum ada santri dengan transaksi uang saku.</p>
<a href="<?php echo e(route('admin.uang-saku.create')); ?>" class="btn btn-success">
<i class="fas fa-plus"></i> Tambah Transaksi
</a>
</div>
<?php endif; ?>
</div>
<script>
function toggleDetail(id, el) {
var detail = document.getElementById(id);
var arrow = el.querySelector('.toggle-arrow');
var open = detail.style.display !== 'none';
detail.style.display = open ? 'none' : 'block';
arrow.style.transform = open ? 'rotate(0deg)' : 'rotate(90deg)';
}
function setPreset(type) {
var form = document.getElementById('filterForm');
var dari = form.querySelector('[name=dari]');
var sampai = form.querySelector('[name=sampai]');
var today = new Date();
var pad = n => String(n).padStart(2, '0');
var ymd = d => d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate());
if (type === 'today') {
dari.value = ymd(today);
sampai.value = ymd(today);
} else if (type === 'month') {
var first = new Date(today.getFullYear(), today.getMonth(), 1);
var last = new Date(today.getFullYear(), today.getMonth() + 1, 0);
dari.value = ymd(first);
sampai.value = ymd(last);
}
form.submit();
}
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/uang-saku/index.blade.php ENDPATH**/ ?>

View File

@ -1,410 +0,0 @@
<?php $__env->startSection('title', 'Pengajuan Kepulangan dari Mobile'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-mobile-alt"></i> Pengajuan Kepulangan dari Mobile</h2>
<p style="color: #7F8C8D; margin-top: 5px;">Kelola pengajuan izin kepulangan yang diajukan melalui aplikasi mobile</p>
</div>
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 14px; border-radius: 12px; margin-bottom: 14px;">
<div style="display: flex; align-items: center; gap: 11px;">
<div style="background: rgba(255,255,255,0.2); padding: 15px; border-radius: 12px;">
<i class="fas fa-info-circle" style="font-size: 2rem;"></i>
</div>
<div>
<h4 style="margin: 0 0 5px 0;">Tentang Pengajuan dari Mobile</h4>
<p style="margin: 0; font-size: 0.95rem; opacity: 0.9;">
Pengajuan ini dikirim oleh wali santri melalui aplikasi mobile.
Setelah Anda approve, data akan otomatis masuk ke tabel kepulangan utama dengan status "Disetujui".
</p>
</div>
</div>
</div>
<div class="row-cards">
<div class="card card-info">
<h3>Total Pengajuan</h3>
<div class="card-value"><?php echo e($stats['total_data']); ?></div>
<i class="fas fa-list card-icon"></i>
</div>
<div class="card card-warning">
<h3>Menunggu Review</h3>
<div class="card-value"><?php echo e($stats['menunggu']); ?></div>
<i class="fas fa-clock card-icon"></i>
</div>
<div class="card card-success">
<h3>Disetujui</h3>
<div class="card-value"><?php echo e($stats['disetujui']); ?></div>
<i class="fas fa-check-circle card-icon"></i>
</div>
<div class="card card-danger">
<h3>Ditolak</h3>
<div class="card-value"><?php echo e($stats['ditolak']); ?></div>
<i class="fas fa-times-circle card-icon"></i>
</div>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger">
<i class="fas fa-exclamation-circle"></i> <?php echo e(session('error')); ?>
</div>
<?php endif; ?>
<div class="content-box">
<form method="GET" action="<?php echo e(route('admin.kepulangan.pengajuan')); ?>" id="filterForm" style="margin-bottom: 14px;">
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 11px; align-items: end;">
<div class="form-group" style="margin-bottom: 0;">
<input type="text"
name="search"
class="form-control"
placeholder="Cari nama santri atau ID..."
value="<?php echo e(request('search')); ?>">
</div>
<div class="form-group" style="margin-bottom: 0;">
<select name="status" class="form-control" onchange="document.getElementById('filterForm').submit();">
<option value="">Semua Status</option>
<option value="Menunggu" <?php echo e(request('status') == 'Menunggu' ? 'selected' : ''); ?>>Menunggu</option>
<option value="Disetujui" <?php echo e(request('status') == 'Disetujui' ? 'selected' : ''); ?>>Disetujui</option>
<option value="Ditolak" <?php echo e(request('status') == 'Ditolak' ? 'selected' : ''); ?>>Ditolak</option>
</select>
</div>
<div style="display: flex; gap: 10px;">
<button type="submit" class="btn btn-primary">
<i class="fas fa-search"></i> Filter
</button>
<a href="<?php echo e(route('admin.kepulangan.pengajuan')); ?>" class="btn btn-secondary">
<i class="fas fa-redo"></i> Reset
</a>
</div>
</div>
</form>
<div style="overflow-x: auto;">
<table class="data-table">
<thead>
<tr>
<th>ID Pengajuan</th>
<th>Santri</th>
<th>Tanggal Pengajuan</th>
<th>Tanggal Pulang - Kembali</th>
<th>Durasi</th>
<th>Alasan</th>
<th>Status</th>
<th class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__empty_1 = true; $__currentLoopData = $pengajuan; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
<tr style="<?php echo e($item->status == 'Menunggu' ? 'background-color: rgba(255, 193, 7, 0.1);' : ''); ?>">
<td>
<strong><?php echo e($item->id_pengajuan); ?></strong>
<?php if($item->status == 'Menunggu'): ?>
<span style="display: inline-block; background: #ffc107; color: #000; padding: 2px 6px; border-radius: 4px; font-size: 0.75rem; margin-left: 5px;">
<i class="fas fa-clock"></i> BARU
</span>
<?php endif; ?>
</td>
<td>
<div>
<strong><?php echo e($item->santri->nama_lengkap ?? 'N/A'); ?></strong><br>
<small style="color: #7F8C8D;">
<?php echo e($item->santri->id_santri ?? ''); ?> | <?php echo e($item->santri->kelas ?? ''); ?>
</small>
</div>
</td>
<td>
<?php echo e($item->created_at->format('d M Y')); ?><br>
<small style="color: #7F8C8D;"><?php echo e($item->created_at->format('H:i')); ?> WIB</small>
</td>
<td>
<?php echo e($item->tanggal_pulang->format('d M Y')); ?><br>
<small style="color: #7F8C8D;">s/d <?php echo e($item->tanggal_kembali->format('d M Y')); ?></small>
</td>
<td>
<span style="display: inline-block; background: <?php echo e($item->durasi_izin > 7 ? '#ffc107' : '#6c757d'); ?>; color: <?php echo e($item->durasi_izin > 7 ? '#000' : '#fff'); ?>; padding: 4px 8px; border-radius: 4px; font-size: 0.85rem; font-weight: 600;">
<?php echo e($item->durasi_izin); ?> hari
</span>
</td>
<td>
<span style="max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block;" title="<?php echo e($item->alasan); ?>">
<?php echo e($item->alasan); ?>
</span>
</td>
<td>
<span style="display: inline-block; padding: 4px 10px; border-radius: 4px; font-size: 0.85rem; font-weight: 600;
<?php if($item->status == 'Menunggu'): ?> background: #ffc107; color: #000;
<?php elseif($item->status == 'Disetujui'): ?> background: #28a745; color: white;
<?php else: ?> background: #dc3545; color: white;
<?php endif; ?>">
<?php echo e($item->status); ?>
</span>
<?php if($item->reviewed_at): ?>
<br><small style="color: #7F8C8D;"><?php echo e($item->reviewed_at->format('d M Y H:i')); ?></small>
<?php endif; ?>
</td>
<td class="text-center">
<div style="display: flex; gap: 5px; justify-content: center; flex-wrap: wrap;">
<?php if($item->status == 'Menunggu'): ?>
<button type="button"
class="btn btn-sm btn-success"
onclick="approvePengajuan(<?php echo e($item->id); ?>)"
title="Setujui">
<i class="fas fa-check"></i> Setujui
</button>
<button type="button"
class="btn btn-sm btn-danger"
onclick="rejectPengajuan(<?php echo e($item->id); ?>)"
title="Tolak">
<i class="fas fa-times"></i> Tolak
</button>
<?php else: ?>
<small style="color: #7F8C8D;">
<?php if($item->catatan_review): ?>
<strong>Catatan:</strong><br><?php echo e(Str::limit($item->catatan_review, 50)); ?>
<?php else: ?>
Sudah direview
<?php endif; ?>
</small>
<?php endif; ?>
</div>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
<tr>
<td colspan="8" style="text-align: center; padding: 22px;">
<i class="fas fa-inbox" style="font-size: 2.2rem; color: #ccc; margin-bottom: 15px;"></i>
<p style="color: #7F8C8D;">Tidak ada pengajuan kepulangan dari mobile</p>
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
<?php if($pengajuan->hasPages()): ?>
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 14px; flex-wrap: wrap; gap: 11px;">
<div>
Menampilkan <?php echo e($pengajuan->firstItem() ?? 0); ?> - <?php echo e($pengajuan->lastItem() ?? 0); ?>
dari <?php echo e($pengajuan->total()); ?> data
</div>
<div>
<?php echo e($pengajuan->appends(request()->query())->links()); ?>
</div>
</div>
<?php endif; ?>
</div>
<div class="modal fade" id="approveModal" tabindex="-1" style="display: none;">
<div class="modal-dialog">
<div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;">
<form id="approveForm">
<?php echo csrf_field(); ?>
<div style="margin-bottom: 14px;">
<h3 style="margin: 0; color: #2C3E50;">
<i class="fas fa-check-circle" style="color: #28a745;"></i>
Setujui Pengajuan
</h3>
</div>
<p>Pengajuan akan otomatis dipindahkan ke tabel kepulangan dengan status <strong>"Disetujui"</strong>.</p>
<div class="form-group">
<label>Catatan Persetujuan (Opsional):</label>
<textarea name="catatan_review" class="form-control" rows="3"
placeholder="Tambahkan catatan untuk persetujuan ini..."></textarea>
</div>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;">
<button type="button" class="btn btn-secondary" onclick="closeModal('approveModal')">Batal</button>
<button type="submit" class="btn btn-success">
<i class="fas fa-check"></i> Setujui Pengajuan
</button>
</div>
</form>
</div>
</div>
</div>
<div class="modal fade" id="rejectModal" tabindex="-1" style="display: none;">
<div class="modal-dialog">
<div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;">
<form id="rejectForm">
<?php echo csrf_field(); ?>
<div style="margin-bottom: 14px;">
<h3 style="margin: 0; color: #2C3E50;">
<i class="fas fa-times-circle" style="color: #dc3545;"></i>
Tolak Pengajuan
</h3>
</div>
<p style="color: #dc3545;">Pengajuan akan ditolak dan wali santri akan menerima notifikasi penolakan.</p>
<div class="form-group">
<label>Alasan Penolakan: <span style="color: #dc3545;">*</span></label>
<textarea name="catatan_review" class="form-control" rows="3"
placeholder="Jelaskan alasan penolakan..." required></textarea>
</div>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;">
<button type="button" class="btn btn-secondary" onclick="closeModal('rejectModal')">Batal</button>
<button type="submit" class="btn btn-danger">
<i class="fas fa-times"></i> Tolak Pengajuan
</button>
</div>
</form>
</div>
</div>
</div>
<style>
.modal.fade {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 1000;
align-items: center;
justify-content: center;
}
.modal-dialog {
max-width: 500px;
width: 90%;
margin: auto;
}
.modal-content {
max-height: 90vh;
overflow-y: auto;
}
</style>
<script>
let currentPengajuanId = null;
// Approve
function approvePengajuan(id) {
currentPengajuanId = id;
document.getElementById('approveModal').style.display = 'flex';
}
document.getElementById('approveForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML;
submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...';
fetch(`/admin/kepulangan/pengajuan/${currentPengajuanId}/approve`, {
method: 'POST',
body: formData,
headers: { 'X-CSRF-TOKEN': '<?php echo e(csrf_token()); ?>' }
})
.then(response => response.json())
.then(data => {
if (data.success) {
closeModal('approveModal');
showAlert('success', data.message);
setTimeout(() => window.location.reload(), 1000);
} else {
showAlert('danger', data.message);
}
})
.catch(error => showAlert('danger', 'Error: ' + error.message))
.finally(() => {
submitBtn.disabled = false;
submitBtn.innerHTML = originalText;
});
});
// Reject
function rejectPengajuan(id) {
currentPengajuanId = id;
document.getElementById('rejectModal').style.display = 'flex';
}
document.getElementById('rejectForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML;
submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...';
fetch(`/admin/kepulangan/pengajuan/${currentPengajuanId}/reject`, {
method: 'POST',
body: formData,
headers: { 'X-CSRF-TOKEN': '<?php echo e(csrf_token()); ?>' }
})
.then(response => response.json())
.then(data => {
if (data.success) {
closeModal('rejectModal');
showAlert('success', data.message);
setTimeout(() => window.location.reload(), 1000);
} else {
showAlert('danger', data.message);
}
})
.catch(error => showAlert('danger', 'Error: ' + error.message))
.finally(() => {
submitBtn.disabled = false;
submitBtn.innerHTML = originalText;
});
});
// Helper functions
function closeModal(modalId) {
document.getElementById(modalId).style.display = 'none';
}
function showAlert(type, message) {
const alertDiv = document.createElement('div');
alertDiv.className = `alert alert-${type}`;
alertDiv.innerHTML = `<i class="fas fa-${type === 'success' ? 'check' : 'exclamation'}-circle"></i> ${message}`;
const pageHeader = document.querySelector('.page-header');
pageHeader.insertAdjacentElement('afterend', alertDiv);
setTimeout(() => alertDiv.remove(), 5000);
}
// Close modals on ESC
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
document.querySelectorAll('.modal.fade').forEach(modal => modal.style.display = 'none');
}
});
// Close modal on outside click
document.querySelectorAll('.modal.fade').forEach(modal => {
modal.addEventListener('click', function(e) {
if (e.target === this) {
this.style.display = 'none';
}
});
});
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kepulangan/pengajuan.blade.php ENDPATH**/ ?>

View File

@ -1,252 +0,0 @@
<?php $__env->startSection('title', 'Tambah Pembinaan & Sanksi'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-plus-circle"></i> Tambah Peraturan & Tata Tertib</h2>
</div>
<div class="content-box">
<form action="<?php echo e(route('admin.pembinaan-sanksi.store')); ?>" method="POST">
<?php echo csrf_field(); ?>
<div class="form-group">
<label>
<i class="fas fa-id-card form-icon"></i>
ID Peraturan (Preview)
</label>
<input type="text" class="form-control" value="<?php echo e($nextId); ?>" disabled>
<span class="form-text">ID akan dibuat otomatis</span>
</div>
<div class="form-group">
<label for="judul">
<i class="fas fa-heading form-icon"></i>
Judul <span style="color: var(--danger-color);">*</span>
</label>
<input type="text"
name="judul"
id="judul"
class="form-control <?php $__errorArgs = ['judul'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?> is-invalid <?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>"
value="<?php echo e(old('judul')); ?>"
placeholder="Contoh: Pembinaan & sanksi, Peraturan Pondok, Tata Tertib, dll"
required>
<?php $__errorArgs = ['judul'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<span class="invalid-feedback"><?php echo e($message); ?></span>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>
</div>
<div class="form-group">
<label for="konten">
<i class="fas fa-file-alt form-icon"></i>
Konten <span style="color: var(--danger-color);">*</span>
</label>
<div id="editor-container" style="min-height: 400px; background: white; border: 1px solid #ddd; border-radius: 4px;"></div>
<textarea name="konten"
id="konten"
class="form-control <?php $__errorArgs = ['konten'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?> is-invalid <?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>"
style="display: none;"
required><?php echo e(old('konten')); ?></textarea>
<?php $__errorArgs = ['konten'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<span class="invalid-feedback" style="display: block;"><?php echo e($message); ?></span>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>
<span class="form-text">
<i class="fas fa-magic"></i> Gunakan toolbar di atas untuk formatting: Bold, Italic, Daftar Bernomor, Warna, dsb.
</span>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
<div class="form-group">
<label for="urutan">
<i class="fas fa-sort-numeric-up form-icon"></i>
Urutan Tampilan
</label>
<input type="number"
name="urutan"
id="urutan"
class="form-control <?php $__errorArgs = ['urutan'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?> is-invalid <?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>"
value="<?php echo e(old('urutan', 0)); ?>"
min="0">
<?php $__errorArgs = ['urutan'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<span class="invalid-feedback"><?php echo e($message); ?></span>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>
</div>
<div class="form-group">
<label>
<i class="fas fa-toggle-on form-icon"></i>
Status
</label>
<div style="margin-top: 12px;">
<label style="display: flex; align-items: center; cursor: pointer;">
<input type="checkbox"
name="is_active"
value="1"
<?php echo e(old('is_active', true) ? 'checked' : ''); ?>
style="margin-right: 8px;">
<span>Aktif</span>
</label>
</div>
</div>
</div>
<div class="btn-group" style="margin-top: 22px;">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i> Simpan
</button>
<a href="<?php echo e(route('admin.pembinaan-sanksi.index')); ?>" class="btn btn-secondary">
<i class="fas fa-times"></i> Batal
</a>
</div>
</form>
</div>
<!-- Quill Editor CSS -->
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
<!-- Quill Editor JS -->
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
<script>
// Initialize Quill Editor
var quill = new Quill('#editor-container', {
theme: 'snow',
modules: {
toolbar: [
[{ 'header': [1, 2, 3, false] }],
['bold', 'italic', 'underline', 'strike'],
[{ 'color': [] }, { 'background': [] }],
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
[{ 'indent': '-1'}, { 'indent': '+1' }],
[{ 'align': [] }],
['link', 'image'],
['clean']
]
},
placeholder: 'Tulis konten di sini...\n\n Gunakan toolbar di atas untuk formatting:\n Heading untuk judul\n Bold/Italic untuk penekanan\n List untuk daftar\nColor untuk highlight'
});
// Load existing content if any (for old() values)
var existingContent = document.getElementById('konten').value;
if (existingContent) {
quill.root.innerHTML = existingContent;
}
// Sync Quill content to hidden textarea on form submit
document.querySelector('form').onsubmit = function() {
var kontenInput = document.getElementById('konten');
kontenInput.value = quill.root.innerHTML;
// Validation: check if content is empty
if (quill.getText().trim().length === 0) {
alert('Konten tidak boleh kosong!');
return false;
}
return true;
};
// Optional: Sync on every change (real-time)
quill.on('text-change', function() {
document.getElementById('konten').value = quill.root.innerHTML;
});
</script>
<style>
/* Custom Quill Editor Styling */
.ql-toolbar {
background-color: #f8f9fa;
border-radius: 4px 4px 0 0;
border-bottom: 2px solid #dee2e6;
}
.ql-container {
font-size: 11px;
font-family: Arial, sans-serif;
min-height: 350px;
}
.ql-editor {
min-height: 350px;
max-height: 600px;
overflow-y: auto;
}
.ql-editor h1 {
font-size: 2em;
color: #2c3e50;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ql-editor h2 {
font-size: 1.5em;
color: #34495e;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ql-editor h3 {
font-size: 1.2em;
color: #34495e;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ql-editor p {
margin-bottom: 1em;
}
.ql-editor ol, .ql-editor ul {
padding-left: 1.5em;
margin-bottom: 1em;
}
.ql-editor li {
margin-bottom: 0.5em;
}
</style>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/pembinaan_sanksi/create.blade.php ENDPATH**/ ?>

View File

@ -1,136 +0,0 @@

<?php $__env->startSection('title', 'Riwayat Uang Saku'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-wallet"></i> Riwayat Uang Saku</h2>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger">
<i class="fas fa-exclamation-circle"></i> <?php echo e(session('error')); ?>
</div>
<?php endif; ?>
<div class="row-cards">
<div class="card card-success">
<h3><i class="fas fa-arrow-down"></i> Total Pemasukan</h3>
<div class="card-value"><?php echo e('Rp ' . number_format($totalPemasukan, 0, ',', '.')); ?></div>
<div class="card-icon"><i class="fas fa-arrow-down"></i></div>
</div>
<div class="card card-danger">
<h3><i class="fas fa-arrow-up"></i> Total Pengeluaran</h3>
<div class="card-value"><?php echo e('Rp ' . number_format($totalPengeluaran, 0, ',', '.')); ?></div>
<div class="card-icon"><i class="fas fa-arrow-up"></i></div>
</div>
<div class="card card-primary">
<h3><i class="fas fa-wallet"></i> Saldo Terakhir</h3>
<div class="card-value"><?php echo e('Rp ' . number_format($saldoTerakhir, 0, ',', '.')); ?></div>
<div class="card-icon"><i class="fas fa-wallet"></i></div>
</div>
</div>
<div class="content-box" style="margin-top: 14px;">
<form method="GET" action="<?php echo e(route('santri.uang-saku.index')); ?>" class="filter-form-inline">
<input type="text" name="search" class="form-control" placeholder="Cari keterangan..." value="<?php echo e(request('search')); ?>" style="min-width: 200px;">
<select name="jenis_transaksi" class="form-control" style="min-width: 150px;">
<option value="">Semua Jenis</option>
<option value="pemasukan" <?php echo e(request('jenis_transaksi') == 'pemasukan' ? 'selected' : ''); ?>>Pemasukan</option>
<option value="pengeluaran" <?php echo e(request('jenis_transaksi') == 'pengeluaran' ? 'selected' : ''); ?>>Pengeluaran</option>
</select>
<input type="date" name="tanggal_dari" class="form-control" value="<?php echo e(request('tanggal_dari')); ?>" placeholder="Dari Tanggal">
<input type="date" name="tanggal_sampai" class="form-control" value="<?php echo e(request('tanggal_sampai')); ?>" placeholder="Sampai Tanggal">
<button type="submit" class="btn btn-primary">
<i class="fas fa-filter"></i> Filter
</button>
<a href="<?php echo e(route('santri.uang-saku.index')); ?>" class="btn btn-secondary">
<i class="fas fa-redo"></i> Reset
</a>
</form>
</div>
<div class="table-container" style="margin-top: 14px;">
<?php if($riwayatUangSaku->count() > 0): ?>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>No</th>
<th>ID Transaksi</th>
<th>Tanggal</th>
<th>Jenis</th>
<th>Nominal</th>
<th>Keterangan</th>
<th>Saldo Sebelum</th>
<th>Saldo Sesudah</th>
<th class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $riwayatUangSaku; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $transaksi): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($riwayatUangSaku->firstItem() + $index); ?></td>
<td><strong><?php echo e($transaksi->id_uang_saku); ?></strong></td>
<td><?php echo e(\Carbon\Carbon::parse($transaksi->tanggal_transaksi)->format('d/m/Y')); ?></td>
<td>
<?php if($transaksi->jenis_transaksi === 'pemasukan'): ?>
<span class="badge badge-success">
<i class="fas fa-arrow-down"></i> Pemasukan
</span>
<?php else: ?>
<span class="badge badge-danger">
<i class="fas fa-arrow-up"></i> Pengeluaran
</span>
<?php endif; ?>
</td>
<td class="nominal-highlight"><?php echo e('Rp ' . number_format($transaksi->nominal, 0, ',', '.')); ?></td>
<td><?php echo e($transaksi->keterangan ?? '-'); ?></td>
<td><?php echo e('Rp ' . number_format($transaksi->saldo_sebelum, 0, ',', '.')); ?></td>
<td><?php echo e('Rp ' . number_format($transaksi->saldo_sesudah, 0, ',', '.')); ?></td>
<td class="text-center">
<a href="<?php echo e(route('santri.uang-saku.show', $transaksi->id)); ?>" class="btn btn-sm btn-primary" title="Lihat Detail">
<i class="fas fa-eye"></i> Detail
</a>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<div style="margin-top: 14px;">
<?php echo e($riwayatUangSaku->links()); ?>
</div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-inbox"></i>
<h3>Belum Ada Transaksi</h3>
<p>Riwayat uang saku Anda masih kosong.</p>
</div>
<?php endif; ?>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/santri/uang-saku/index.blade.php ENDPATH**/ ?>

View File

@ -1,136 +0,0 @@
<?php $__env->startSection('title', 'Detail Berita - ' . $berita->id_berita); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-newspaper"></i> Detail Berita</h2>
</div>
<!-- Header Actions -->
<div class="content-box" style="margin-bottom: 14px;">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px;">
<div>
<span class="badge <?php echo e($berita->status_badge); ?>" style="font-size: 1em; padding: 6px 11px;">
<?php if($berita->status === 'published'): ?>
<i class="fas fa-check-circle"></i> Published
<?php else: ?>
<i class="fas fa-edit"></i> Draft
<?php endif; ?>
</span>
</div>
<div style="display: flex; gap: 10px;">
<a href="<?php echo e(route('admin.berita.edit', $berita->id_berita)); ?>" class="btn btn-warning">
<i class="fas fa-edit"></i> Edit
</a>
<a href="<?php echo e(route('admin.berita.index')); ?>" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
</div>
</div>
<!-- Detail Berita -->
<div class="content-box">
<div style="padding: 10px;">
<!-- Header Berita -->
<div style="border-bottom: 3px solid var(--primary-color); padding-bottom: 25px; margin-bottom: 22px;">
<div style="margin-bottom: 15px;">
<span style="background: var(--primary-light); color: var(--primary-dark); padding: 6px 12px; border-radius: var(--border-radius-sm); font-weight: 600; font-size: 0.9em;">
ID: <?php echo e($berita->id_berita); ?>
</span>
</div>
<h1 style="color: var(--primary-dark); margin-bottom: 14px; font-size: 2em; line-height: 1.3;">
<?php echo e($berita->judul); ?>
</h1>
<div style="display: flex; flex-wrap: wrap; gap: 20px; align-items: center; color: var(--text-light); font-size: 0.95em;">
<span>
<i class="fas fa-user"></i>
<strong>Penulis:</strong> <?php echo e($berita->penulis); ?>
</span>
<span>
<i class="fas fa-calendar"></i>
<strong>Tanggal:</strong> <?php echo e($berita->created_at->format('d M Y, H:i')); ?> WIB
</span>
<span>
<?php
$badgeClass = match($berita->target_berita) {
'semua' => 'badge-primary',
'kelas_tertentu' => 'badge-info',
default => 'badge-secondary'
};
?>
<span class="badge <?php echo e($badgeClass); ?>">
<i class="fas fa-bullseye"></i> <?php echo e($berita->target_audience); ?>
</span>
</span>
</div>
</div>
<!-- Gambar Berita -->
<?php if($berita->gambar): ?>
<div style="text-align: center; margin: 40px 0;">
<img src="<?php echo e(asset('storage/' . $berita->gambar)); ?>"
alt="Gambar Berita"
style="max-width: 100%; max-height: 500px; border-radius: var(--border-radius); box-shadow: var(--shadow-lg); object-fit: cover;">
</div>
<?php endif; ?>
<!-- Konten Berita -->
<div class="detail-section">
<h4><i class="fas fa-align-left"></i> Konten Berita</h4>
<div style="line-height: 1.9; font-size: 1.05em; color: var(--text-color); background: var(--primary-light); padding: 18px; border-radius: var(--border-radius-sm); border-left: 4px solid var(--primary-color);">
<?php echo $berita->konten; ?>
</div>
</div>
<!-- Info Target Kelas -->
<?php if($berita->target_berita === 'kelas_tertentu'): ?>
<div class="detail-section">
<h4>
<i class="fas fa-graduation-cap"></i>
Target Kelas
</h4>
<div style="background: linear-gradient(135deg, #E3F2FD 0%, #D1E9F9 100%); padding: 14px; border-radius: var(--border-radius-sm); border-left: 4px solid var(--info-color);">
<p style="margin: 0; color: var(--text-color); font-size: 1em;">
<i class="fas fa-info-circle"></i>
Berita ini ditujukan untuk:
<strong><?php echo e($berita->target_audience); ?></strong>
</p>
</div>
</div>
<?php endif; ?>
<!-- Aksi -->
<div style="border-top: 2px solid var(--primary-light); padding-top: 30px; margin-top: 40px; text-align: center;">
<div style="display: flex; justify-content: center; gap: 10px; flex-wrap: wrap;">
<a href="<?php echo e(route('admin.berita.edit', $berita->id_berita)); ?>" class="btn btn-warning">
<i class="fas fa-edit"></i> Edit Berita
</a>
<form action="<?php echo e(route('admin.berita.destroy', $berita->id_berita)); ?>"
method="POST"
style="display: inline;"
onsubmit="return confirm('Yakin ingin menghapus berita ini? Tindakan ini tidak dapat dibatalkan!')">
<?php echo csrf_field(); ?>
<?php echo method_field('DELETE'); ?>
<button type="submit" class="btn btn-danger">
<i class="fas fa-trash"></i> Hapus Berita
</button>
</form>
<a href="<?php echo e(route('admin.berita.index')); ?>" class="btn btn-secondary">
<i class="fas fa-list"></i> Daftar Berita
</a>
</div>
</div>
</div>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/berita/show.blade.php ENDPATH**/ ?>

View File

@ -1,149 +0,0 @@
<?php $__env->startSection('title', $berita->judul); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-newspaper"></i> Berita & Pengumuman</h2>
</div>
<div class="content-box" style="padding: 0; overflow: hidden;">
<?php if($berita->gambar): ?>
<div style="width: 100%; max-height: 340px; overflow: hidden; position: relative;">
<img src="<?php echo e(asset('storage/' . $berita->gambar)); ?>"
alt="<?php echo e($berita->judul); ?>"
style="width: 100%; height: 340px; object-fit: cover; display: block;">
<div style="position: absolute; bottom: 0; left: 0; right: 0; height: 120px;
background: linear-gradient(to bottom, transparent, rgba(0,0,0,0.55));"></div>
</div>
<?php else: ?>
<div style="background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark, #1a4980) 100%);
height: 90px; position: relative; overflow: hidden;">
<div style="position: absolute; right: -20px; top: -20px; width: 120px; height: 120px;
background: rgba(255,255,255,0.07); border-radius: 50%;"></div>
<div style="position: absolute; right: 80px; bottom: -30px; width: 80px; height: 80px;
background: rgba(255,255,255,0.05); border-radius: 50%;"></div>
</div>
<?php endif; ?>
<div style="padding: 26px 28px;">
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; flex-wrap: wrap; gap: 10px;">
<div style="display: flex; align-items: center; gap: 8px;">
<a href="<?php echo e(route('santri.berita.index')); ?>"
style="color: var(--primary-color); text-decoration: none; font-size: 0.88em;">
<i class="fas fa-newspaper"></i> Berita
</a>
<i class="fas fa-chevron-right" style="color: var(--text-light); font-size: 0.7em;"></i>
<span style="color: var(--text-light); font-size: 0.88em;">Detail</span>
</div>
<a href="<?php echo e(route('santri.berita.index')); ?>" class="btn btn-secondary btn-sm">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
<div style="margin-bottom: 12px; display: flex; gap: 8px; flex-wrap: wrap; align-items: center;">
<span class="badge badge-primary" style="font-size: 0.82em;"><?php echo e($berita->id_berita); ?></span>
<span class="badge badge-success" style="font-size: 0.82em;">
<i class="fas fa-check-circle"></i> Published
</span>
</div>
<h2 style="margin: 0 0 14px; color: var(--text-color); font-size: 1.5em; line-height: 1.4;">
<?php echo e($berita->judul); ?>
</h2>
<div style="display: flex; gap: 18px; color: var(--text-light); font-size: 0.88em;
padding-bottom: 18px; border-bottom: 2px solid var(--primary-light); flex-wrap: wrap;">
<span><i class="fas fa-user" style="color: var(--primary-color);"></i> <?php echo e($berita->penulis); ?></span>
<span><i class="fas fa-calendar" style="color: var(--primary-color);"></i>
<?php echo e($berita->created_at->isoFormat('dddd, D MMMM YYYY')); ?>
</span>
<span><i class="fas fa-clock" style="color: var(--primary-color);"></i>
<?php echo e($berita->created_at->format('H:i')); ?> WIB
</span>
</div>
<div class="berita-body" style="margin-top: 22px; font-size: 1em; line-height: 1.85; color: var(--text-color);">
<?php echo $berita->konten; ?>
</div>
<div style="margin-top: 30px; padding-top: 18px; border-top: 1px solid #eee;
display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px;">
<p style="margin: 0; color: var(--text-light); font-size: 0.85em;">
<i class="fas fa-clock"></i>
Terakhir diperbarui: <?php echo e($berita->updated_at->isoFormat('D MMMM YYYY, HH:mm')); ?> WIB
</p>
<div style="display: flex; gap: 8px;">
<a href="<?php echo e(route('santri.berita.index')); ?>" class="btn btn-primary btn-sm">
<i class="fas fa-list"></i> Berita Lainnya
</a>
<a href="<?php echo e(route('santri.dashboard')); ?>" class="btn btn-secondary btn-sm">
<i class="fas fa-home"></i> Dashboard
</a>
</div>
</div>
</div>
</div>
<style>
.berita-body h1, .berita-body h2, .berita-body h3 {
color: var(--primary-color);
margin-top: 20px;
margin-bottom: 10px;
line-height: 1.4;
}
.berita-body h1 { font-size: 1.5em; border-bottom: 2px solid var(--primary-light); padding-bottom: 8px; }
.berita-body h2 { font-size: 1.25em; }
.berita-body h3 { font-size: 1.1em; }
.berita-body p { margin-bottom: 14px; }
.berita-body ul, .berita-body ol {
margin-left: 24px;
margin-bottom: 14px;
}
.berita-body li { margin-bottom: 6px; }
.berita-body strong { color: #2c3e50; font-weight: 600; }
.berita-body blockquote {
border-left: 4px solid var(--primary-color);
margin: 0 0 14px;
padding: 10px 16px;
background: var(--primary-light);
border-radius: 0 6px 6px 0;
color: var(--primary-dark, #1a4980);
}
.berita-body img {
max-width: 100%;
border-radius: var(--border-radius-sm);
margin: 10px 0;
}
.berita-body table {
width: 100%;
border-collapse: collapse;
margin-bottom: 16px;
font-size: 0.95em;
}
.berita-body table td, .berita-body table th {
border: 1px solid #dee2e6;
padding: 9px 12px;
}
.berita-body table th {
background: var(--primary-light);
color: var(--primary-color);
font-weight: 600;
}
</style>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/santri/berita/show.blade.php ENDPATH**/ ?>

View File

@ -1,207 +0,0 @@

<?php $__env->startSection('title', 'Kelola Kelas Santri'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-layer-group"></i> Kelola Kelas Santri</h2>
</div>
<!-- Flash Messages -->
<?php if(session('success')): ?>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="fas fa-exclamation-circle"></i> <?php echo e(session('error')); ?>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<?php endif; ?>
<!-- Quick Navigation Menu -->
<div class="content-box" style="margin-bottom: 14px; background: linear-gradient(135deg, #E8F7F2 0%, #D4F1E3 100%); border: 2px solid var(--primary-color);">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 11px;">
<div>
<h4 style="margin: 0; color: var(--primary-dark); display: flex; align-items: center; gap: 10px;">
<i class="fas fa-layer-group"></i>
Menu Manajemen Kelas
</h4>
<p style="margin: 5px 0 0 0; color: var(--text-light); font-size: 0.9rem;">
Kelola kelompok kelas, daftar kelas, dan kenaikan kelas tahunan
</p>
</div>
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
<a href="<?php echo e(route('admin.kelas.kelompok.index')); ?>" class="btn btn-info">
<i class="fas fa-folder"></i> Kelompok Kelas
</a>
<a href="<?php echo e(route('admin.kelas.kenaikan.index')); ?>" class="btn btn-success">
<i class="fas fa-graduation-cap"></i> Kenaikan Kelas
</a>
</div>
</div>
</div>
<!-- Header Actions -->
<div class="content-box" style="margin-bottom: 14px;">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 11px;">
<!-- Search & Filter Form -->
<form method="GET" action="<?php echo e(route('admin.kelas.index')); ?>" style="display: flex; gap: 10px; flex-wrap: wrap; flex-grow: 1;">
<input type="text"
name="search"
class="form-control"
placeholder="Cari nama atau kode kelas..."
value="<?php echo e(request('search')); ?>"
style="max-width: 300px;">
<select name="kelompok" class="form-control" style="max-width: 200px;">
<option value="">Semua Kelompok</option>
<?php $__currentLoopData = $kelompokKelas; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelompok): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($kelompok->id_kelompok); ?>"
<?php echo e(request('kelompok') == $kelompok->id_kelompok ? 'selected' : ''); ?>>
<?php echo e($kelompok->nama_kelompok); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
<select name="status" class="form-control" style="max-width: 150px;">
<option value="">Semua Status</option>
<option value="active" <?php echo e(request('status') == 'active' ? 'selected' : ''); ?>>Aktif</option>
<option value="inactive" <?php echo e(request('status') == 'inactive' ? 'selected' : ''); ?>>Tidak Aktif</option>
</select>
<button type="submit" class="btn btn-primary">
<i class="fas fa-search"></i> Filter
</button>
<a href="<?php echo e(route('admin.kelas.index')); ?>" class="btn btn-secondary">
<i class="fas fa-redo"></i> Reset
</a>
</form>
<!-- Action Button -->
<div>
<a href="<?php echo e(route('admin.kelas.create')); ?>" class="btn btn-success">
<i class="fas fa-plus"></i> Tambah Kelas Baru
</a>
</div>
</div>
</div>
<!-- Kelas List -->
<div class="content-box">
<?php if($kelas->count() > 0): ?>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">No</th>
<th>Kode Kelas</th>
<th>Nama Kelas</th>
<th>Kelompok</th>
<th style="width: 80px;">Urutan</th>
<th style="width: 100px;">Status</th>
<th style="width: 150px;">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $kelas; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($kelas->firstItem() + $index); ?></td>
<td><strong><?php echo e($item->kode_kelas); ?></strong></td>
<td><?php echo e($item->nama_kelas); ?></td>
<td>
<span class="badge badge-info">
<?php echo e($item->kelompok->nama_kelompok); ?>
</span>
</td>
<td class="text-center"><?php echo e($item->urutan); ?></td>
<td>
<?php if($item->is_active): ?>
<span class="badge badge-success">
<i class="fas fa-check-circle"></i> Aktif
</span>
<?php else: ?>
<span class="badge badge-secondary">
<i class="fas fa-times-circle"></i> Tidak Aktif
</span>
<?php endif; ?>
</td>
<td>
<div style="display: flex; gap: 5px;">
<a href="<?php echo e(route('admin.kelas.show', $item->id)); ?>"
class="btn btn-sm btn-info"
title="Lihat Detail">
<i class="fas fa-eye"></i>
</a>
<a href="<?php echo e(route('admin.kelas.edit', $item->id)); ?>"
class="btn btn-sm btn-warning"
title="Edit">
<i class="fas fa-edit"></i>
</a>
<form action="<?php echo e(route('admin.kelas.destroy', $item->id)); ?>"
method="POST"
style="display: inline;"
onsubmit="return confirm('Apakah Anda yakin ingin menghapus kelas <?php echo e($item->nama_kelas); ?>?')">
<?php echo csrf_field(); ?>
<?php echo method_field('DELETE'); ?>
<button type="submit"
class="btn btn-sm btn-danger"
title="Hapus">
<i class="fas fa-trash"></i>
</button>
</form>
</div>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<!-- Pagination -->
<?php if($kelas->hasPages()): ?>
<div style="margin-top: 14px;">
<?php echo e($kelas->links('vendor.pagination.custom')); ?>
</div>
<?php endif; ?>
<?php else: ?>
<!-- Empty State -->
<div class="text-center py-5">
<i class="fas fa-layer-group fa-3x text-muted mb-3"></i>
<h5 class="text-muted">Tidak ada data kelas</h5>
<p class="text-muted">
<?php if(request()->has('search') || request()->has('kelompok') || request()->has('status')): ?>
Tidak ada kelas yang sesuai dengan filter.
<?php else: ?>
Belum ada kelas yang ditambahkan.
<?php endif; ?>
</p>
<?php if(!request()->has('search') && !request()->has('kelompok') && !request()->has('status')): ?>
<a href="<?php echo e(route('admin.kelas.create')); ?>" class="btn btn-success mt-2">
<i class="fas fa-plus"></i> Tambah Kelas Baru
</a>
<?php else: ?>
<a href="<?php echo e(route('admin.kelas.index')); ?>" class="btn btn-secondary mt-2">
<i class="fas fa-redo"></i> Reset Filter
</a>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kelas/index.blade.php ENDPATH**/ ?>

View File

@ -1,479 +0,0 @@
<?php $__env->startSection('title', 'Tambah Izin Kepulangan'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-plus-circle"></i> Tambah Izin Kepulangan</h2>
</div>
<div style="background: #E8F7F2; padding: 15px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #6FBA9D;">
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 11px;">
<div>
<strong> Periode Kuota:</strong><br>
<?php echo e($settings->periode_mulai->format('d M Y')); ?> - <?php echo e($settings->periode_akhir->format('d M Y')); ?>
</div>
<div>
<strong> Kuota Maksimal:</strong><br>
<?php echo e($settings->kuota_maksimal); ?> Hari / Tahun
</div>
</div>
</div>
<?php if($errors->any()): ?>
<div class="alert alert-danger">
<ul style="margin: 0; padding-left: 20px;">
<?php $__currentLoopData = $errors->all(); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $error): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<li><?php echo e($error); ?></li>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</ul>
</div>
<?php endif; ?>
<div class="content-box">
<form action="<?php echo e(route('admin.kepulangan.store')); ?>" method="POST" id="kepulanganForm">
<?php echo csrf_field(); ?>
<div class="form-group">
<label for="id_santri">
<i class="fas fa-user form-icon"></i>
Pilih Santri <span style="color: #dc3545;">*</span>
</label>
<select name="id_santri" id="id_santri" class="form-control" required>
<option value="">-- Pilih Santri --</option>
<?php $__currentLoopData = $santriList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $santri): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($santri->id_santri); ?>" <?php echo e(old('id_santri') == $santri->id_santri ? 'selected' : ''); ?>>
<?php echo e($santri->nama_lengkap); ?> (<?php echo e($santri->id_santri); ?> - <?php echo e($santri->kelas); ?>)
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div id="santriInfo" style="display: none; background: #f8f9fa; padding: 14px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #6FBA9D;">
<h4 style="margin-top: 0; color: #2C3E50;"> Informasi Santri & Kuota</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px;">
<div>
<p style="margin: 5px 0;"><strong>Nama:</strong> <span id="santriNama">-</span></p>
<p style="margin: 5px 0;"><strong>Kelas:</strong> <span id="santriKelas">-</span></p>
<p style="margin: 5px 0;"><strong>Periode:</strong> <span id="santriPeriode">-</span></p>
</div>
<div>
<p style="margin: 5px 0;"><strong>Kuota Maksimal:</strong> <span id="kuotaMaksimal">-</span></p>
<p style="margin: 5px 0;"><strong>Total Terpakai:</strong> <span id="totalTerpakai" class="badge">-</span></p>
<p style="margin: 5px 0;"><strong>Sisa Kuota:</strong> <span id="sisaKuota" class="badge">-</span></p>
</div>
</div>
<div style="margin-top: 15px;">
<label style="font-size: 0.9rem; color: #7F8C8D; margin-bottom: 5px;">Penggunaan Kuota:</label>
<div style="width: 100%; height: 20px; background: #E0F0EC; border-radius: 10px; overflow: hidden; position: relative;">
<div id="progressBar" style="height: 100%; width: 0%; background: #28a745; transition: all 0.3s ease; display: flex; align-items: center; justify-content: center; color: white; font-size: 0.75rem; font-weight: 600;"></div>
</div>
<small id="progressText" style="color: #7F8C8D; margin-top: 5px; display: block;">0% dari kuota terpakai</small>
</div>
<div id="warningOverLimit" style="display: none; margin-top: 15px; padding: 12px; background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; color: #856404;">
<i class="fas fa-exclamation-triangle"></i>
<strong>⚠️ PERHATIAN:</strong> <span id="warningText"></span>
</div>
</div>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 14px;">
<div class="form-group">
<label for="tanggal_pulang">
<i class="fas fa-calendar-alt form-icon"></i>
Tanggal Pulang <span style="color: #dc3545;">*</span>
</label>
<input type="date"
name="tanggal_pulang"
id="tanggal_pulang"
class="form-control"
value="<?php echo e(old('tanggal_pulang', date('Y-m-d'))); ?>"
min="<?php echo e(date('Y-m-d')); ?>"
required>
</div>
<div class="form-group">
<label for="tanggal_kembali">
<i class="fas fa-calendar-check form-icon"></i>
Tanggal Kembali <span style="color: #dc3545;">*</span>
</label>
<input type="date"
name="tanggal_kembali"
id="tanggal_kembali"
class="form-control"
value="<?php echo e(old('tanggal_kembali')); ?>"
required>
</div>
</div>
<div id="durasiInfo" style="display: none; background: #fff3e0; padding: 14px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #ff9800;">
<h4 style="margin-top: 0; color: #2C3E50;">⏱️ Detail Durasi Izin</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 11px;">
<div style="text-align: center; padding: 15px; background: white; border-radius: 8px;">
<div style="font-size: 0.85rem; color: #7F8C8D; margin-bottom: 5px;">Durasi Izin</div>
<div id="durasiHari" style="font-size: 2rem; font-weight: 700; color: #ff9800;">0</div>
<div style="font-size: 0.8rem; color: #7F8C8D;">hari</div>
</div>
<div style="text-align: center; padding: 15px; background: white; border-radius: 8px;">
<div style="font-size: 0.85rem; color: #7F8C8D; margin-bottom: 5px;">Total Setelah Izin</div>
<div id="totalSetelahIzin" style="font-size: 2rem; font-weight: 700; color: #2196f3;">0</div>
<div style="font-size: 0.8rem; color: #7F8C8D;">hari terpakai</div>
</div>
<div style="text-align: center; padding: 15px; background: white; border-radius: 8px;">
<div style="font-size: 0.85rem; color: #7F8C8D; margin-bottom: 5px;">Sisa Kuota</div>
<div id="sisaKuotaSetelah" style="font-size: 2rem; font-weight: 700; color: #28a745;"><?php echo e($settings->kuota_maksimal); ?></div>
<div style="font-size: 0.8rem; color: #7F8C8D;">hari tersisa</div>
</div>
</div>
<div id="warningDurasi" style="display: none; margin-top: 15px; padding: 12px; background: #ffebee; border: 1px solid #ffcdd2; border-radius: 6px; color: #c62828;">
<i class="fas fa-exclamation-circle"></i>
<strong>⚠️ PERHATIAN:</strong> <span id="warningDurasiMessage"></span>
</div>
</div>
<div class="form-group">
<label for="alasan">
<i class="fas fa-comment-alt form-icon"></i>
Alasan Kepulangan <span style="color: #dc3545;">*</span>
</label>
<textarea name="alasan"
id="alasan"
class="form-control"
rows="4"
placeholder="Jelaskan alasan kepulangan"
required><?php echo e(old('alasan')); ?></textarea>
<small style="color: #7F8C8D; margin-top: 5px; display: block;">
<span id="charCount">0</span>/500 karakter
</small>
</div>
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
<button type="submit" class="btn btn-primary" id="submitBtn">
<i class="fas fa-save"></i> Simpan Izin Kepulangan
</button>
<button type="reset" class="btn btn-secondary">
<i class="fas fa-undo"></i> Reset Form
</button>
<a href="<?php echo e(route('admin.kepulangan.index')); ?>" class="btn btn-danger">
<i class="fas fa-times"></i> Batal
</a>
</div>
</form>
</div>
<div class="modal fade" id="overLimitModal" tabindex="-1" style="display: none;">
<div class="modal-dialog">
<div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;">
<div style="margin-bottom: 14px;">
<h3 style="margin: 0; color: #2C3E50;">⚠️ Konfirmasi Izin Melebihi Batas</h3>
</div>
<div style="padding: 15px; background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; margin-bottom: 15px;">
<i class="fas fa-exclamation-triangle" style="font-size: 2rem; color: #856404; margin-bottom: 10px;"></i>
<h4 style="margin: 10px 0; color: #856404;">Peringatan!</h4>
<p id="overLimitMessage" style="margin: 0; color: #856404;"></p>
</div>
<p style="margin: 15px 0;">Izin tetap bisa diproses, tetapi santri ini akan <strong>melebihi kuota maksimal</strong>.</p>
<p style="margin: 15px 0; color: #7F8C8D; font-size: 0.9rem;">Apakah Anda yakin ingin melanjutkan pengajuan izin ini?</p>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;">
<button type="button" class="btn btn-secondary" onclick="closeModal('overLimitModal')">Batal</button>
<button type="button" class="btn btn-warning" id="confirmOverLimit" style="background: #ff9800; border-color: #ff9800;">
<i class="fas fa-check"></i> Ya, Lanjutkan Tetap
</button>
</div>
</div>
</div>
</div>
<style>
.modal.fade { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center; }
.modal-dialog { max-width: 500px; width: 90%; margin: auto; }
.modal-content { max-height: 90vh; overflow-y: auto; }
.badge { display: inline-block; padding: 4px 10px; border-radius: 4px; font-size: 0.9rem; font-weight: 600; }
</style>
<script>
let currentSantriData = null;
let isOverLimit = false;
// Load santri data when selected
document.getElementById('id_santri').addEventListener('change', function() {
const santriId = this.value;
if (!santriId) {
document.getElementById('santriInfo').style.display = 'none';
currentSantriData = null;
calculateDurasi();
return;
}
const infoDiv = document.getElementById('santriInfo');
infoDiv.style.display = 'block';
// Show loading state
infoDiv.innerHTML = '<div style="text-align: center; padding: 14px;"><i class="fas fa-spinner fa-spin"></i> Memuat data santri...</div>';
// PERBAIKAN: Proper error handling untuk API
fetch(`/admin/kepulangan/api/santri/${santriId}`)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
if (data.success) {
currentSantriData = data;
updateSantriInfo(data);
calculateDurasi();
} else {
showError(data.message || 'Gagal memuat data santri');
}
})
.catch(error => {
console.error('Error:', error);
showError('Terjadi kesalahan saat memuat data santri: ' + error.message);
});
});
// PERBAIKAN: Function untuk show error
function showError(message) {
const infoDiv = document.getElementById('santriInfo');
infoDiv.innerHTML = `
<div style="padding: 15px; background: #ffebee; border: 1px solid #ffcdd2; border-radius: 6px; color: #c62828;">
<i class="fas fa-exclamation-circle"></i>
<strong>Error:</strong> ${message}
</div>
`;
currentSantriData = null;
}
function updateSantriInfo(data) {
const santri = data.santri;
const kuota = data.penggunaan_izin;
// Rebuild HTML structure
const infoDiv = document.getElementById('santriInfo');
infoDiv.innerHTML = `
<h4 style="margin-top: 0; color: #2C3E50;"> Informasi Santri & Kuota</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px;">
<div>
<p style="margin: 5px 0;"><strong>Nama:</strong> <span id="santriNama">${santri.nama_lengkap}</span></p>
<p style="margin: 5px 0;"><strong>Kelas:</strong> <span id="santriKelas">${santri.kelas}</span></p>
<p style="margin: 5px 0;"><strong>Periode:</strong> <span id="santriPeriode">${kuota.periode_mulai} - ${kuota.periode_akhir}</span></p>
</div>
<div>
<p style="margin: 5px 0;"><strong>Kuota Maksimal:</strong> <span id="kuotaMaksimal">${kuota.kuota_maksimal} hari</span></p>
<p style="margin: 5px 0;"><strong>Total Terpakai:</strong> <span id="totalTerpakai" class="badge" style="background: ${getBadgeColor(kuota.badge_color)}; color: ${kuota.badge_color === 'warning' ? '#000' : 'white'};">${kuota.total_terpakai} hari</span></p>
<p style="margin: 5px 0;"><strong>Sisa Kuota:</strong> <span id="sisaKuota" class="badge" style="background: ${getBadgeColor(kuota.badge_color)}; color: ${kuota.badge_color === 'warning' ? '#000' : 'white'};">${kuota.sisa_kuota} hari</span></p>
</div>
</div>
<div style="margin-top: 15px;">
<label style="font-size: 0.9rem; color: #7F8C8D; margin-bottom: 5px;">Penggunaan Kuota:</label>
<div style="width: 100%; height: 20px; background: #E0F0EC; border-radius: 10px; overflow: hidden; position: relative;">
<div id="progressBar" style="height: 100%; width: ${Math.min(100, kuota.persentase)}%; background: ${getProgressColor(kuota.persentase)}; transition: all 0.3s ease; display: flex; align-items: center; justify-content: center; color: white; font-size: 0.75rem; font-weight: 600;">${kuota.persentase}%</div>
</div>
<small id="progressText" style="color: #7F8C8D; margin-top: 5px; display: block;">${kuota.persentase}% dari kuota terpakai</small>
</div>
<div id="warningOverLimit" style="display: ${kuota.status === 'melebihi' ? 'block' : 'none'}; margin-top: 15px; padding: 12px; background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; color: #856404;">
<i class="fas fa-exclamation-triangle"></i>
<strong>⚠️ PERHATIAN:</strong> <span id="warningText">Santri ini sudah melebihi kuota ${kuota.kuota_maksimal} hari per tahun! Total terpakai: ${kuota.total_terpakai} hari.</span>
</div>
`;
}
function getBadgeColor(badge) {
const colors = {
'success': '#28a745',
'warning': '#ffc107',
'danger': '#dc3545'
};
return colors[badge] || '#6c757d';
}
function getProgressColor(persentase) {
if (persentase >= 100) return '#dc3545';
if (persentase >= 80) return '#ffc107';
return '#28a745';
}
// Calculate durasi when dates change
document.getElementById('tanggal_pulang').addEventListener('change', calculateDurasi);
document.getElementById('tanggal_kembali').addEventListener('change', calculateDurasi);
function calculateDurasi() {
const tanggalPulang = document.getElementById('tanggal_pulang').value;
const tanggalKembali = document.getElementById('tanggal_kembali').value;
const durasiInfoDiv = document.getElementById('durasiInfo');
if (!tanggalPulang || !tanggalKembali) {
durasiInfoDiv.style.display = 'none';
return;
}
const startDate = new Date(tanggalPulang);
const endDate = new Date(tanggalKembali);
if (endDate <= startDate) {
durasiInfoDiv.style.display = 'none';
return;
}
// Hitung durasi (termasuk hari pertama)
const diffTime = Math.abs(endDate - startDate);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1;
durasiInfoDiv.style.display = 'block';
// Update durasi
document.getElementById('durasiHari').textContent = diffDays;
let totalSetelah = diffDays;
let sisaSetelah = <?php echo e($settings->kuota_maksimal); ?> - diffDays;
let showWarning = false;
let warningMessage = '';
if (currentSantriData) {
const currentUsage = currentSantriData.penggunaan_izin.total_terpakai;
const kuotaMaks = currentSantriData.penggunaan_izin.kuota_maksimal;
totalSetelah = currentUsage + diffDays;
sisaSetelah = kuotaMaks - totalSetelah;
// Update nilai
document.getElementById('totalSetelahIzin').textContent = totalSetelah;
document.getElementById('sisaKuotaSetelah').textContent = Math.max(0, sisaSetelah);
// Ubah warna berdasarkan status
const totalSetelahEl = document.getElementById('totalSetelahIzin');
const sisaSetelahEl = document.getElementById('sisaKuotaSetelah');
if (totalSetelah > kuotaMaks) {
totalSetelahEl.style.color = '#dc3545';
sisaSetelahEl.style.color = '#dc3545';
showWarning = true;
warningMessage = `Izin ini akan melebihi batas ${kuotaMaks} hari per tahun (Total setelah izin: ${totalSetelah} hari, Kelebihan: ${totalSetelah - kuotaMaks} hari)`;
isOverLimit = true;
} else if (totalSetelah >= kuotaMaks * 0.8) {
totalSetelahEl.style.color = '#ff9800';
sisaSetelahEl.style.color = '#ff9800';
showWarning = true;
warningMessage = `Perhatian: Kuota hampir habis! Sisa kuota setelah izin ini hanya ${sisaSetelah} hari.`;
isOverLimit = false;
} else {
totalSetelahEl.style.color = '#2196f3';
sisaSetelahEl.style.color = '#28a745';
showWarning = false;
isOverLimit = false;
}
}
// Tampilkan warning durasi
const warningDiv = document.getElementById('warningDurasi');
const warningMessageEl = document.getElementById('warningDurasiMessage');
if (showWarning) {
warningDiv.style.display = 'block';
warningMessageEl.textContent = warningMessage;
} else {
warningDiv.style.display = 'none';
}
}
// Character counter (PERBAIKAN: Tidak ada validasi minimal)
document.getElementById('alasan').addEventListener('input', function() {
const current = this.value.length;
const counter = document.getElementById('charCount');
counter.textContent = current;
if (current > 500) {
counter.style.color = 'red';
} else {
counter.style.color = '#7F8C8D';
}
});
// Form submission with over limit confirmation
document.getElementById('kepulanganForm').addEventListener('submit', function(e) {
if (isOverLimit) {
e.preventDefault();
const warningMessageEl = document.getElementById('warningDurasiMessage');
const message = warningMessageEl ? warningMessageEl.textContent : 'Izin ini akan melebihi batas kuota per tahun';
document.getElementById('overLimitMessage').textContent = message;
document.getElementById('overLimitModal').style.display = 'flex';
}
});
// Confirm over limit submission
document.getElementById('confirmOverLimit').addEventListener('click', function() {
closeModal('overLimitModal');
isOverLimit = false;
document.getElementById('kepulanganForm').submit();
});
// Auto-set minimum tanggal_kembali
document.getElementById('tanggal_pulang').addEventListener('change', function() {
const pulangDate = new Date(this.value);
pulangDate.setDate(pulangDate.getDate() + 1);
const minKembaliDate = pulangDate.toISOString().split('T')[0];
document.getElementById('tanggal_kembali').min = minKembaliDate;
const currentKembali = document.getElementById('tanggal_kembali').value;
if (currentKembali && currentKembali <= this.value) {
document.getElementById('tanggal_kembali').value = minKembaliDate;
}
});
// Initialize
document.addEventListener('DOMContentLoaded', function() {
const today = new Date().toISOString().split('T')[0];
document.getElementById('tanggal_pulang').min = today;
const alasanField = document.getElementById('alasan');
document.getElementById('charCount').textContent = alasanField.value.length;
calculateDurasi();
});
// Form reset handler
document.querySelector('button[type="reset"]').addEventListener('click', function() {
setTimeout(() => {
document.getElementById('santriInfo').style.display = 'none';
document.getElementById('durasiInfo').style.display = 'none';
currentSantriData = null;
isOverLimit = false;
document.getElementById('charCount').textContent = '0';
}, 100);
});
// Helper functions
function closeModal(modalId) {
document.getElementById(modalId).style.display = 'none';
}
// Close modal on ESC
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
document.querySelectorAll('.modal.fade').forEach(modal => modal.style.display = 'none');
}
});
// Close modal on outside click
document.querySelectorAll('.modal.fade').forEach(modal => {
modal.addEventListener('click', function(e) {
if (e.target === this) {
this.style.display = 'none';
}
});
});
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kepulangan/create.blade.php ENDPATH**/ ?>

View File

@ -1,5 +0,0 @@
<?php $__env->startSection('title', __('Page Expired')); ?>
<?php $__env->startSection('code', '419'); ?>
<?php $__env->startSection('message', __('Page Expired')); ?>
<?php echo $__env->make('errors::minimal', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\vendor\laravel\framework\src\Illuminate\Foundation\Exceptions/views/419.blade.php ENDPATH**/ ?>

View File

@ -0,0 +1,164 @@
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bukti Pembayaran SPP - <?php echo e($pembayaranSpp->id_pembayaran); ?></title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: Arial, sans-serif; padding: 30px; font-size: 13px; }
.bukti-container { max-width: 600px; margin: 0 auto; border: 3px solid #6FBA9D; border-radius: 10px; padding: 25px; }
/* ── KOP SURAT ─────────────────────────────────── */
.kop { display: flex; align-items: center; gap: 16px; padding-bottom: 12px; border-bottom: 3px double #6FBA9D; margin-bottom: 8px; }
.kop img { width: 72px; height: 72px; object-fit: contain; flex-shrink: 0; }
.kop-text { flex: 1; text-align: center; }
.kop-text .nama-lembaga { font-size: 17px; font-weight: bold; color: #1a1a1a; letter-spacing: .4px; text-transform: uppercase; }
.kop-text .nama-singkat { font-size: 13px; color: #555; margin: 2px 0; }
.kop-text .alamat { font-size: 10.5px; color: #555; line-height: 16px; margin-top: 4px; }
/* ── JUDUL DOKUMEN ─────────────────────────────── */
.header { text-align: center; margin: 14px 0 20px; }
.header h2 { font-size: 15px; color: #6FBA9D; letter-spacing: 2px; text-transform: uppercase; }
.header p { font-size: 12px; color: #666; margin-top: 4px; }
.bukti-info { background: #f9f9f9; padding: 20px; border-radius: 8px; margin-bottom: 20px; }
.bukti-info table { width: 100%; }
.bukti-info tr { line-height: 28px; }
.bukti-info td:first-child { font-weight: bold; width: 160px; color: #555; }
.bukti-info td:nth-child(2) { width: 20px; }
.bukti-info td:last-child { color: #333; }
.nominal-box { background: linear-gradient(135deg, #6FBA9D 0%, #8FCAAE 100%); color: white; padding: 20px; border-radius: 8px; text-align: center; margin: 25px 0; }
.nominal-box h3 { font-size: 14px; margin-bottom: 10px; opacity: .9; }
.nominal-box .amount { font-size: 32px; font-weight: bold; letter-spacing: 1px; }
.status-box { text-align: center; padding: 15px; border-radius: 8px; margin-bottom: 20px; }
.status-lunas { background: #d4edda; color: #155724; border: 2px solid #c3e6cb; }
.status-belum { background: #fff3cd; color: #856404; border: 2px solid #ffeaa7; }
.footer { text-align: center; margin-top: 30px; padding-top: 20px; border-top: 2px dashed #ddd; }
.footer p { font-size: 11px; color: #888; line-height: 18px; }
.ttd-section { margin-top: 40px; display: flex; justify-content: flex-end; }
.ttd-box { text-align: center; width: 45%; }
.ttd-box p { margin-bottom: 60px; font-size: 12px; }
.ttd-box strong { font-size: 13px; border-top: 1px solid #333; padding-top: 5px; display: inline-block; }
@media print {
body { padding: 0; }
.no-print { display: none; }
@page { margin: 1.5cm; }
}
</style>
</head>
<body>
<!-- Tombol Print -->
<div class="no-print" style="text-align:center; margin-bottom:20px;">
<button onclick="window.print()" style="padding:12px 30px; background:#6FBA9D; color:white; border:none; border-radius:5px; cursor:pointer; font-size:14px;">
Cetak Bukti
</button>
</div>
<div class="bukti-container">
<!-- ══ KOP SURAT ══ -->
<div class="kop">
<img src="<?php echo e(asset('images/logo.png')); ?>" alt="Logo PKPPS Riyadlul Jannah">
<div class="kop-text">
<div class="nama-lembaga">PKPPS Riyadlul Jannah Mojokerto</div>
<div class="alamat">
Jl. Raya Brangkal No. 42 RT. 02 RW. 01, Desa Brangkal<br>
Kec. Sooko, Kab. Mojokerto, Prov. Jawa Timur
</div>
</div>
</div>
<!-- ══ JUDUL DOKUMEN ══ -->
<div class="header">
<h2>Bukti Pembayaran SPP</h2>
<p>No. Bukti: <strong><?php echo e($pembayaranSpp->id_pembayaran); ?></strong></p>
</div>
<!-- Status -->
<?php if($pembayaranSpp->status === 'Lunas'): ?>
<div class="status-box status-lunas">
<strong style="font-size:16px;">&#10003; LUNAS</strong>
</div>
<?php else: ?>
<div class="status-box status-belum">
<strong style="font-size:16px;">&#9888; BELUM LUNAS</strong>
</div>
<?php endif; ?>
<!-- Info Santri & Pembayaran -->
<div class="bukti-info">
<table>
<tr>
<td>ID Santri</td>
<td>:</td>
<td><?php echo e($pembayaranSpp->santri->id_santri); ?></td>
</tr>
<tr>
<td>Nama Santri</td>
<td>:</td>
<td><strong><?php echo e($pembayaranSpp->santri->nama_lengkap); ?></strong></td>
</tr>
<tr>
<td>Periode Pembayaran</td>
<td>:</td>
<td><strong><?php echo e($pembayaranSpp->periode_lengkap); ?></strong></td>
</tr>
<tr>
<td>Tanggal Bayar</td>
<td>:</td>
<td>
<?php if($pembayaranSpp->tanggal_bayar): ?>
<?php echo e($pembayaranSpp->tanggal_bayar->format('d F Y')); ?>
<?php else: ?>
<span style="color:#999;">Belum dibayar</span>
<?php endif; ?>
</td>
</tr>
<?php if($pembayaranSpp->keterangan): ?>
<tr>
<td>Keterangan</td>
<td>:</td>
<td><?php echo e($pembayaranSpp->keterangan); ?></td>
</tr>
<?php endif; ?>
</table>
</div>
<!-- Nominal -->
<div class="nominal-box">
<h3>JUMLAH PEMBAYARAN</h3>
<div class="amount"><?php echo e($pembayaranSpp->nominal_format); ?></div>
</div>
<!-- Tanda Tangan -->
<div class="ttd-section">
<div class="ttd-box">
<p>Petugas</p>
<strong>(&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)</strong>
</div>
</div>
<!-- Footer -->
<div class="footer">
<p>
<strong>PERHATIAN:</strong><br>
Bukti pembayaran ini sah dan merupakan tanda terima yang diakui secara resmi.<br>
Simpan bukti ini sebagai arsip pembayaran SPP.<br>
Dicetak pada: <?php echo e(date('d F Y, H:i')); ?> WIB
</p>
</div>
</div>
</body>
</html><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/pembayaran-spp/cetak-bukti.blade.php ENDPATH**/ ?>

View File

@ -1,153 +0,0 @@
<?php $__env->startSection('title', $admin ? 'Edit Akun Admin' : 'Tambah Akun Admin'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2>
<i class="fas fa-user-shield"></i>
<?php echo e($admin ? 'Edit Akun Admin: ' . $admin->name : 'Tambah Akun Admin'); ?>
</h2>
</div>
<div class="content-box" style="max-width: 540px;">
<?php if($errors->any()): ?>
<div class="alert alert-danger">
<ul style="margin:0;padding-left:18px;">
<?php $__currentLoopData = $errors->all(); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $error): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<li><?php echo e($error); ?></li>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</ul>
</div>
<?php endif; ?>
<form action="<?php echo e($action); ?>" method="POST" class="data-form">
<?php echo csrf_field(); ?>
<?php if($method === 'PUT'): ?>
<?php echo method_field('PUT'); ?>
<?php endif; ?>
<div class="form-group">
<label for="name">Nama Lengkap *</label>
<input type="text" id="name" name="name"
value="<?php echo e(old('name', $admin->name ?? '')); ?>"
class="form-control <?php $__errorArgs = ['name'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?> is-invalid <?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>"
required>
<?php $__errorArgs = ['name'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?><div class="invalid-feedback"><?php echo e($message); ?></div><?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>
</div>
<div class="form-group">
<label for="email">Email (digunakan untuk login) *</label>
<input type="email" id="email" name="email"
value="<?php echo e(old('email', $admin->email ?? '')); ?>"
class="form-control <?php $__errorArgs = ['email'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?> is-invalid <?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>"
required>
<?php $__errorArgs = ['email'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?><div class="invalid-feedback"><?php echo e($message); ?></div><?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>
</div>
<div class="form-group">
<label for="role">Role *</label>
<select id="role" name="role"
class="form-control <?php $__errorArgs = ['role'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?> is-invalid <?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>"
required>
<option value="">-- Pilih Role --</option>
<option value="akademik" <?php echo e(old('role', $admin->role ?? '') === 'akademik' ? 'selected' : ''); ?>>
Akademik (Data santri, kegiatan, pelanggaran, absensi, rekap)
</option>
<option value="pamong" <?php echo e(old('role', $admin->role ?? '') === 'pamong' ? 'selected' : ''); ?>>
Pamong (Uang saku, absensi RFID, capaian, kesehatan, kepulangan)
</option>
</select>
<?php $__errorArgs = ['role'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?><div class="invalid-feedback"><?php echo e($message); ?></div><?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>
</div>
<div class="form-group">
<label for="password">
Password <?php echo e($admin ? '(kosongkan jika tidak ingin mengganti)' : '*'); ?>
</label>
<input type="password" id="password" name="password"
class="form-control <?php $__errorArgs = ['password'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?> is-invalid <?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>"
<?php echo e($admin ? '' : 'required'); ?>>
<?php $__errorArgs = ['password'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?><div class="invalid-feedback"><?php echo e($message); ?></div><?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>
<small class="form-text text-muted">Minimal 8 karakter.</small>
</div>
<div class="form-group">
<label for="password_confirmation">Konfirmasi Password <?php echo e($admin ? '' : '*'); ?></label>
<input type="password" id="password_confirmation" name="password_confirmation"
class="form-control"
<?php echo e($admin ? '' : 'required'); ?>>
</div>
<div style="display:flex;gap:10px;margin-top:16px;">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i> <?php echo e($admin ? 'Simpan Perubahan' : 'Buat Akun'); ?>
</button>
<a href="<?php echo e(route('admin.users.admin_accounts')); ?>" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
</form>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', ['isAdmin' => true], \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/users/admin_form.blade.php ENDPATH**/ ?>

View File

@ -1,241 +0,0 @@

<?php $__env->startSection('title', 'Mapping ID Fingerprint'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header" style="display:flex;align-items:center;justify-content:space-between">
<h2><i class="fas fa-link"></i> Mapping ID Fingerprint</h2>
<a href="<?php echo e(route('admin.kegiatan.index')); ?>" class="btn btn-sm btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success"><i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?></div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger"><i class="fas fa-times-circle"></i> <?php echo e(session('error')); ?></div>
<?php endif; ?>
<div class="content-box" style="margin-bottom:14px">
<h4 style="margin:0 0 6px;font-size:15px">
<i class="fas fa-magic" style="color:#166534"></i> Auto-Import dari INFO.XLS
</h4>
<p style="margin:0 0 12px;color:#6B7280;font-size:13px">
Upload INFO.XLS dari mesin Eppos sistem otomatis cocokkan nama dan buat mapping.
Nama yang tidak cocok otomatis ke dropdown untuk dipilih manual.
</p>
<form action="<?php echo e(route('admin.mesin.mapping-santri.import-info')); ?>"
method="POST" enctype="multipart/form-data"
style="display:flex;gap:10px;align-items:center;flex-wrap:wrap">
<?php echo csrf_field(); ?>
<input type="file" name="file_info" accept=".xls,.xlsx" required
class="form-control" style="max-width:320px">
<button type="submit" class="btn btn-success">
<i class="fas fa-magic"></i> Auto-Import
</button>
</form>
</div>
<?php
$total = $mappings->count();
$terpetakan = $mappings->filter(fn($m) => !empty($m->id_santri))->count();
$belum = $total - $terpetakan;
?>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-bottom:14px">
<div style="background:#F9FAFB;border:1px solid #E5E7EB;border-radius:10px;padding:14px;text-align:center">
<div style="font-size:28px;font-weight:700;color:#1F2937"><?php echo e($total); ?></div>
<div style="font-size:12px;color:#6B7280">Total ID Mesin</div>
</div>
<div style="background:#DCFCE7;border:1px solid #BBF7D0;border-radius:10px;padding:14px;text-align:center">
<div style="font-size:28px;font-weight:700;color:#166534"><?php echo e($terpetakan); ?></div>
<div style="font-size:12px;color:#166534">Terpetakan</div>
</div>
<div style="background:<?php echo e($belum > 0 ? '#FEE2E2' : '#DCFCE7'); ?>;border:1px solid <?php echo e($belum > 0 ? '#FECACA' : '#BBF7D0'); ?>;border-radius:10px;padding:14px;text-align:center">
<div style="font-size:28px;font-weight:700;color:<?php echo e($belum > 0 ? '#991B1B' : '#166534'); ?>"><?php echo e($belum); ?></div>
<div style="font-size:12px;color:<?php echo e($belum > 0 ? '#991B1B' : '#166534'); ?>">
<?php echo e($belum > 0 ? 'Belum Dipetakan' : 'Semua Terpetakan'); ?>
</div>
</div>
</div>
<?php if($belum > 0): ?>
<div style="background:#FEF9C3;border:1px solid #FDE68A;border-left:4px solid #F59E0B;
border-radius:8px;padding:12px 16px;margin-bottom:14px;font-size:13px">
<strong>âš  <?php echo e($belum); ?> ID mesin belum dipetakan ke santri.</strong>
Data scan santri tersebut tidak akan tersimpan saat import absensi.
Pilih santri yang sesuai dari dropdown di bawah.
</div>
<?php endif; ?>
<div class="content-box" style="padding:0;overflow:hidden;margin-bottom:14px">
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width:70px;text-align:center">ID Mesin</th>
<th>Nama di Mesin</th>
<th style="width:90px">Dept/Kel</th>
<th>Santri Web yang Dipetakan</th>
<th style="width:110px;text-align:center">Status</th>
<th style="width:70px;text-align:center">Hapus</th>
</tr>
</thead>
<tbody>
<?php $__empty_1 = true; $__currentLoopData = $mappings; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $m): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
<tr style="background:<?php echo e(empty($m->id_santri) ? '#FFFBEB' : 'white'); ?>">
<td style="text-align:center">
<strong style="font-family:monospace;font-size:15px;color:#1D4ED8">
<?php echo e($m->id_mesin); ?>
</strong>
</td>
<td>
<div style="font-weight:600;color:#1F2937"><?php echo e($m->nama_mesin ?? '-'); ?></div>
<?php if($m->catatan): ?>
<div style="font-size:11px;color:#9CA3AF"><?php echo e($m->catatan); ?></div>
<?php endif; ?>
</td>
<td style="color:#6B7280;font-size:12px"><?php echo e($m->dept_mesin ?? '-'); ?></td>
<td>
<form action="<?php echo e(route('admin.mesin.mapping-santri.update', $m->id)); ?>"
method="POST" style="margin:0">
<?php echo csrf_field(); ?> <?php echo method_field('PUT'); ?>
<div style="display:flex;align-items:center;gap:8px">
<select name="id_santri"
class="form-control"
style="font-size:13px;
border-color:<?php echo e(empty($m->id_santri) ? '#FCA5A5' : '#D1D5DB'); ?>;
background:<?php echo e(empty($m->id_santri) ? '#FFF5F5' : 'white'); ?>"
onchange="this.form.submit()">
<option value="">-- Pilih Santri --</option>
<?php $__currentLoopData = $santris; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $s): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($s->id_santri); ?>"
<?php echo e($m->id_santri == $s->id_santri ? 'selected' : ''); ?>>
<?php echo e($s->nama_lengkap); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
<?php if(!empty($m->id_santri)): ?>
<i class="fas fa-check-circle" style="color:#22C55E;font-size:16px" title="Sudah dipetakan"></i>
<?php else: ?>
<i class="fas fa-exclamation-circle" style="color:#EF4444;font-size:16px" title="Belum dipetakan"></i>
<?php endif; ?>
</div>
</form>
</td>
<td style="text-align:center">
<?php if(!empty($m->id_santri)): ?>
<span style="background:#DCFCE7;color:#166534;border-radius:12px;
padding:3px 10px;font-size:11px;font-weight:700">
Terpetakan
</span>
<?php else: ?>
<span style="background:#FEE2E2;color:#991B1B;border-radius:12px;
padding:3px 10px;font-size:11px;font-weight:700">
âš  Belum
</span>
<?php endif; ?>
</td>
<td style="text-align:center">
<form action="<?php echo e(route('admin.mesin.mapping-santri.destroy', $m->id)); ?>"
method="POST"
onsubmit="return confirm('Hapus mapping ID Mesin <?php echo e($m->id_mesin); ?> (<?php echo e($m->nama_mesin); ?>)?')">
<?php echo csrf_field(); ?> <?php echo method_field('DELETE'); ?>
<button type="submit"
class="btn btn-sm btn-danger"
style="padding:4px 10px">
<i class="fas fa-trash"></i>
</button>
</form>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
<tr>
<td colspan="6" style="text-align:center;padding:40px;color:#9CA3AF">
<i class="fas fa-inbox" style="font-size:32px;display:block;margin-bottom:8px"></i>
Belum ada mapping. Upload INFO.XLS di atas untuk mulai.
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<div class="content-box">
<h4 style="margin:0 0 6px;font-size:15px">
<i class="fas fa-plus-circle" style="color:#1D4ED8"></i> Tambah Mapping Manual
</h4>
<p style="margin:0 0 12px;color:#6B7280;font-size:13px">
Untuk santri yang baru daftar ke mesin setelah INFO.XLS diekspor,
atau santri yang nama di mesin sangat berbeda dari nama di sistem.
</p>
<form action="<?php echo e(route('admin.mesin.mapping-santri.store')); ?>" method="POST">
<?php echo csrf_field(); ?>
<div style="display:grid;grid-template-columns:120px 160px 1fr auto;gap:10px;align-items:end">
<div class="form-group" style="margin:0">
<label style="font-size:12px;font-weight:600">ID Mesin <span style="color:red">*</span></label>
<input type="text" name="id_mesin" class="form-control"
placeholder="cth: 8" required value="<?php echo e(old('id_mesin')); ?>"
style="font-family:monospace;font-size:15px;font-weight:700">
<?php $__errorArgs = ['id_mesin'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<p style="color:#EF4444;font-size:11px;margin:3px 0 0"><?php echo e($message); ?></p>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>
</div>
<div class="form-group" style="margin:0">
<label style="font-size:12px;font-weight:600">Nama di Mesin</label>
<input type="text" name="nama_mesin" class="form-control"
placeholder="cth: ilham" value="<?php echo e(old('nama_mesin')); ?>">
</div>
<div class="form-group" style="margin:0">
<label style="font-size:12px;font-weight:600">Santri Web</label>
<select name="id_santri" class="form-control">
<option value="">-- Pilih Santri (bisa diisi nanti) --</option>
<?php $__currentLoopData = $santris; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $s): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($s->id_santri); ?>"
<?php echo e(old('id_santri') == $s->id_santri ? 'selected' : ''); ?>>
<?php echo e($s->nama_lengkap); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div>
<button type="submit" class="btn btn-primary" style="white-space:nowrap;padding:9px 18px">
<i class="fas fa-plus"></i> Tambah
</button>
</div>
</div>
</form>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/mesin/mapping-santri/index.blade.php ENDPATH**/ ?>

View File

@ -1,830 +0,0 @@
<?php $__env->startSection('title', 'Detail: ' . $kegiatan->nama_kegiatan); ?>
<?php $__env->startSection('content'); ?>
<style>
:root {
--g: #1a7a5e;
--m: #2bbd8e;
--sf: #e8f7f2;
--tx: #0f1923;
--mu: #64748b;
--br: #e8edf2;
--bg: #f4f7f9;
--wh: #ffffff;
--sh: 0 2px 12px rgba(0,0,0,0.06);
--sh2: 0 6px 28px rgba(0,0,0,0.10);
--ra: 14px;
}
* { box-sizing: border-box; }
/* ──────────────────────────────────────────────
BREADCRUMB / BACK NAV
────────────────────────────────────────────── */
.sd-nav {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 14px;
font-size: 0.8rem;
color: var(--mu);
flex-wrap: wrap;
}
.sd-nav a {
color: var(--g);
text-decoration: none;
font-weight: 600;
display: inline-flex;
align-items: center;
gap: 5px;
padding: 5px 12px;
background: var(--wh);
border: 1.5px solid var(--br);
border-radius: 8px;
transition: all 0.15s;
}
.sd-nav a:hover { background: var(--sf); border-color: var(--m); }
.sd-nav-sep { color: var(--br); font-size: 1rem; }
.sd-nav-cur { font-weight: 700; color: var(--tx); }
/* ──────────────────────────────────────────────
HERO CARD Info Kegiatan
────────────────────────────────────────────── */
.sd-hero {
background: linear-gradient(135deg, #0b3528 0%, #1a7a5e 60%, #28b585 100%);
border-radius: var(--ra);
padding: 24px 26px 20px;
color: white;
margin-bottom: 18px;
position: relative;
overflow: hidden;
}
.sd-hero::before {
content: '';
position: absolute; top: -60px; right: -60px;
width: 200px; height: 200px; border-radius: 50%;
background: rgba(255,255,255,0.05); pointer-events: none;
}
.sd-hero-inner { position: relative; z-index: 1; }
.sd-hero-name {
font-size: 1.35rem; font-weight: 800;
margin: 0 0 10px; line-height: 1.2;
}
.sd-hero-chips { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: 18px; }
.sd-chip {
background: rgba(255,255,255,0.14);
border: 1px solid rgba(255,255,255,0.22);
padding: 4px 11px; border-radius: 20px;
font-size: 0.77rem; font-weight: 600;
display: inline-flex; align-items: center; gap: 5px;
}
/* ── Besar 3 KPI di hero ── */
.sd-hero-kpi {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1px;
background: rgba(255,255,255,0.12);
border: 1px solid rgba(255,255,255,0.15);
border-radius: 10px;
overflow: hidden;
}
.sd-hkpi {
padding: 12px 14px;
background: rgba(0,0,0,0.08);
text-align: center;
}
.sd-hkpi-val {
font-size: 2rem; font-weight: 900; line-height: 1;
margin-bottom: 3px;
}
.sd-hkpi-val.clr-great { color: #4ade80; }
.sd-hkpi-val.clr-ok { color: #fcd34d; }
.sd-hkpi-val.clr-bad { color: #fca5a5; }
.sd-hkpi-val.clr-white { color: #ffffff; }
.sd-hkpi-lbl { font-size: 0.75rem; opacity: 0.75; font-weight: 600; }
.sd-hkpi-sub { font-size: 0.66rem; opacity: 0.50; margin-top: 2px; }
/* ──────────────────────────────────────────────
FILTER BAR
────────────────────────────────────────────── */
.sd-filter {
background: var(--wh);
border-radius: 12px;
padding: 12px 14px;
margin-bottom: 16px;
box-shadow: var(--sh);
display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end;
}
.sd-fg { display: flex; flex-direction: column; gap: 3px; }
.sd-fg label {
font-size: 0.70rem; font-weight: 700; color: var(--mu);
text-transform: uppercase; letter-spacing: 0.5px;
}
.sd-presets { display: flex; gap: 4px; flex-wrap: wrap; }
.sd-pbtn {
padding: 6px 11px; border: 1.5px solid var(--br);
border-radius: 8px; background: var(--wh);
font-size: 0.78rem; font-weight: 600; color: var(--mu);
cursor: pointer; transition: all 0.15s; white-space: nowrap;
}
.sd-pbtn:hover { border-color: var(--m); color: var(--g); background: var(--sf); }
.sd-pbtn.active { border-color: var(--g); background: var(--g); color: white; }
.sd-drange { display: flex; align-items: center; gap: 5px; }
.sd-drange input[type=date] {
padding: 6px 9px; border: 1.5px solid var(--br);
border-radius: 8px; font-size: 0.79rem; color: var(--tx);
}
.sd-drange input[type=date]:focus { outline: none; border-color: var(--m); }
.sd-drange span { font-size: 0.78rem; font-weight: 600; color: var(--mu); }
.sd-apply {
padding: 7px 14px; background: var(--g); color: white;
border: none; border-radius: 8px;
font-size: 0.8rem; font-weight: 700; cursor: pointer;
display: inline-flex; align-items: center; gap: 5px;
}
.sd-apply:hover { background: #155c47; }
.sd-finfo {
font-size: 0.75rem; color: var(--mu);
padding: 5px 9px; background: var(--bg);
border-radius: 8px; border: 1px solid var(--br);
display: flex; align-items: center; gap: 4px; align-self: center;
}
/* ──────────────────────────────────────────────
6 STAT PILL CARDS
────────────────────────────────────────────── */
.sd-pills {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 8px;
margin-bottom: 18px;
}
.sd-pill-card {
background: var(--wh);
border-radius: 11px;
padding: 13px 8px 11px;
box-shadow: var(--sh);
text-align: center;
border-bottom: 3px solid transparent;
transition: transform 0.15s, box-shadow 0.15s;
}
.sd-pill-card:hover { transform: translateY(-2px); box-shadow: var(--sh2); }
.sd-pill-card.p-green { border-bottom-color: #2bbd8e; }
.sd-pill-card.p-amber { border-bottom-color: #f59e0b; }
.sd-pill-card.p-blue { border-bottom-color: #3b82f6; }
.sd-pill-card.p-purple { border-bottom-color: #8b5cf6; }
.sd-pill-card.p-red { border-bottom-color: #e53e3e; }
.sd-pill-card.p-teal { border-bottom-color: #0d9488; }
.sd-pill-icon {
width: 32px; height: 32px; border-radius: 8px;
display: flex; align-items: center; justify-content: center;
font-size: 0.85rem; margin: 0 auto 7px;
}
.p-green .sd-pill-icon { background: #d1fae5; color: #059669; }
.p-amber .sd-pill-icon { background: #fef3c7; color: #d97706; }
.p-blue .sd-pill-icon { background: #dbeafe; color: #2563eb; }
.p-purple .sd-pill-icon { background: #ede9fe; color: #7c3aed; }
.p-red .sd-pill-icon { background: #fee2e2; color: #dc2626; }
.p-teal .sd-pill-icon { background: #ccfbf1; color: #0f766e; }
.sd-pill-val { font-size: 1.6rem; font-weight: 800; color: var(--tx); line-height: 1; }
.sd-pill-lbl { font-size: 0.71rem; color: var(--mu); margin-top: 3px; font-weight: 500; }
/* ──────────────────────────────────────────────
INSIGHT BANNER (pesan sederhana untuk santri)
────────────────────────────────────────────── */
.sd-insight {
border-radius: 11px;
padding: 13px 16px;
margin-bottom: 18px;
display: flex; align-items: center; gap: 12px;
font-size: 0.84rem; font-weight: 600;
}
.sd-insight.good { background: #d1fae5; color: #065f46; border: 1px solid #a7f3d0; }
.sd-insight.warn { background: #fef3c7; color: #92400e; border: 1px solid #fde68a; }
.sd-insight.bad { background: #fee2e2; color: #991b1b; border: 1px solid #fecaca; }
.sd-insight-ic { font-size: 1.4rem; flex-shrink: 0; }
.sd-insight-text b { display: block; font-size: 0.9rem; margin-bottom: 2px; }
/* ──────────────────────────────────────────────
2 KOLOM Chart & Distribusi
────────────────────────────────────────────── */
.sd-row2 {
display: grid;
grid-template-columns: 3fr 2fr;
gap: 14px;
margin-bottom: 18px;
}
.sd-card {
background: var(--wh);
border-radius: 12px;
padding: 18px;
box-shadow: var(--sh);
}
.sd-card-title {
font-size: 0.85rem; font-weight: 700; color: var(--tx);
margin-bottom: 14px;
display: flex; align-items: center; gap: 7px;
}
.sd-card-title .badge {
margin-left: auto;
font-size: 0.70rem; color: var(--mu); font-weight: 500;
background: var(--bg); padding: 3px 8px; border-radius: 6px;
border: 1px solid var(--br);
}
/* Progress distribusi */
.sd-dist-list { display: flex; flex-direction: column; gap: 10px; }
.sd-dist-row { display: flex; align-items: center; gap: 9px; }
.sd-dist-lbl { font-size: 0.77rem; font-weight: 600; color: var(--tx); min-width: 72px; }
.sd-dist-track{ flex: 1; height: 9px; background: #f1f5f9; border-radius: 5px; overflow: hidden; }
.sd-dist-fill { height: 100%; border-radius: 5px; transition: width 0.6s ease; }
.sd-dist-val { font-size: 0.73rem; font-weight: 700; color: var(--tx); min-width: 46px; text-align: right; }
.sd-dist-pct { font-size: 0.67rem; color: var(--mu); font-weight: 400; }
/* ──────────────────────────────────────────────
TABEL RIWAYAT
────────────────────────────────────────────── */
.sd-table-wrap {
background: var(--wh);
border-radius: 12px;
box-shadow: var(--sh);
overflow: hidden;
}
.sd-table-header {
padding: 13px 16px;
border-bottom: 1px solid var(--br);
display: flex; align-items: center; gap: 8px;
}
.sd-table-header-title {
font-size: 0.86rem; font-weight: 700; color: var(--tx);
display: flex; align-items: center; gap: 7px;
}
.sd-count-badge {
margin-left: auto;
background: var(--sf); color: var(--g);
padding: 3px 10px; border-radius: 8px;
font-size: 0.72rem; font-weight: 700;
}
.sd-table { width: 100%; border-collapse: collapse; }
.sd-table thead tr { background: var(--bg); }
.sd-table th {
padding: 9px 14px;
text-align: left;
font-size: 0.72rem; font-weight: 700; color: var(--mu);
text-transform: uppercase; letter-spacing: 0.5px;
border-bottom: 1px solid var(--br);
}
.sd-table td {
padding: 10px 14px;
font-size: 0.83rem;
border-bottom: 1px solid #f5f8fa;
color: var(--tx);
vertical-align: middle;
}
.sd-table tbody tr:last-child td { border-bottom: none; }
.sd-table tbody tr:hover { background: #fafcfd; }
/* Row highlight berdasarkan status */
.sd-table tbody tr.row-alpa { background: #fff5f5; }
.sd-table tbody tr.row-alpa:hover { background: #fee2e2; }
/* Status badge di tabel */
.sd-status {
padding: 4px 11px; border-radius: 20px;
font-size: 0.76rem; font-weight: 700;
display: inline-flex; align-items: center; gap: 4px;
}
.sd-status.hadir { background: #d1fae5; color: #065f46; }
.sd-status.terlambat { background: #fef3c7; color: #92400e; }
.sd-status.izin { background: #dbeafe; color: #1e40af; }
.sd-status.sakit { background: #ede9fe; color: #5b21b6; }
.sd-status.alpa { background: #fee2e2; color: #991b1b; }
.sd-status.pulang { background: #ccfbf1; color: #0f766e; }
/* Kolom tanggal + hari */
.sd-date-main { font-weight: 700; font-size: 0.84rem; color: var(--tx); }
.sd-date-day { font-size: 0.71rem; color: var(--mu); margin-top: 1px; }
/* Metode chip */
.sd-metode {
display: inline-flex; align-items: center; gap: 5px;
background: var(--bg); border: 1px solid var(--br);
padding: 3px 9px; border-radius: 7px;
font-size: 0.74rem; font-weight: 600; color: var(--mu);
}
.sd-empty {
text-align: center; padding: 44px 20px;
color: var(--mu); font-size: 0.84rem;
}
.sd-empty i { font-size: 2.6rem; opacity: 0.15; display: block; margin-bottom: 10px; }
/* ──────────────────────────────────────────────
PAGINATION
────────────────────────────────────────────── */
.sd-pagination { padding: 12px 16px; border-top: 1px solid var(--br); }
@media (max-width: 720px) {
.sd-pills { grid-template-columns: repeat(3, 1fr); }
.sd-row2 { grid-template-columns: 1fr; }
.sd-hero-kpi { grid-template-columns: repeat(3, 1fr); }
.sd-table th:nth-child(1),
.sd-table td:nth-child(1) { display: none; }
}
</style>
<div class="sd-nav">
<a href="<?php echo e(route('santri.kegiatan.index')); ?>?tab=<?php echo e($fromTab ?? 'jadwal'); ?>">
<i class="fas fa-arrow-left"></i> Kembali ke Jadwal
</a>
<span class="sd-nav-sep"></span>
<span class="sd-nav-cur"><?php echo e($kegiatan->nama_kegiatan); ?></span>
</div>
<div class="sd-hero">
<div class="sd-hero-inner">
<h1 class="sd-hero-name">
<i class="fas fa-clipboard-list" style="opacity:0.7;margin-right:4px;"></i>
<?php echo e($kegiatan->nama_kegiatan); ?>
</h1>
<div class="sd-hero-chips">
<span class="sd-chip"><i class="fas fa-tag"></i> <?php echo e($kegiatan->kategori->nama_kategori); ?></span>
<span class="sd-chip"><i class="fas fa-calendar-day"></i> Setiap <?php echo e($kegiatan->hari); ?></span>
<span class="sd-chip">
<i class="fas fa-clock"></i>
<?php echo e(date('H:i', strtotime($kegiatan->waktu_mulai))); ?> <?php echo e(date('H:i', strtotime($kegiatan->waktu_selesai))); ?>
</span>
<?php if($kegiatan->materi): ?>
<span class="sd-chip"><i class="fas fa-book-open"></i> <?php echo e(Str::limit($kegiatan->materi, 35)); ?></span>
<?php endif; ?>
</div>
<div class="sd-hero-kpi">
<div class="sd-hkpi">
<?php
$clr = $persentaseHadir >= 85 ? 'clr-great' : ($persentaseHadir >= 70 ? 'clr-ok' : 'clr-bad');
?>
<div class="sd-hkpi-val <?php echo e($clr); ?>"><?php echo e($persentaseHadir); ?>%</div>
<div class="sd-hkpi-lbl">Tingkat Kehadiran</div>
<div class="sd-hkpi-sub">hadir + terlambat</div>
</div>
<div class="sd-hkpi">
<div class="sd-hkpi-val clr-white"><?php echo e($hadirEfektif); ?></div>
<div class="sd-hkpi-lbl">Kali Hadir</div>
<div class="sd-hkpi-sub">dari <?php echo e($totalAbsensi); ?> tercatat</div>
</div>
<div class="sd-hkpi">
<div class="sd-hkpi-val <?php echo e(($stats['Alpa'] ?? 0) > 0 ? 'clr-bad' : 'clr-great'); ?>">
<?php echo e($stats['Alpa'] ?? 0); ?>
</div>
<div class="sd-hkpi-lbl">Kali Alpa</div>
<div class="sd-hkpi-sub">tidak masuk tanpa izin</div>
</div>
</div>
</div>
</div>
<form method="GET" action="<?php echo e(route('santri.kegiatan.show', $kegiatan->kegiatan_id)); ?>" id="filterForm">
<input type="hidden" name="from_tab" value="<?php echo e($fromTab ?? 'jadwal'); ?>">
<input type="hidden" name="preset" id="hPreset" value="<?php echo e($preset); ?>">
<input type="hidden" name="date_from" id="hDateFrom" value="<?php echo e(request('date_from')); ?>">
<input type="hidden" name="date_to" id="hDateTo" value="<?php echo e(request('date_to')); ?>">
<div class="sd-filter">
<div class="sd-fg">
<label><i class="fas fa-bolt"></i> Tampilkan periode</label>
<div class="sd-presets" id="presetBtns">
<?php $__currentLoopData = [
'this_week' => 'Minggu Ini',
'this_month' => 'Bulan Ini',
'last_month' => 'Bulan Lalu',
'last_3m' => '3 Bulan',
'all' => 'Semua Data',
]; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $v => $l): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<button type="button"
class="sd-pbtn <?php echo e($preset === $v ? 'active' : ''); ?>"
onclick="setPreset('<?php echo e($v); ?>')"><?php echo e($l); ?></button>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
</div>
<div class="sd-fg">
<label><i class="fas fa-calendar-alt"></i> Rentang kustom</label>
<div class="sd-drange">
<input type="date" id="inpFrom" value="<?php echo e($dateFrom->format('Y-m-d')); ?>" onchange="setCustom()">
<span></span>
<input type="date" id="inpTo" value="<?php echo e($dateTo->format('Y-m-d')); ?>" onchange="setCustom()">
</div>
</div>
<button type="submit" class="sd-apply"><i class="fas fa-sync-alt"></i> Terapkan</button>
<div class="sd-finfo">
<i class="fas fa-calendar-check" style="color:var(--m);"></i>
<?php echo e($dateFrom->locale('id')->isoFormat('D MMM YYYY')); ?>
<?php echo e($dateTo->locale('id')->isoFormat('D MMM YYYY')); ?>
</div>
</div>
</form>
<div class="sd-pills">
<?php
$pillData = [
['label' => 'Hadir', 'val' => $stats['Hadir'] ?? 0, 'icon' => 'check-circle', 'cls' => 'p-green'],
['label' => 'Terlambat', 'val' => $stats['Terlambat'] ?? 0, 'icon' => 'clock', 'cls' => 'p-amber'],
['label' => 'Izin', 'val' => $stats['Izin'] ?? 0, 'icon' => 'info-circle', 'cls' => 'p-blue'],
['label' => 'Sakit', 'val' => $stats['Sakit'] ?? 0, 'icon' => 'heartbeat', 'cls' => 'p-purple'],
['label' => 'Alpa', 'val' => $stats['Alpa'] ?? 0, 'icon' => 'times-circle', 'cls' => 'p-red'],
['label' => 'Pulang', 'val' => $stats['Pulang'] ?? 0, 'icon' => 'home', 'cls' => 'p-teal'],
];
?>
<?php $__currentLoopData = $pillData; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $p): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div class="sd-pill-card <?php echo e($p['cls']); ?>">
<div class="sd-pill-icon"><i class="fas fa-<?php echo e($p['icon']); ?>"></i></div>
<div class="sd-pill-val"><?php echo e($p['val']); ?></div>
<div class="sd-pill-lbl"><?php echo e($p['label']); ?></div>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
<?php
$alpaCount = $stats['Alpa'] ?? 0;
$insightCls = $persentaseHadir >= 85 ? 'good' : ($persentaseHadir >= 65 ? 'warn' : 'bad');
if ($insightCls === 'good') {
$insightIcon = '🎉';
$insightJudul = 'Kehadiranmu sangat baik!';
$insightMsg = "Kamu hadir $hadirEfektif dari $totalAbsensi sesi yang tercatat. Pertahankan ya!";
} elseif ($insightCls === 'warn') {
$insightIcon = '⚠️';
$insightJudul = 'Kehadiranmu perlu ditingkatkan.';
$insightMsg = "Tingkat kehadiranmu $persentaseHadir% dalam periode ini. Yuk lebih rajin lagi!";
} else {
$insightIcon = '❗';
$insightJudul = 'Kehadiranmu sangat rendah.';
$insightMsg = "Hanya $persentaseHadir% dari sesi yang dihadiri. Ada $alpaCount kali alpa. Segera konsultasikan ke pembimbing.";
}
?>
<?php if($totalAbsensi > 0): ?>
<div class="sd-insight <?php echo e($insightCls); ?>">
<div class="sd-insight-ic"><?php echo e($insightIcon); ?></div>
<div class="sd-insight-text">
<b><?php echo e($insightJudul); ?></b>
<?php echo e($insightMsg); ?>
</div>
</div>
<?php endif; ?>
<?php
// $absensiByDate sudah dikirim dari controller: ['Y-m-d' => 'Status', ...]
// Mencakup SEMUA data dalam range, bukan hanya halaman saat ini
$statusMeta = [
'Hadir' => ['bg'=>'#d1fae5','text'=>'#065f46','border'=>'#6ee7b7','dot'=>'#2bbd8e','icon'=>'✓'],
'Terlambat' => ['bg'=>'#fef3c7','text'=>'#92400e','border'=>'#fcd34d','dot'=>'#f59e0b','icon'=>'⏰'],
'Izin' => ['bg'=>'#dbeafe','text'=>'#1e40af','border'=>'#93c5fd','dot'=>'#3b82f6','icon'=>'I'],
'Sakit' => ['bg'=>'#ede9fe','text'=>'#5b21b6','border'=>'#c4b5fd','dot'=>'#8b5cf6','icon'=>'🏥'],
'Alpa' => ['bg'=>'#fee2e2','text'=>'#991b1b','border'=>'#fca5a5','dot'=>'#e53e3e','icon'=>'✗'],
'Pulang' => ['bg'=>'#ccfbf1','text'=>'#0f766e','border'=>'#5eead4','dot'=>'#0d9488','icon'=>'🏠'],
];
$distItems = [
['label'=>'Hadir', 'val'=>$stats['Hadir'] ?? 0, 'color'=>'#2bbd8e', 'emoji'=>'✅'],
['label'=>'Terlambat', 'val'=>$stats['Terlambat'] ?? 0, 'color'=>'#f59e0b', 'emoji'=>'⏰'],
['label'=>'Izin', 'val'=>$stats['Izin'] ?? 0, 'color'=>'#3b82f6', 'emoji'=>''],
['label'=>'Sakit', 'val'=>$stats['Sakit'] ?? 0, 'color'=>'#8b5cf6', 'emoji'=>'🏥'],
['label'=>'Alpa', 'val'=>$stats['Alpa'] ?? 0, 'color'=>'#e53e3e', 'emoji'=>'❌'],
['label'=>'Pulang', 'val'=>$stats['Pulang'] ?? 0, 'color'=>'#0d9488', 'emoji'=>'🏠'],
];
$hariSingkat = ['Monday'=>'Sen','Tuesday'=>'Sel','Wednesday'=>'Rab',
'Thursday'=>'Kam','Friday'=>'Jum','Saturday'=>'Sab','Sunday'=>'Ahd'];
?>
<style>
/* ── Kalender Visual ── */
.sd-cal-wrap {
background: var(--wh); border-radius: 12px;
padding: 18px; box-shadow: var(--sh); margin-bottom: 14px;
}
.sd-cal-title {
font-size: 0.85rem; font-weight: 700; color: var(--tx);
margin-bottom: 6px; display: flex; align-items: center; gap: 7px;
}
.sd-cal-hint {
font-size: 0.75rem; color: var(--mu);
margin-bottom: 14px; padding: 7px 11px;
background: var(--bg); border-radius: 7px;
border-left: 3px solid var(--m);
display: flex; align-items: center; gap: 6px;
}
.sd-legend {
display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px;
}
.sd-legend-item {
display: inline-flex; align-items: center; gap: 5px;
font-size: 0.74rem; font-weight: 600; color: var(--tx);
}
.sd-legend-dot { width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0; }
.sd-cal-grid { display: flex; flex-wrap: wrap; gap: 6px; }
.sd-cal-slot {
width: 50px; border-radius: 9px; padding: 7px 4px 6px;
text-align: center; border: 1.5px solid #e8edf2;
background: #f8fafc; transition: transform 0.12s, box-shadow 0.12s;
cursor: default;
}
.sd-cal-slot:hover { transform: translateY(-2px); box-shadow: 0 5px 16px rgba(0,0,0,0.13); z-index: 5; }
.sd-cal-slot-icon { font-size: 1rem; line-height: 1; margin-bottom: 3px; display: block; }
.sd-cal-slot-date { font-size: 0.69rem; font-weight: 800; line-height: 1; display: block; }
.sd-cal-slot-day { font-size: 0.60rem; font-weight: 500; opacity: 0.65; display: block; margin-top: 1px; }
.sd-cal-slot-lbl { font-size: 0.58rem; font-weight: 700; display: block; margin-top: 3px;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sd-cal-slot.empty { background: #f1f5f9; border-color: #e2e8f0; opacity: 0.5; }
.sd-cal-slot.is-today { outline: 2px solid #f5a623; outline-offset: 2px; }
/* ── Distribusi ── */
.sd-dist2-wrap {
background: var(--wh); border-radius: 12px;
padding: 18px; box-shadow: var(--sh); margin-bottom: 18px;
}
.sd-dist2-title {
font-size: 0.85rem; font-weight: 700; color: var(--tx);
margin-bottom: 14px; display: flex; align-items: center; gap: 7px;
}
.sd-dist2-list { display: flex; flex-direction: column; gap: 13px; }
.sd-dist2-row { display: flex; align-items: center; gap: 10px; }
.sd-dist2-emoji { font-size: 1.05rem; width: 22px; text-align: center; flex-shrink: 0; }
.sd-dist2-lbl { font-size: 0.82rem; font-weight: 700; color: var(--tx); min-width: 76px; }
.sd-dist2-track { flex: 1; height: 12px; background: #f1f5f9; border-radius: 6px; overflow: hidden; }
.sd-dist2-fill { height: 100%; border-radius: 6px; }
.sd-dist2-val { font-size: 0.82rem; font-weight: 800; color: var(--tx); min-width: 30px; text-align: right; }
.sd-dist2-pct { font-size: 0.72rem; color: var(--mu); min-width: 38px; text-align: right; }
</style>
<div class="sd-cal-wrap">
<div class="sd-cal-title">
<i class="fas fa-calendar-alt" style="color:var(--m);"></i>
Kalender Kehadiran
<span style="margin-left:auto;font-size:0.71rem;color:var(--mu);font-weight:500;background:var(--bg);border:1px solid var(--br);padding:3px 9px;border-radius:7px;">
<?php echo e($dateFrom->locale('id')->isoFormat('D MMM')); ?> <?php echo e($dateTo->locale('id')->isoFormat('D MMM YYYY')); ?>
</span>
</div>
<div class="sd-cal-hint">
<i class="fas fa-lightbulb" style="color:var(--m);flex-shrink:0;"></i>
Tiap kotak = 1 hari dalam periode filter. Warna = status absensimu. Kotak abu-abu = tidak ada catatan absensi di hari itu.
</div>
<div class="sd-legend">
<?php $__currentLoopData = $statusMeta; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $sLabel => $sMeta): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div class="sd-legend-item">
<div class="sd-legend-dot" style="background:<?php echo e($sMeta['dot']); ?>;"></div> <?php echo e($sLabel); ?>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<div class="sd-legend-item">
<div class="sd-legend-dot" style="background:#e2e8f0;"></div> Tidak ada catatan
</div>
</div>
<div class="sd-cal-grid">
<?php $cursor = $dateFrom->copy(); ?>
<?php while($cursor->lte($dateTo)): ?>
<?php
$tgl = $cursor->format('Y-m-d');
$status = $absensiByDate[$tgl] ?? null;
$meta = $status ? ($statusMeta[$status] ?? null) : null;
$hariId = $hariSingkat[$cursor->format('l')] ?? substr($cursor->format('l'), 0, 3);
$tglFmt = $cursor->format('d/m');
$isToday = $tgl === \Carbon\Carbon::today()->format('Y-m-d');
?>
<?php if($meta): ?>
<div class="sd-cal-slot <?php echo e($isToday ? 'is-today' : ''); ?>"
style="background:<?php echo e($meta['bg']); ?>;border-color:<?php echo e($meta['border']); ?>;color:<?php echo e($meta['text']); ?>;"
title="<?php echo e($cursor->locale('id')->isoFormat('dddd, D MMMM YYYY')); ?> — <?php echo e($status); ?>">
<span class="sd-cal-slot-icon"><?php echo e($meta['icon']); ?></span>
<span class="sd-cal-slot-date"><?php echo e($tglFmt); ?></span>
<span class="sd-cal-slot-day"><?php echo e($hariId); ?></span>
<span class="sd-cal-slot-lbl"><?php echo e($status); ?></span>
</div>
<?php else: ?>
<div class="sd-cal-slot empty <?php echo e($isToday ? 'is-today' : ''); ?>"
title="<?php echo e($cursor->locale('id')->isoFormat('dddd, D MMMM YYYY')); ?> — Tidak ada catatan">
<span class="sd-cal-slot-icon" style="color:#cbd5e1;"></span>
<span class="sd-cal-slot-date" style="color:#94a3b8;"><?php echo e($tglFmt); ?></span>
<span class="sd-cal-slot-day" style="color:#94a3b8;"><?php echo e($hariId); ?></span>
<span class="sd-cal-slot-lbl" style="color:#d1d5db;">Belum</span>
</div>
<?php endif; ?>
<?php $cursor->addDay(); ?>
<?php endwhile; ?>
</div>
</div>
<div class="sd-dist2-wrap">
<div class="sd-dist2-title">
<i class="fas fa-align-left" style="color:#f5a623;"></i>
Perincian Status
<span style="margin-left:auto;font-size:0.71rem;color:var(--mu);font-weight:500;background:var(--bg);border:1px solid var(--br);padding:3px 9px;border-radius:7px;"><?php echo e($totalAbsensi); ?> total sesi tercatat</span>
</div>
<?php if($totalAbsensi > 0): ?>
<div class="sd-dist2-list">
<?php $__currentLoopData = $distItems; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $d): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php if($d['val'] > 0 || in_array($d['label'], ['Hadir','Alpa'])): ?>
<div class="sd-dist2-row">
<div class="sd-dist2-emoji"><?php echo e($d['emoji']); ?></div>
<div class="sd-dist2-lbl"><?php echo e($d['label']); ?></div>
<div class="sd-dist2-track">
<div class="sd-dist2-fill" style="width:<?php echo e(round($d['val']/$totalAbsensi*100)); ?>%;background:<?php echo e($d['color']); ?>;"></div>
</div>
<div class="sd-dist2-val"><?php echo e($d['val']); ?>×</div>
<div class="sd-dist2-pct"><?php echo e(round($d['val']/$totalAbsensi*100)); ?>%</div>
</div>
<?php endif; ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
<?php else: ?>
<div class="sd-empty"><i class="fas fa-inbox"></i><p>Belum ada data absensi.</p></div>
<?php endif; ?>
</div>
<div class="sd-table-wrap">
<div class="sd-table-header" style="flex-wrap:wrap;gap:8px;">
<div class="sd-table-header-title">
<i class="fas fa-history" style="color:var(--m);"></i>
Rekap Kehadiran
</div>
<div style="display:flex;align-items:center;gap:6px;flex-wrap:wrap;flex:1;">
<span style="
background:#e8f7f2; color:#1a7a5e;
border:1px solid #a7f3d0;
padding:4px 11px; border-radius:20px;
font-size:0.76rem; font-weight:700;
display:inline-flex; align-items:center; gap:5px;
">
<i class="fas fa-calendar-check"></i>
<?php echo e($dateFrom->locale('id')->isoFormat('D MMM YYYY')); ?>
&nbsp;&nbsp;
<?php echo e($dateTo->locale('id')->isoFormat('D MMM YYYY')); ?>
</span>
<?php
$presetLabels = [
'this_week' => 'Minggu Ini',
'this_month' => 'Bulan Ini',
'last_month' => 'Bulan Lalu',
'last_3m' => '3 Bulan Terakhir',
'all' => 'Semua Data',
'custom' => 'Kustom',
];
?>
<?php if(isset($presetLabels[$preset])): ?>
<span style="font-size:0.73rem;color:var(--mu);">
(<?php echo e($presetLabels[$preset]); ?>)
</span>
<?php endif; ?>
</div>
<span class="sd-count-badge"><?php echo e($riwayats->total()); ?> sesi</span>
</div>
<div style="
padding:9px 16px;
background:#f8fafc;
border-bottom:1px solid var(--br);
font-size:0.78rem; color:var(--mu);
display:flex; align-items:center; gap:6px;
">
<i class="fas fa-info-circle" style="color:var(--m);"></i>
Menampilkan <strong style="color:var(--tx);"><?php echo e($riwayats->total()); ?> catatan absensi</strong>
kegiatan <strong style="color:var(--tx);"><?php echo e($kegiatan->nama_kegiatan); ?></strong>
dari tanggal <strong style="color:var(--tx);"><?php echo e($dateFrom->locale('id')->isoFormat('D MMM YYYY')); ?></strong>
sampai <strong style="color:var(--tx);"><?php echo e($dateTo->locale('id')->isoFormat('D MMM YYYY')); ?></strong>.
<?php if($riwayats->hasPages()): ?>
Halaman <?php echo e($riwayats->currentPage()); ?> dari <?php echo e($riwayats->lastPage()); ?>.
<?php endif; ?>
</div>
<?php if($riwayats->count() > 0): ?>
<div style="overflow-x:auto;">
<table class="sd-table">
<thead>
<tr>
<th style="width:42px;">#</th>
<th>Tanggal</th>
<th>Jam Absen</th>
<th>Status</th>
<th>Cara Absen</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $riwayats; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $idx => $absensi): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$statusLower = strtolower($absensi->status);
$rowCls = $statusLower === 'alpa' ? 'row-alpa' : '';
$metode = $absensi->metode_absen ?? '';
$metodeLabel = $metode === 'Import_Mesin' ? 'Mesin' : ($metode ?: 'Manual');
$metodeIcon = $metode === 'RFID' ? 'id-card' : ($metode === 'Import_Mesin' ? 'desktop' : 'hand-pointer');
?>
<tr class="<?php echo e($rowCls); ?>">
<td style="color:#9ca3af;font-size:0.74rem;text-align:center;">
<?php echo e($riwayats->firstItem() + $idx); ?>
</td>
<td>
<div class="sd-date-main">
<?php echo e(\Carbon\Carbon::parse($absensi->tanggal)->format('d M Y')); ?>
</div>
<div class="sd-date-day">
<?php echo e(\Carbon\Carbon::parse($absensi->tanggal)->locale('id')->isoFormat('dddd')); ?>
</div>
</td>
<td>
<?php if($absensi->waktu_absen): ?>
<span style="font-weight:700;color:var(--tx);font-size:0.9rem;">
<?php echo e(\Carbon\Carbon::parse($absensi->waktu_absen)->format('H:i')); ?>
</span>
<span style="font-size:0.7rem;color:var(--mu);display:block;">WIB</span>
<?php else: ?>
<span style="color:#d1d5db;font-size:0.8rem;"></span>
<?php endif; ?>
</td>
<td>
<span class="sd-status <?php echo e($statusLower); ?>">
<?php if($absensi->status === 'Hadir'): ?> <i class="fas fa-check"></i>
<?php elseif($absensi->status === 'Terlambat'): ?> <i class="fas fa-clock"></i>
<?php elseif($absensi->status === 'Izin'): ?> <i class="fas fa-info"></i>
<?php elseif($absensi->status === 'Sakit'): ?> <i class="fas fa-heartbeat"></i>
<?php elseif($absensi->status === 'Alpa'): ?> <i class="fas fa-times"></i>
<?php elseif($absensi->status === 'Pulang'): ?> <i class="fas fa-home"></i>
<?php endif; ?>
<?php echo e($absensi->status); ?>
</span>
</td>
<td>
<span class="sd-metode">
<i class="fas fa-<?php echo e($metodeIcon); ?>"></i> <?php echo e($metodeLabel); ?>
</span>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<div class="sd-pagination">
<?php echo e($riwayats->appends(request()->query())->links()); ?>
</div>
<?php else: ?>
<div class="sd-empty">
<i class="fas fa-inbox"></i>
<p>Belum ada catatan absensi dalam periode ini.</p>
<p style="font-size:0.76rem;margin-top:4px;">
Periode aktif: <strong><?php echo e($dateFrom->locale('id')->isoFormat('D MMM YYYY')); ?> <?php echo e($dateTo->locale('id')->isoFormat('D MMM YYYY')); ?></strong>.
Coba pilih periode yang lebih luas di filter atas.
</p>
</div>
<?php endif; ?>
</div>
<script>
function setPreset(val) {
document.querySelectorAll('.sd-pbtn').forEach(b => b.classList.remove('active'));
event.target.classList.add('active');
document.getElementById('hPreset').value = val;
document.getElementById('hDateFrom').value = '';
document.getElementById('hDateTo').value = '';
document.getElementById('filterForm').submit();
}
function setCustom() {
document.getElementById('hPreset').value = '';
document.getElementById('hDateFrom').value = document.getElementById('inpFrom').value;
document.getElementById('hDateTo').value = document.getElementById('inpTo').value;
document.querySelectorAll('.sd-pbtn').forEach(b => b.classList.remove('active'));
}
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/santri/kegiatan/show.blade.php ENDPATH**/ ?>

View File

@ -1,87 +0,0 @@

<?php $__env->startSection('title', 'Manajemen Akun Admin'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-user-shield"></i> Manajemen Akun Admin</h2>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success"><?php echo e(session('success')); ?></div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger"><?php echo e(session('error')); ?></div>
<?php endif; ?>
<div class="content-box">
<div class="content-header-flex">
<a href="<?php echo e(route('admin.users.admin_create')); ?>" class="btn btn-primary">
<i class="fas fa-plus"></i> Tambah Akun Admin
</a>
</div>
<p class="text-muted" style="margin-top: 8px;">
Kelola akun untuk role <strong>Akademik</strong> dan <strong>Pamong</strong>.
Akun <strong>Super Admin</strong> tidak dapat dihapus dari halaman ini.
</p>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>No</th>
<th>Nama</th>
<th>Email</th>
<th>Role</th>
<th>Dibuat</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<?php $__empty_1 = true; $__currentLoopData = $admins; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $i => $admin): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
<tr>
<td><?php echo e($i + 1); ?></td>
<td><?php echo e($admin->name); ?></td>
<td><?php echo e($admin->email); ?></td>
<td>
<?php if($admin->role === 'super_admin'): ?>
<span class="badge" style="background:#6f42c1;color:#fff;padding:3px 8px;border-radius:4px;">Super Admin</span>
<?php elseif($admin->role === 'akademik'): ?>
<span class="badge" style="background:#0d6efd;color:#fff;padding:3px 8px;border-radius:4px;">Akademik</span>
<?php else: ?>
<span class="badge" style="background:#198754;color:#fff;padding:3px 8px;border-radius:4px;">Pamong</span>
<?php endif; ?>
</td>
<td><?php echo e($admin->created_at->format('d/m/Y')); ?></td>
<td>
<?php if($admin->role !== 'super_admin'): ?>
<a href="<?php echo e(route('admin.users.admin_edit', $admin->id)); ?>" class="btn btn-sm btn-warning">
<i class="fas fa-edit"></i> Edit
</a>
<form action="<?php echo e(route('admin.users.admin_destroy', $admin->id)); ?>" method="POST" style="display:inline;"
onsubmit="return confirm('Yakin hapus akun <?php echo e($admin->name); ?>?')">
<?php echo csrf_field(); ?>
<?php echo method_field('DELETE'); ?>
<button type="submit" class="btn btn-sm btn-danger">
<i class="fas fa-trash"></i> Hapus
</button>
</form>
<?php else: ?>
<span class="text-muted"><i class="fas fa-lock"></i> Protected</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
<tr>
<td colspan="6" class="text-center">Belum ada akun admin terdaftar.</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', ['isAdmin' => true], \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/users/admin_accounts.blade.php ENDPATH**/ ?>

View File

@ -1,253 +0,0 @@
<div class="modal-kegiatan-detail">
<div style="background: linear-gradient(135deg, <?php echo e($kegiatan->kategori->warna ?? '#6FBAA5'); ?>, <?php echo e($kegiatan->kategori->warna ?? '#5AA88D'); ?>);
color: white; padding: 14px; border-radius: 8px; margin-bottom: 14px;">
<h4 style="margin: 0 0 10px 0; display: flex; align-items: center; gap: 10px;">
<i class="fas <?php echo e($kegiatan->kategori->icon ?? 'fa-calendar'); ?>"></i>
<?php echo e($kegiatan->nama_kegiatan); ?>
</h4>
<div style="display: flex; gap: 20px; flex-wrap: wrap; font-size: 0.9rem; opacity: 0.95;">
<span><i class="fas fa-clock"></i> <?php echo e(date('H:i', strtotime($kegiatan->waktu_mulai))); ?> - <?php echo e(date('H:i', strtotime($kegiatan->waktu_selesai))); ?></span>
<span><i class="fas fa-tag"></i> <?php echo e($kegiatan->kategori->nama_kategori); ?></span>
<span><i class="fas fa-calendar-day"></i> <?php echo e($kegiatan->hari); ?></span>
<span>
<i class="fas fa-layer-group"></i>
<?php if($kegiatan->kelasKegiatan->isEmpty()): ?>
Kegiatan Umum
<?php else: ?>
<?php echo e($kegiatan->kelasKegiatan->pluck('nama_kelas')->implode(', ')); ?>
<?php endif; ?>
</span>
</div>
<?php if($kegiatan->materi): ?>
<div style="margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(255,255,255,0.2);">
<i class="fas fa-book"></i> Materi: <?php echo e($kegiatan->materi); ?>
</div>
<?php endif; ?>
</div>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 11px; margin-bottom: 20px;">
<div style="background: linear-gradient(135deg, #28a745, #218838); color: white; padding: 15px; border-radius: 8px; text-align: center;">
<div style="font-size: 2rem; font-weight: 700;"><?php echo e($stats['hadir']); ?></div>
<div style="font-size: 0.85rem; opacity: 0.9; margin-top: 5px;"><i class="fas fa-check-circle"></i> Hadir</div>
</div>
<div style="background: linear-gradient(135deg, #ffc107, #e0a800); color: white; padding: 15px; border-radius: 8px; text-align: center;">
<div style="font-size: 2rem; font-weight: 700;"><?php echo e($stats['izin']); ?></div>
<div style="font-size: 0.85rem; opacity: 0.9; margin-top: 5px;"><i class="fas fa-info-circle"></i> Izin</div>
</div>
<div style="background: linear-gradient(135deg, #17a2b8, #138496); color: white; padding: 15px; border-radius: 8px; text-align: center;">
<div style="font-size: 2rem; font-weight: 700;"><?php echo e($stats['sakit']); ?></div>
<div style="font-size: 0.85rem; opacity: 0.9; margin-top: 5px;"><i class="fas fa-heartbeat"></i> Sakit</div>
</div>
<div style="background: linear-gradient(135deg, #dc3545, #c82333); color: white; padding: 15px; border-radius: 8px; text-align: center;">
<div style="font-size: 2rem; font-weight: 700;"><?php echo e($stats['alpa']); ?></div>
<div style="font-size: 0.85rem; opacity: 0.9; margin-top: 5px;"><i class="fas fa-times-circle"></i> Alpa</div>
</div>
<div style="background: linear-gradient(135deg, #6c757d, #5a6268); color: white; padding: 15px; border-radius: 8px; text-align: center;">
<div style="font-size: 2rem; font-weight: 700;"><?php echo e($stats['belum_absen']); ?></div>
<div style="font-size: 0.85rem; opacity: 0.9; margin-top: 5px;"><i class="fas fa-hourglass-half"></i> Belum</div>
</div>
</div>
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-bottom: 14px;">
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
<strong style="color: #2c3e50;">Total Kehadiran</strong>
<strong style="color: <?php echo e($stats['persen_hadir'] >= 85 ? '#28a745' : ($stats['persen_hadir'] >= 70 ? '#ffc107' : '#dc3545')); ?>;">
<?php echo e($stats['hadir']); ?>/<?php echo e($stats['total']); ?> (<?php echo e($stats['persen_hadir']); ?>%)
</strong>
</div>
<div style="height: 30px; background: #e9ecef; border-radius: 15px; overflow: hidden;">
<div style="height: 100%; width: <?php echo e($stats['persen_hadir']); ?>%;
background: <?php echo e($stats['persen_hadir'] >= 85 ? 'linear-gradient(90deg, #28a745, #20c997)' : ($stats['persen_hadir'] >= 70 ? 'linear-gradient(90deg, #ffc107, #fd7e14)' : 'linear-gradient(90deg, #dc3545, #c82333)')); ?>;
display: flex; align-items: center; justify-content: center;
color: white; font-weight: 700; font-size: 0.85rem;">
<?php echo e($stats['persen_hadir']); ?>%
</div>
</div>
</div>
<div>
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
<h5 style="color: #2c3e50; margin: 0;">
<i class="fas fa-users"></i> Daftar Absensi (<?php echo e($absensis->count()); ?> dari <?php echo e($stats['total']); ?> santri)
</h5>
<input type="text" id="searchSantri_<?php echo e($kegiatan->kegiatan_id); ?>"
placeholder="Cari santri..."
style="padding: 8px 12px; border: 1px solid #ddd; border-radius: 6px; width: 200px;"
onkeyup="filterSantri_<?php echo e($kegiatan->kegiatan_id); ?>()">
</div>
<?php if($absensis->count() > 0): ?>
<?php $__currentLoopData = $absensiPerKelas; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $namaKelas => $kelasAbsensis): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div style="margin-bottom: 18px;">
<div style="background: linear-gradient(135deg, #f0f7f4, #e8f5e9); padding: 10px 14px; border-radius: 8px 8px 0 0; display: flex; justify-content: space-between; align-items: center;">
<h6 style="margin: 0; color: #2c6b4f; font-size: 0.9rem;">
<i class="fas fa-school"></i> <?php echo e($namaKelas); ?>
</h6>
<span style="background: #6FBAA5; color: white; padding: 2px 10px; border-radius: 10px; font-size: 0.75rem; font-weight: 600;">
<?php echo e($kelasAbsensis->count()); ?> santri
</span>
</div>
<div style="max-height: 250px; overflow-y: auto; border: 1px solid #e9ecef; border-top: 0; border-radius: 0 0 8px 8px;">
<table style="width: 100%; border-collapse: collapse;">
<thead style="position: sticky; top: 0; background: white; box-shadow: 0 2px 4px rgba(0,0,0,0.05);">
<tr style="border-bottom: 2px solid #e9ecef;">
<th style="padding: 10px; text-align: left; font-size: 0.8rem; color: #6c757d;">No</th>
<th style="padding: 10px; text-align: left; font-size: 0.8rem; color: #6c757d;">ID</th>
<th style="padding: 10px; text-align: left; font-size: 0.8rem; color: #6c757d;">Nama Santri</th>
<th style="padding: 10px; text-align: center; font-size: 0.8rem; color: #6c757d;">Status</th>
<th style="padding: 10px; text-align: center; font-size: 0.8rem; color: #6c757d;">Waktu</th>
<th style="padding: 10px; text-align: center; font-size: 0.8rem; color: #6c757d;">Metode</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $kelasAbsensis; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $absensi): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr class="santri-row-<?php echo e($kegiatan->kegiatan_id); ?>"
style="border-bottom: 1px solid #f1f3f5;"
data-nama="<?php echo e(strtolower($absensi->santri->nama_lengkap)); ?>">
<td style="padding: 8px 10px;"><?php echo e($index + 1); ?></td>
<td style="padding: 8px 10px; font-weight: 600;"><?php echo e($absensi->santri->id_santri); ?></td>
<td style="padding: 8px 10px;"><?php echo e($absensi->santri->nama_lengkap); ?></td>
<td style="padding: 8px 10px; text-align: center;">
<?php if($absensi->status == 'Hadir'): ?>
<span style="background: #d4edda; color: #155724; padding: 4px 10px; border-radius: 12px; font-size: 0.8rem; font-weight: 600;">
<i class="fas fa-check-circle"></i> Hadir
</span>
<?php elseif($absensi->status == 'Izin'): ?>
<span style="background: #fff3cd; color: #856404; padding: 4px 10px; border-radius: 12px; font-size: 0.8rem; font-weight: 600;">
<i class="fas fa-info-circle"></i> Izin
</span>
<?php elseif($absensi->status == 'Sakit'): ?>
<span style="background: #d1ecf1; color: #0c5460; padding: 4px 10px; border-radius: 12px; font-size: 0.8rem; font-weight: 600;">
<i class="fas fa-heartbeat"></i> Sakit
</span>
<?php elseif($absensi->status == 'Pulang'): ?>
<span style="background: #FFF3E0; color: #E65100; padding: 4px 10px; border-radius: 12px; font-size: 0.8rem; font-weight: 600;">
<i class="fas fa-home"></i> Pulang
</span>
<?php else: ?>
<span style="background: #f8d7da; color: #721c24; padding: 4px 10px; border-radius: 12px; font-size: 0.8rem; font-weight: 600;">
<i class="fas fa-times-circle"></i> Alpa
</span>
<?php endif; ?>
</td>
<td style="padding: 8px 10px; text-align: center; font-size: 0.85rem; color: #6c757d;">
<?php echo e($absensi->waktu_absen ? date('H:i', strtotime($absensi->waktu_absen)) : '-'); ?>
</td>
<td style="padding: 8px 10px; text-align: center;">
<?php if($absensi->metode_absen == 'RFID'): ?>
<span style="background: #6FBAA5; color: white; padding: 3px 8px; border-radius: 8px; font-size: 0.75rem;">
<i class="fas fa-id-card"></i> RFID
</span>
<?php elseif($absensi->metode_absen == 'Import_Mesin'): ?>
<span style="background: #7c3aed; color: white; padding: 3px 8px; border-radius: 8px; font-size: 0.75rem;">
<i class="fas fa-desktop"></i> Mesin
</span>
<?php else: ?>
<span style="background: #6c757d; color: white; padding: 3px 8px; border-radius: 8px; font-size: 0.75rem;">
<i class="fas fa-hand-pointer"></i> Manual
</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<?php else: ?>
<div style="text-align: center; padding: 22px; background: #f8f9fa; border-radius: 8px;">
<i class="fas fa-inbox" style="font-size: 2.2rem; color: #cbd5e0; margin-bottom: 15px;"></i>
<p style="color: #6c757d; margin: 0;">Belum ada absensi untuk kegiatan ini.</p>
</div>
<?php endif; ?>
</div>
<?php if(isset($santriBelumAbsen) && $santriBelumAbsen->count() > 0): ?>
<div style="margin-top: 18px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<h5 style="color: #d97706; margin: 0;">
<i class="fas fa-exclamation-triangle"></i> Santri Belum Absen (<?php echo e($santriBelumAbsen->count()); ?> orang)
</h5>
</div>
<?php $__currentLoopData = $santriBelumAbsenPerKelas; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $namaKelas => $kelasSantris): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div style="margin-bottom: 12px;">
<div style="background: linear-gradient(135deg, #fef3c7, #fef9c3); padding: 8px 14px; border-radius: 8px 8px 0 0; display: flex; justify-content: space-between; align-items: center;">
<h6 style="margin: 0; color: #92400e; font-size: 0.9rem;">
<i class="fas fa-school"></i> <?php echo e($namaKelas); ?>
</h6>
<span style="background: #f59e0b; color: white; padding: 2px 10px; border-radius: 10px; font-size: 0.75rem; font-weight: 600;">
<?php echo e($kelasSantris->count()); ?> santri
</span>
</div>
<div style="max-height: 200px; overflow-y: auto; border: 1px solid #fde68a; border-top: 0; border-radius: 0 0 8px 8px;">
<table style="width: 100%; border-collapse: collapse;">
<thead style="position: sticky; top: 0; background: white; box-shadow: 0 2px 4px rgba(0,0,0,0.05);">
<tr style="border-bottom: 2px solid #fde68a;">
<th style="padding: 8px; text-align: left; font-size: 0.8rem; color: #6c757d;">No</th>
<th style="padding: 8px; text-align: left; font-size: 0.8rem; color: #6c757d;">ID</th>
<th style="padding: 8px; text-align: left; font-size: 0.8rem; color: #6c757d;">Nama Santri</th>
<th style="padding: 8px; text-align: center; font-size: 0.8rem; color: #6c757d;">Status</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $kelasSantris; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $idx => $santri): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr style="border-bottom: 1px solid #fef3c7;">
<td style="padding: 6px 8px; font-size: 0.85rem;"><?php echo e($idx + 1); ?></td>
<td style="padding: 6px 8px; font-size: 0.85rem; font-weight: 600;"><?php echo e($santri->id_santri); ?></td>
<td style="padding: 6px 8px; font-size: 0.85rem;"><?php echo e($santri->nama_lengkap); ?></td>
<td style="padding: 6px 8px; text-align: center;">
<span style="background: #fef3c7; color: #92400e; padding: 3px 8px; border-radius: 10px; font-size: 0.75rem; font-weight: 600;">
<i class="fas fa-hourglass-half"></i> Belum
</span>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
<?php endif; ?>
<div style="margin-top: 25px; padding-top: 20px; border-top: 2px solid #e9ecef; display: flex; gap: 10px; justify-content: flex-end;">
<a href="<?php echo e(route('admin.absensi-kegiatan.input', $kegiatan->kegiatan_id)); ?>?tanggal=<?php echo e($tanggal); ?>"
class="btn btn-primary">
<i class="fas fa-clipboard-check"></i> Input Absensi
</a>
<a href="<?php echo e(route('admin.riwayat-kegiatan.index')); ?>?kegiatan_id=<?php echo e($kegiatan->kegiatan_id); ?>&tanggal=<?php echo e($tanggal); ?>"
class="btn btn-info">
<i class="fas fa-chart-bar"></i> Lihat Rekap Lengkap
</a>
<button class="btn btn-secondary" onclick="closeModal()">
<i class="fas fa-times"></i> Tutup
</button>
</div>
</div>
<script>
function filterSantri_<?php echo e($kegiatan->kegiatan_id); ?>() {
var val = document.getElementById('searchSantri_<?php echo e($kegiatan->kegiatan_id); ?>').value.toLowerCase();
var rows = document.querySelectorAll('.santri-row-<?php echo e($kegiatan->kegiatan_id); ?>');
rows.forEach(function(row) {
row.style.display = (row.getAttribute('data-nama') || '').includes(val) ? '' : 'none';
});
}
</script><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kegiatan/data/partials/detail-modal.blade.php ENDPATH**/ ?>

View File

@ -1,115 +0,0 @@

<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-id-card"></i> Kelola Kartu RFID Santri</h2>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger">
<i class="fas fa-exclamation-circle"></i> <?php echo e(session('error')); ?>
</div>
<?php endif; ?>
<div class="content-box">
<div style="margin-bottom: 14px;">
<form method="GET" class="filter-form-inline">
<select name="filter" class="form-control">
<option value="">-- Semua Santri --</option>
<option value="ada_rfid" <?php echo e(request('filter') == 'ada_rfid' ? 'selected' : ''); ?>>Sudah Punya RFID</option>
<option value="belum_rfid" <?php echo e(request('filter') == 'belum_rfid' ? 'selected' : ''); ?>>Belum Punya RFID</option>
</select>
<button type="submit" class="btn btn-primary">
<i class="fas fa-filter"></i> Filter
</button>
<?php if(request('filter')): ?>
<a href="<?php echo e(route('admin.kartu-rfid.index')); ?>" class="btn btn-secondary">
<i class="fas fa-times"></i> Reset
</a>
<?php endif; ?>
</form>
</div>
<?php if($santris->count() > 0): ?>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">No</th>
<th style="width: 100px;">ID Santri</th>
<th>Nama Santri</th>
<th style="width: 100px;">Kelas</th>
<th style="width: 200px;">UID RFID</th>
<th style="width: 120px; text-align: center;">Status</th>
<th style="width: 250px; text-align: center;">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $santris; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $santri): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($santris->firstItem() + $index); ?></td>
<td><strong><?php echo e($santri->id_santri); ?></strong></td>
<td><?php echo e($santri->nama_lengkap); ?></td>
<td><span class="badge badge-secondary"><?php echo e($santri->kelasSantri->first()?->kelas?->nama_kelas ?? '-'); ?></span></td>
<td>
<?php if($santri->rfid_uid): ?>
<code style="font-size: 0.85rem;"><?php echo e($santri->rfid_uid); ?></code>
<?php else: ?>
<span style="color: var(--text-light);">-</span>
<?php endif; ?>
</td>
<td class="text-center">
<?php if($santri->rfid_uid): ?>
<span class="badge badge-success"><i class="fas fa-check"></i> Terdaftar</span>
<?php else: ?>
<span class="badge badge-warning"><i class="fas fa-exclamation"></i> Belum</span>
<?php endif; ?>
</td>
<td class="text-center">
<?php if($santri->rfid_uid): ?>
<a href="<?php echo e(route('admin.kartu-rfid.cetak', $santri->id_santri)); ?>" class="btn btn-sm btn-primary" title="Cetak Kartu" target="_blank">
<i class="fas fa-print"></i> Cetak
</a>
<form action="<?php echo e(route('admin.kartu-rfid.hapus', $santri->id_santri)); ?>" method="POST" style="display: inline-block;" onsubmit="return confirm('Yakin ingin menghapus RFID ini?')">
<?php echo csrf_field(); ?>
<?php echo method_field('DELETE'); ?>
<button type="submit" class="btn btn-sm btn-danger" title="Hapus RFID">
<i class="fas fa-trash"></i> Hapus
</button>
</form>
<?php else: ?>
<a href="<?php echo e(route('admin.kartu-rfid.daftar', $santri->id_santri)); ?>" class="btn btn-sm btn-success" title="Daftarkan RFID">
<i class="fas fa-id-card"></i> Daftarkan RFID
</a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<div style="margin-top: 14px;">
<?php echo e($santris->links()); ?>
</div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-users-slash"></i>
<h3>Tidak Ada Data Santri</h3>
<p>Belum ada santri aktif yang terdaftar.</p>
</div>
<?php endif; ?>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kegiatan/kartu/index.blade.php ENDPATH**/ ?>

View File

@ -0,0 +1,168 @@
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Laporan Pembayaran SPP</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: Arial, sans-serif; padding: 20px; font-size: 12px; }
.header { text-align: center; margin-bottom: 30px; border-bottom: 3px solid #333; padding-bottom: 15px; }
.header h1 { font-size: 20px; margin-bottom: 5px; }
.header h2 { font-size: 16px; color: #666; margin-bottom: 10px; }
.header p { font-size: 11px; color: #888; }
.info-box { background: #f5f5f5; padding: 15px; margin-bottom: 20px; border-radius: 5px; }
.info-box table { width: 100%; }
.info-box td { padding: 5px; }
.info-box td:first-child { font-weight: bold; width: 150px; }
.stats { display: flex; justify-content: space-around; margin-bottom: 20px; }
.stat-card { text-align: center; flex: 1; padding: 15px; background: #f9f9f9; border-radius: 5px; margin: 0 5px; }
.stat-card h3 { font-size: 11px; color: #666; margin-bottom: 8px; }
.stat-card .value { font-size: 18px; font-weight: bold; color: #333; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
th, td { padding: 10px; text-align: left; border: 1px solid #ddd; }
th { background: #6FBA9D; color: white; font-weight: bold; }
tr:nth-child(even) { background: #f9f9f9; }
.text-center { text-align: center; }
.text-right { text-align: right; }
.badge { padding: 4px 8px; border-radius: 3px; font-size: 10px; font-weight: bold; }
.badge-success { background: #d4edda; color: #155724; }
.badge-warning { background: #fff3cd; color: #856404; }
.badge-danger { background: #f8d7da; color: #721c24; }
.footer { margin-top: 30px; text-align: center; font-size: 10px; color: #888; border-top: 1px solid #ddd; padding-top: 10px; }
@media print {
body { padding: 0; }
.no-print { display: none; }
@page { margin: 1cm; }
}
</style>
</head>
<body>
<!-- Tombol Print -->
<div class="no-print" style="margin-bottom: 20px; text-align: right;">
<button onclick="window.print()" style="padding: 10px 20px; background: #6FBA9D; color: white; border: none; border-radius: 5px; cursor: pointer;">
<i class="fas fa-print"></i> Cetak Laporan
</button>
</div>
<!-- Header -->
<div class="header">
<h1>PKPPS RIYADLUL JANNAH</h1>
<h2>LAPORAN PEMBAYARAN SPP</h2>
<p>Tanggal Cetak: <?php echo e(date('d F Y')); ?> WIB</p>
</div>
<!-- Info Filter -->
<?php if(request()->has('bulan') || request()->has('tahun') || request()->has('status')): ?>
<div class="info-box">
<table>
<?php if(request()->filled('bulan')): ?>
<tr>
<td>Bulan</td>
<td>: <?php echo e(DateTime::createFromFormat('!m', request('bulan'))->format('F')); ?></td>
</tr>
<?php endif; ?>
<?php if(request()->filled('tahun')): ?>
<tr>
<td>Tahun</td>
<td>: <?php echo e(request('tahun')); ?></td>
</tr>
<?php endif; ?>
<?php if(request()->filled('status')): ?>
<tr>
<td>Status</td>
<td>: <?php echo e(request('status')); ?></td>
</tr>
<?php endif; ?>
</table>
</div>
<?php endif; ?>
<!-- Statistik -->
<div class="stats">
<div class="stat-card">
<h3>Total Terbayar</h3>
<div class="value" style="color: #28a745;">Rp <?php echo e(number_format($totalLunas, 0, ',', '.')); ?></div>
</div>
<div class="stat-card">
<h3>Total Tunggakan</h3>
<div class="value" style="color: #dc3545;">Rp <?php echo e(number_format($totalTunggakan, 0, ',', '.')); ?></div>
</div>
<div class="stat-card">
<h3>Pembayaran Telat</h3>
<div class="value" style="color: #ffc107;"><?php echo e($jumlahTelat); ?></div>
</div>
<div class="stat-card">
<h3>Total Data</h3>
<div class="value" style="color: #17a2b8;"><?php echo e($pembayaranSpp->count()); ?></div>
</div>
</div>
<!-- Tabel Data -->
<table>
<thead>
<tr>
<th width="5%">No</th>
<th width="10%">ID</th>
<th width="20%">Santri</th>
<th width="15%">Periode</th>
<th width="15%">Nominal</th>
<th width="12%">Batas Bayar</th>
<th width="12%">Tgl Bayar</th>
<th width="11%">Status</th>
</tr>
</thead>
<tbody>
<?php $__empty_1 = true; $__currentLoopData = $pembayaranSpp; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $spp): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
<tr>
<td class="text-center"><?php echo e($index + 1); ?></td>
<td><?php echo e($spp->id_pembayaran); ?></td>
<td>
<strong><?php echo e($spp->santri->nama_lengkap); ?></strong><br>
<small style="color: #666;"><?php echo e($spp->santri->id_santri); ?></small>
</td>
<td><?php echo e($spp->periode_lengkap); ?></td>
<td class="text-right"><strong><?php echo e($spp->nominal_format); ?></strong></td>
<td class="text-center"><?php echo e($spp->batas_bayar->format('d/m/Y')); ?></td>
<td class="text-center">
<?php if($spp->tanggal_bayar): ?>
<?php echo e($spp->tanggal_bayar->format('d/m/Y')); ?>
<?php else: ?>
<span style="color: #999;">-</span>
<?php endif; ?>
</td>
<td class="text-center">
<?php if($spp->status === 'Lunas'): ?>
<span class="badge badge-success">Lunas</span>
<?php elseif($spp->isTelat()): ?>
<span class="badge badge-danger">Telat</span>
<?php else: ?>
<span class="badge badge-warning">Belum Lunas</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
<tr>
<td colspan="8" class="text-center" style="padding: 30px; color: #999;">
Tidak ada data pembayaran SPP
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
<script>
// Auto print saat load (opsional)
// window.onload = function() { window.print(); }
</script>
</body>
</html><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/pembayaran-spp/cetak-laporan.blade.php ENDPATH**/ ?>

View File

@ -1,272 +0,0 @@
<?php $__env->startSection('title', 'Riwayat Kesehatan'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-heartbeat"></i> Riwayat Kesehatan</h2>
<p style="margin: 4px 0 0 0; color: var(--text-light);">
Kunjungan UKP <strong><?php echo e($santri->nama_lengkap); ?></strong>
</p>
</div>
<?php if($sedangDirawatSekarang): ?>
<div style="
background: linear-gradient(135deg, #E74C3C, #C0392B);
color: white; padding: 16px 20px; border-radius: 12px;
margin-bottom: 18px; display: flex; align-items: center; gap: 14px;
box-shadow: 0 4px 18px rgba(231,76,60,0.4); animation: alertPulse 2.5s infinite;">
<div style="background: rgba(255,255,255,0.2); width: 52px; height: 52px; border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-shrink: 0;">
<i class="fas fa-procedures" style="font-size: 1.5rem;"></i>
</div>
<div style="flex: 1; min-width: 0;">
<strong style="font-size: 1.05rem; display: block;">⚠️ Kamu Sedang Dalam Perawatan UKP</strong>
<span style="font-size: 0.85rem; opacity: 0.9; display: block; margin-top: 2px;">
Masuk sejak <?php echo e($sedangDirawatSekarang->tanggal_masuk->locale('id')->isoFormat('D MMMM Y')); ?>
&bull; Hari ke-<?php echo e($sedangDirawatSekarang->lama_dirawat); ?>
&bull; <?php echo e(Str::limit($sedangDirawatSekarang->keluhan, 55)); ?>
</span>
</div>
<a href="<?php echo e(route('santri.kesehatan.show', $sedangDirawatSekarang->id)); ?>"
style="background: rgba(255,255,255,0.2); color: white; padding: 8px 14px; border-radius: 8px;
text-decoration: none; font-size: 0.82rem; white-space: nowrap; border: 1px solid rgba(255,255,255,0.35); flex-shrink: 0;"
onmouseover="this.style.background='rgba(255,255,255,0.35)';"
onmouseout="this.style.background='rgba(255,255,255,0.2)';">
<i class="fas fa-eye"></i> Lihat Detail
</a>
</div>
<?php endif; ?>
<?php if($errors->any()): ?>
<div class="alert alert-danger">
<i class="fas fa-exclamation-triangle"></i> <?php echo e($errors->first()); ?>
</div>
<?php endif; ?>
<div class="row-cards">
<div class="card card-info">
<h3><i class="fas fa-notes-medical"></i> Total Kunjungan</h3>
<div class="card-value"><?php echo e($statistik['total_kunjungan']); ?></div>
<div class="card-icon"><i class="fas fa-notes-medical"></i></div>
<p style="margin-top: 8px; font-size: 0.82rem; color: var(--text-light);">Periode dipilih</p>
</div>
<div class="card card-danger">
<h3><i class="fas fa-procedures"></i> Sedang Dirawat</h3>
<div class="card-value"><?php echo e($statistik['sedang_dirawat']); ?></div>
<div class="card-icon"><i class="fas fa-procedures"></i></div>
<p style="margin-top: 8px; font-size: 0.82rem; color: <?php echo e($statistik['sedang_dirawat'] > 0 ? 'var(--danger-color)' : 'var(--text-light)'); ?>;">
<?php echo e($statistik['sedang_dirawat'] > 0 ? '⚠️ Perlu perhatian' : 'Tidak ada'); ?>
</p>
</div>
<div class="card card-success">
<h3><i class="fas fa-check-circle"></i> Sembuh</h3>
<div class="card-value"><?php echo e($statistik['sembuh']); ?></div>
<div class="card-icon"><i class="fas fa-check-circle"></i></div>
<p style="margin-top: 8px; font-size: 0.82rem; color: var(--text-light);">Alhamdulillah</p>
</div>
<div class="card card-warning">
<h3><i class="fas fa-home"></i> Izin Sakit</h3>
<div class="card-value"><?php echo e($statistik['izin']); ?></div>
<div class="card-icon"><i class="fas fa-home"></i></div>
<p style="margin-top: 8px; font-size: 0.82rem; color: var(--text-light);">Izin pulang</p>
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 14px;">
<div style="background: linear-gradient(135deg, #E8F7F2, #D4F1E3); padding: 16px; border-radius: 12px; border-left: 4px solid #6FBA9D; display: flex; align-items: center; gap: 14px;">
<i class="fas fa-history" style="font-size: 2rem; color: #6FBA9D; flex-shrink: 0;"></i>
<div>
<p style="margin: 0; font-size: 0.82rem; color: var(--text-light);">Total Kunjungan Semua Waktu</p>
<p style="margin: 0; font-size: 1.7rem; font-weight: 700; color: #2C5F4F; line-height: 1.1;"><?php echo e($totalAllTime); ?> <span style="font-size: 1rem;">kali</span></p>
</div>
</div>
<div style="background: linear-gradient(135deg, #FFF8E1, #FFF3CD); padding: 16px; border-radius: 12px; border-left: 4px solid #FFD56B; display: flex; align-items: center; gap: 14px;">
<i class="fas fa-bed" style="font-size: 2rem; color: #F39C12; flex-shrink: 0;"></i>
<div>
<p style="margin: 0; font-size: 0.82rem; color: var(--text-light);">Total Hari Dirawat Semua Waktu</p>
<p style="margin: 0; font-size: 1.7rem; font-weight: 700; color: #7D5A00; line-height: 1.1;"><?php echo e($totalHariDirawat); ?> <span style="font-size: 1rem;">hari</span></p>
</div>
</div>
</div>
<div class="content-box" style="margin-bottom: 14px;">
<form method="GET" action="<?php echo e(route('santri.kesehatan.index')); ?>" id="filterForm">
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr auto; gap: 11px; align-items: end;">
<div class="form-group" style="margin-bottom: 0;">
<label style="display: block; font-size: 0.82rem; font-weight: 600; margin-bottom: 6px;">
<i class="fas fa-calendar-alt form-icon"></i> Tanggal Dari
</label>
<input type="date" name="tanggal_dari" class="form-control"
value="<?php echo e($tanggalDari->format('Y-m-d')); ?>" max="<?php echo e(date('Y-m-d')); ?>">
</div>
<div class="form-group" style="margin-bottom: 0;">
<label style="display: block; font-size: 0.82rem; font-weight: 600; margin-bottom: 6px;">
<i class="fas fa-calendar-check form-icon"></i> Tanggal Sampai
</label>
<input type="date" name="tanggal_sampai" class="form-control"
value="<?php echo e($tanggalSampai->format('Y-m-d')); ?>" max="<?php echo e(date('Y-m-d')); ?>">
</div>
<div class="form-group" style="margin-bottom: 0;">
<label style="display: block; font-size: 0.82rem; font-weight: 600; margin-bottom: 6px;">
<i class="fas fa-filter form-icon"></i> Status
</label>
<select name="status" class="form-control">
<option value="">Semua Status</option>
<?php $__currentLoopData = $statusOptions; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $value => $label): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($value); ?>" <?php echo e(request('status') == $value ? 'selected' : ''); ?>><?php echo e($label); ?></option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div style="display: flex; gap: 8px;">
<button type="submit" class="btn btn-primary hover-lift">
<i class="fas fa-search"></i> Filter
</button>
<a href="<?php echo e(route('santri.kesehatan.index')); ?>" class="btn btn-secondary hover-lift">
<i class="fas fa-sync"></i>
</a>
</div>
</div>
</form>
<p style="margin: 11px 0 0 0; color: var(--text-light); font-size: 0.82rem;">
<i class="fas fa-info-circle"></i>
Periode: <strong style="color: var(--primary-color);">
<?php echo e($tanggalDari->locale('id')->isoFormat('D MMMM Y')); ?> — <?php echo e($tanggalSampai->locale('id')->isoFormat('D MMMM Y')); ?>
</strong>
(<?php echo e($tanggalDari->diffInDays($tanggalSampai) + 1); ?> hari)
</p>
</div>
<?php if($riwayatKesehatan->isEmpty()): ?>
<div class="empty-state" style="margin-top: 14px;">
<i class="fas fa-notes-medical"></i>
<h3>Tidak Ada Data</h3>
<p>Tidak ada riwayat kesehatan pada periode yang dipilih.</p>
<a href="<?php echo e(route('santri.kesehatan.index')); ?>" class="btn btn-primary" style="margin-top: 14px;">
<i class="fas fa-sync"></i> Lihat Semua Data
</a>
</div>
<?php else: ?>
<div class="content-box" style="margin-top: 14px;">
<h3 style="margin: 0 0 14px 0; color: var(--primary-color);">
<i class="fas fa-list"></i> Daftar Riwayat
<span style="color: var(--text-light); font-weight: 400; font-size: 0.9rem;">(<?php echo e($riwayatKesehatan->total()); ?> data)</span>
</h3>
<div style="display: flex; flex-direction: column; gap: 10px;">
<?php $__currentLoopData = $riwayatKesehatan; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$bColor = match($item->status) { 'dirawat' => '#E74C3C', 'sembuh' => '#6FBA9D', default => '#F39C12' };
$iBg = match($item->status) { 'dirawat' => 'linear-gradient(135deg,#FFE8EA,#FFD5D8)', 'sembuh' => 'linear-gradient(135deg,#E8F7F2,#D4F1E3)', default => 'linear-gradient(135deg,#FFF8E1,#FFF3CD)' };
$ico = match($item->status) { 'dirawat' => 'fa-procedures', 'sembuh' => 'fa-check-circle', default => 'fa-home' };
?>
<a href="<?php echo e(route('santri.kesehatan.show', $item->id)); ?>"
style="display:flex; gap:14px; padding:14px 16px; background:white; border-radius:10px; border-left:4px solid <?php echo e($bColor); ?>; text-decoration:none; box-shadow:0 2px 8px rgba(0,0,0,0.06); transition:all 0.2s;"
onmouseover="this.style.transform='translateX(5px)'; this.style.boxShadow='0 4px 16px rgba(0,0,0,0.12)';"
onmouseout="this.style.transform=''; this.style.boxShadow='0 2px 8px rgba(0,0,0,0.06)';">
<div style="flex-shrink:0; width:54px; height:54px; border-radius:50%; background:<?php echo e($iBg); ?>; display:flex; align-items:center; justify-content:center;">
<i class="fas <?php echo e($ico); ?>" style="font-size:1.5rem; color:<?php echo e($bColor); ?>;"></i>
</div>
<div style="flex:1; min-width:0;">
<div style="display:flex; justify-content:space-between; align-items:flex-start; margin-bottom:5px;">
<strong style="color:var(--text-color); font-size:0.95rem;"><?php echo e(Str::limit($item->keluhan, 65)); ?></strong>
<span class="badge badge-<?php echo e($item->status_badge_color); ?>" style="margin-left:8px; flex-shrink:0;"><?php echo e(ucfirst($item->status)); ?></span>
</div>
<div style="display:flex; flex-wrap:wrap; gap:10px; font-size:0.8rem; color:var(--text-light);">
<span><i class="fas fa-calendar-plus"></i> <?php echo e($item->tanggal_masuk_formatted); ?></span>
<?php if($item->tanggal_keluar): ?>
<span><i class="fas fa-calendar-check"></i> Keluar: <?php echo e($item->tanggal_keluar_formatted); ?></span>
<?php endif; ?>
<?php if($item->status === 'dirawat'): ?>
<span class="badge badge-danger badge-sm"><i class="fas fa-clock"></i> Hari ke-<?php echo e($item->lama_dirawat); ?></span>
<?php else: ?>
<span class="badge badge-info badge-sm"><i class="fas fa-clock"></i> <?php echo e($item->lama_dirawat); ?> hari</span>
<?php endif; ?>
<span style="color:#ccc; font-size:0.75rem;"><?php echo e($item->id_kesehatan); ?></span>
</div>
</div>
<div style="flex-shrink:0; align-self:center;">
<i class="fas fa-chevron-right" style="color:var(--text-light); font-size:0.8rem;"></i>
</div>
</a>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
<div style="margin-top: 18px;">
<?php echo e($riwayatKesehatan->links()); ?>
</div>
</div>
<?php endif; ?>
<div class="info-box" style="margin-top: 14px;">
<i class="fas fa-info-circle"></i>
<strong>Info:</strong> Default menampilkan data bulan berjalan. Gunakan filter untuk melihat periode lain.
</div>
<?php if($dataGrafik->count() > 0): ?>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script>
const dataGrafik = <?php echo json_encode($dataGrafik, 15, 512) ?>;
new Chart(document.getElementById('chartKesehatan').getContext('2d'), {
type: 'bar',
data: {
labels: dataGrafik.map(d => d.label),
datasets: [
{ label: 'Sembuh', data: dataGrafik.map(d => d.sembuh), backgroundColor: 'rgba(111,186,157,0.85)', borderRadius: 5, borderSkipped: false },
{ label: 'Izin', data: dataGrafik.map(d => d.izin), backgroundColor: 'rgba(255,213,107,0.85)', borderRadius: 5, borderSkipped: false },
{ label: 'Dirawat', data: dataGrafik.map(d => d.dirawat), backgroundColor: 'rgba(231,76,60,0.85)', borderRadius: 5, borderSkipped: false },
]
},
options: {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: { position: 'top' },
tooltip: {
callbacks: { afterBody: items => `Total: ${dataGrafik[items[0].dataIndex].total} kunjungan` }
}
},
scales: {
x: { stacked: true, grid: { display: false } },
y: { stacked: true, beginAtZero: true, ticks: { stepSize: 1 } }
}
}
});
</script>
<?php endif; ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
const dari = document.querySelector('input[name="tanggal_dari"]');
const sampai = document.querySelector('input[name="tanggal_sampai"]');
dari.addEventListener('change', () => { if (sampai.value && sampai.value < dari.value) sampai.value = dari.value; });
sampai.addEventListener('change', function() {
if (dari.value && this.value < dari.value) {
alert('Tanggal sampai tidak boleh lebih kecil dari tanggal dari!');
this.value = dari.value;
}
});
});
</script>
<style>
@keyframes alertPulse {
0%, 100% { box-shadow: 0 4px 18px rgba(231,76,60,0.4); }
50% { box-shadow: 0 4px 28px rgba(231,76,60,0.75); }
}
</style>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/santri/kesehatan/index.blade.php ENDPATH**/ ?>

View File

@ -1,179 +0,0 @@

<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-chart-line"></i> Data Capaian Santri</h2>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger">
<i class="fas fa-exclamation-circle"></i> <?php echo e(session('error')); ?>
</div>
<?php endif; ?>
<div class="content-box" style="margin-bottom: 14px;">
<div style="display: flex; gap: 10px; flex-wrap: wrap; align-items: center;">
<a href="<?php echo e(route('admin.capaian.create')); ?>" class="btn btn-success" style="padding: 9px 18px;">
<i class="fas fa-plus"></i> Input Capaian
</a>
<a href="<?php echo e(route('admin.capaian.akses-santri')); ?>" class="btn btn-primary" style="padding: 9px 18px;">
<i class="fas fa-unlock-alt"></i> Kelola Akses Input Santri
</a>
</div>
</div>
<div class="content-box" style="margin-bottom: 14px;">
<form method="GET" action="<?php echo e(route('admin.capaian.index')); ?>" class="filter-form-inline">
<div style="display: flex; gap: 10px; flex-wrap: wrap; align-items: center;">
<select name="id_kelas" class="form-control" style="width: 220px;" onchange="this.form.submit()">
<option value="">Semua Kelas</option>
<?php
$kelompokGrouped = $kelasList->groupBy(fn($k) => $k->kelompok->nama_kelompok ?? 'Lainnya');
?>
<?php $__currentLoopData = $kelompokGrouped; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $namaKelompok => $kelasGroup): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<optgroup label="<?php echo e($namaKelompok); ?>">
<?php $__currentLoopData = $kelasGroup; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kls): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($kls->id); ?>" <?php echo e($selectedKelas == $kls->id ? 'selected' : ''); ?>>
<?php echo e($kls->nama_kelas); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</optgroup>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
<select name="id_semester" class="form-control" style="width: 250px;">
<?php $__currentLoopData = $semesters; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $semester): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($semester->id_semester); ?>" <?php echo e($selectedSemester == $semester->id_semester ? 'selected' : ''); ?>>
<?php echo e($semester->nama_semester); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
<input type="text" name="search" class="form-control" placeholder="Cari nama santri / NIS..."
value="<?php echo e($search ?? ''); ?>" style="width: 300px;">
<button type="submit" class="btn btn-primary">
<i class="fas fa-search"></i> Filter
</button>
<?php if($selectedKelas || $search): ?>
<a href="<?php echo e(route('admin.capaian.index', ['id_semester' => $selectedSemester])); ?>" class="btn btn-secondary">
<i class="fas fa-redo"></i> Reset
</a>
<?php endif; ?>
</div>
</form>
</div>
<div class="content-box">
<?php if($selectedKelas): ?>
<?php $selectedKelasObj = $kelasList->firstWhere('id', $selectedKelas); ?>
<div style="margin-bottom: 15px; padding: 12px 15px; background: #e3f2fd; border-left: 4px solid #2196F3; border-radius: 4px;">
<span style="color: #1976D2; font-weight: 600;">
<i class="fas fa-filter"></i> Menampilkan data kelas: <strong><?php echo e($selectedKelasObj->nama_kelas ?? 'Unknown'); ?></strong>
<?php if($selectedKelasObj && $selectedKelasObj->kelompok): ?>
(<?php echo e($selectedKelasObj->kelompok->nama_kelompok); ?>)
<?php endif; ?>
</span>
</div>
<?php endif; ?>
<?php if($santriData->count() > 0): ?>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 5%;">No</th>
<th style="width: 15%;">NIS</th>
<th style="width: 30%;">Nama Santri</th>
<th style="width: 10%;">Kelas</th>
<th style="width: 15%;">Total Materi</th>
<th style="width: 15%;">Total Progress</th>
<th class="text-center" style="width: 10%;">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $santriData; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $data): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($index + 1); ?></td>
<td><strong><?php echo e($data['santri']->nis); ?></strong></td>
<td><?php echo e($data['santri']->nama_lengkap); ?></td>
<td>
<span class="badge badge-secondary"><?php echo e($data['santri']->kelas); ?></span>
</td>
<td class="text-center">
<span class="badge badge-info"><?php echo e($data['total_materi']); ?> materi</span>
</td>
<td>
<?php
$progress = $data['total_progress'];
if ($progress >= 100) {
$badgeClass = 'badge-success';
$icon = 'fa-check-circle';
} elseif ($progress >= 75) {
$badgeClass = 'badge-primary';
$icon = 'fa-battery-three-quarters';
} elseif ($progress >= 50) {
$badgeClass = 'badge-warning';
$icon = 'fa-battery-half';
} elseif ($progress >= 25) {
$badgeClass = 'badge-danger';
$icon = 'fa-battery-quarter';
} else {
$badgeClass = 'badge-secondary';
$icon = 'fa-battery-empty';
}
?>
<span class="badge <?php echo e($badgeClass); ?>">
<i class="fas <?php echo e($icon); ?>"></i> <?php echo e(number_format($progress, 2)); ?>%
</span>
</td>
<td class="text-center">
<a href="<?php echo e(route('admin.capaian.riwayat-santri', ['id_santri' => $data['santri']->id_santri, 'id_semester' => $selectedSemester])); ?>"
class="btn btn-sm btn-primary" title="Lihat Detail Capaian">
<i class="fas fa-eye"></i> Show
</a>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-inbox"></i>
<h3>Tidak Ada Data</h3>
<p>
<?php if($search): ?>
Tidak ditemukan santri dengan kata kunci "<strong><?php echo e($search); ?></strong>".
<?php else: ?>
Belum ada santri dengan data capaian.
<?php endif; ?>
</p>
<?php if($search || $selectedKelas): ?>
<a href="<?php echo e(route('admin.capaian.index')); ?>" class="btn btn-secondary">
<i class="fas fa-redo"></i> Reset Filter
</a>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/capaian/index.blade.php ENDPATH**/ ?>

View File

@ -1,290 +0,0 @@

<?php $__env->startSection('title', 'Kenaikan Kelas Massal'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header" style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px;">
<div>
<h2><i class="fas fa-graduation-cap"></i> Kenaikan Kelas Massal</h2>
<p class="text-muted" style="margin: 0;">Kelola kenaikan kelas santri per tahun ajaran</p>
</div>
<a href="<?php echo e(route('admin.kelas.index')); ?>" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali ke Kelola Kelas
</a>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="fas fa-exclamation-circle"></i> <?php echo e(session('error')); ?>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<?php endif; ?>
<!-- Info Card -->
<div class="content-box" style="margin-bottom: 14px;">
<div class="row-cards">
<div class="card card-info">
<h3>Tahun Ajaran Aktif</h3>
<div class="card-value"><?php echo e($tahunAjaranAktif); ?></div>
<p class="text-muted" style="margin: 0;">Tahun ajaran saat ini</p>
</div>
<div class="card card-success">
<h3>Total Santri Aktif</h3>
<div class="card-value"><?php echo e($totalSantriAktif); ?></div>
<p class="text-muted" style="margin: 0;">Santri dengan status aktif</p>
</div>
<div class="card card-warning">
<h3>Tahun Ajaran Baru</h3>
<div class="card-value" style="font-size: 1.8rem;"><?php echo e($tahunAjaranBaru); ?></div>
<p class="text-muted" style="margin: 0;">Target kenaikan kelas</p>
</div>
</div>
</div>
<!-- Filter by Kelompok -->
<div class="content-box" style="margin-bottom: 14px;">
<form method="GET" action="<?php echo e(route('admin.kelas.kenaikan.index')); ?>" style="display: flex; gap: 10px; flex-wrap: wrap; align-items: center;">
<label style="margin: 0; font-weight: 600; color: var(--primary-dark);">
<i class="fas fa-filter"></i> Pilih Kelompok Kelas:
</label>
<select name="kelompok" class="form-control" style="max-width: 300px;" onchange="this.form.submit()">
<?php $__currentLoopData = $kelompokKelas; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelompok): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($kelompok->id_kelompok); ?>"
<?php echo e($selectedKelompok == $kelompok->id_kelompok ? 'selected' : ''); ?>>
<?php echo e($kelompok->nama_kelompok); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</form>
</div>
<?php if($kelasList->isNotEmpty()): ?>
<?php
$currentKelompok = $kelompokKelas->where('id_kelompok', $selectedKelompok)->first();
?>
<div class="content-box" style="margin-bottom: 25px;">
<div style="background: linear-gradient(135deg, #E8F7F2 0%, #D4F1E3 100%); padding: 14px; border-radius: 8px; margin-bottom: 14px;">
<h3 style="margin: 0 0 8px 0; color: var(--primary-dark);">
<i class="fas fa-layer-group"></i>
<?php echo e($currentKelompok->nama_kelompok ?? 'Kelas'); ?>
</h3>
<p style="margin: 0; color: var(--text-light); font-size: 0.95rem;">
<?php echo e($currentKelompok->deskripsi ?? 'Kelola kenaikan kelas untuk kelompok ini'); ?>
</p>
</div>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">No</th>
<th>Kelas Asal</th>
<th style="width: 140px; text-align: center;">Santri Aktif</th>
<th style="width: 280px;">Naik ke Kelas</th>
<th style="width: 200px; text-align: center;">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $kelasList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelas): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($loop->iteration); ?></td>
<td>
<strong style="color: var(--primary-dark);"><?php echo e($kelas->nama_kelas); ?></strong>
<br>
<span class="text-muted" style="font-size: 0.85rem;">
<i class="fas fa-tag"></i> <?php echo e($kelas->kode_kelas); ?>
</span>
</td>
<td style="text-align: center;">
<?php if($kelas->santri_aktif_count > 0): ?>
<span class="badge badge-info" style="font-size: 0.95rem; padding: 8px 14px;">
<i class="fas fa-users"></i> <?php echo e($kelas->santri_aktif_count); ?> santri
</span>
<?php else: ?>
<span class="badge badge-secondary" style="font-size: 0.9rem; padding: 7px 12px;">
<i class="fas fa-user-slash"></i> 0 santri
</span>
<?php endif; ?>
</td>
<td>
<?php if($kelas->santri_aktif_count > 0): ?>
<select class="form-control form-control-sm target-kelas-select"
data-kelas-id="<?php echo e($kelas->id); ?>"
style="font-size: 0.9rem;">
<option value="">-- Pilih Kelas Tujuan --</option>
<?php $__currentLoopData = $allKelasList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $targetKelas): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php if($targetKelas->id != $kelas->id): ?>
<option value="<?php echo e($targetKelas->id); ?>">
<?php echo e($targetKelas->kelompok->nama_kelompok); ?> - <?php echo e($targetKelas->nama_kelas); ?>
</option>
<?php endif; ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
<?php else: ?>
<span class="text-muted" style="font-size:0.85rem;"></span>
<?php endif; ?>
</td>
<td style="text-align: center;">
<?php if($kelas->santri_aktif_count > 0): ?>
<div style="display: flex; gap: 5px; justify-content: center;">
<button type="button"
class="btn btn-sm btn-success btn-naikkan"
data-kelas-id="<?php echo e($kelas->id); ?>"
data-kelas-nama="<?php echo e($kelas->nama_kelas); ?>"
data-santri-count="<?php echo e($kelas->santri_aktif_count); ?>"
disabled
title="Pilih kelas tujuan terlebih dahulu">
<i class="fas fa-arrow-up"></i> Naikkan
</button>
<a href="<?php echo e(route('admin.kelas.kenaikan.preview', $kelas->id)); ?>"
class="btn btn-sm btn-info"
title="Lihat & Pilih Santri">
<i class="fas fa-eye"></i> Lihat
</a>
</div>
<?php else: ?>
<span class="badge badge-secondary">
<i class="fas fa-user-slash"></i> Tidak ada santri
</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
</div>
<?php else: ?>
<div class="content-box">
<div class="text-center py-5">
<i class="fas fa-graduation-cap fa-3x text-muted mb-3"></i>
<h5 class="text-muted">Tidak ada kelas ditemukan</h5>
<p class="text-muted">Belum ada kelas aktif di kelompok yang dipilih.</p>
</div>
</div>
<?php endif; ?>
<div class="alert alert-info" style="border-left: 4px solid var(--info-color); background: #E3F7FC;">
<div style="display: flex; gap: 11px;">
<div style="font-size: 2rem; color: var(--info-color);"><i class="fas fa-info-circle"></i></div>
<div>
<strong style="color: var(--primary-dark); font-size: 1.1rem;">Cara Menggunakan Kenaikan Kelas:</strong>
<ol style="margin: 10px 0 0 0; padding-left: 20px; color: var(--text-color);">
<li style="margin-bottom: 8px;"><strong>Pilih Kelompok Kelas</strong> dari dropdown untuk menampilkan daftar kelas</li>
<li style="margin-bottom: 8px;"><strong>Pilih Kelas Tujuan</strong> di kolom dropdown tiap baris</li>
<li style="margin-bottom: 8px;">Klik <span class="badge badge-success"><i class="fas fa-arrow-up"></i> Naikkan</span> untuk memproses semua santri di kelas tersebut</li>
<li style="margin-bottom: 8px;">Atau klik <span class="badge badge-info"><i class="fas fa-eye"></i> Lihat</span> untuk memilih santri secara individual</li>
<li style="margin-bottom: 8px;">Santri akan dipindahkan ke <strong>Tahun Ajaran <?php echo e($tahunAjaranBaru); ?></strong></li>
</ol>
</div>
</div>
</div>
<?php $__env->stopSection(); ?>
<?php $__env->startSection('scripts'); ?>
<script>
document.addEventListener('DOMContentLoaded', function () {
// ── Enable/disable tombol Naikkan berdasarkan pilihan dropdown ──
document.querySelectorAll('.target-kelas-select').forEach(function (select) {
var kelasId = select.dataset.kelasId;
var button = document.querySelector('.btn-naikkan[data-kelas-id="' + kelasId + '"]');
if (!button) return;
select.addEventListener('change', function () {
if (this.value) {
button.disabled = false;
button.title = 'Klik untuk menaikkan kelas semua santri';
} else {
button.disabled = true;
button.title = 'Pilih kelas tujuan terlebih dahulu';
}
});
});
// ── Handle klik tombol Naikkan ──
document.querySelectorAll('.btn-naikkan').forEach(function (button) {
button.addEventListener('click', function (e) {
e.preventDefault();
var kelasId = this.dataset.kelasId;
var kelasNama = this.dataset.kelasNama;
var santriCount = this.dataset.santriCount;
var select = document.querySelector('.target-kelas-select[data-kelas-id="' + kelasId + '"]');
if (!select || !select.value) {
if (select) {
select.focus();
select.style.border = '2px solid #FF8B94';
setTimeout(function () { select.style.border = ''; }, 2000);
}
alert('Silakan pilih kelas tujuan terlebih dahulu!');
return;
}
var targetKelasText = select.options[select.selectedIndex].text;
var tahunAjaranBaru = '<?php echo e($tahunAjaranBaru); ?>';
var confirmMessage =
'KONFIRMASI KENAIKAN KELAS\n\n' +
'Kelas Asal : ' + kelasNama + '\n' +
'Kelas Tujuan : ' + targetKelasText + '\n' +
'Jumlah Santri: ' + santriCount + ' orang\n' +
'Tahun Ajaran : ' + tahunAjaranBaru + '\n\n' +
'Proses ini akan memindahkan SEMUA santri aktif ke kelas dan tahun ajaran baru.\n' +
'Lanjutkan?';
if (!confirm(confirmMessage)) return;
// Disable tombol agar tidak double-submit
this.disabled = true;
this.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...';
// Buat form dan submit
var form = document.createElement('form');
form.method = 'POST';
form.action = '<?php echo e(route("admin.kelas.kenaikan.process")); ?>';
[
{ name: '_token', value: '<?php echo e(csrf_token()); ?>' },
{ name: 'id_kelas_asal', value: kelasId },
{ name: 'id_kelas_tujuan', value: select.value },
].forEach(function (item) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = item.name;
input.value = item.value;
form.appendChild(input);
});
document.body.appendChild(form);
form.submit();
});
});
});
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kelas/kenaikan/index.blade.php ENDPATH**/ ?>

View File

@ -0,0 +1,144 @@

<?php $__env->startSection('content'); ?>
<style>
.text-center { text-align:center; }
.progress-inline { display:flex; align-items:center; gap:8px; }
.progress-bar-mini { flex:1; background:#e9ecef; border-radius:8px; height:8px; overflow:hidden; max-width:120px; }
.progress-bar-mini .fill { height:100%; border-radius:8px; }
</style>
<div class="page-header">
<h2><i class="fas fa-user-clock"></i> Santri Perlu Perhatian</h2>
<a href="<?php echo e(route('admin.laporan-kegiatan.index', request()->only('periode','tanggal_dari','tanggal_sampai'))); ?>"
class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
<div class="content-box" style="margin-bottom:14px;">
<p style="margin:0;font-size:.88rem;color:var(--text-light);">
<i class="fas fa-info-circle"></i>
Menampilkan <strong><?php echo e($santris->total()); ?> santri</strong>
dari <strong><?php echo e($totalSantriAktif); ?> santri aktif</strong>
yang kehadiran efektifnya &lt;70%
dalam periode <strong><?php echo e($periodeLabel); ?></strong>.
<br>
<span style="font-size:.8rem;opacity:.8;">
<i class="fas fa-clock"></i> Terlambat dihitung sebagai Hadir efektif.
</span>
</p>
</div>
<div class="content-box" style="margin-bottom:14px;">
<form method="GET" style="display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;">
<input type="hidden" name="periode" value="<?php echo e(request('periode','bulan_ini')); ?>">
<input type="hidden" name="tanggal_dari" value="<?php echo e(request('tanggal_dari')); ?>">
<input type="hidden" name="tanggal_sampai" value="<?php echo e(request('tanggal_sampai')); ?>">
<div class="form-group" style="margin:0;">
<label style="font-size:.82rem;">Filter Kelas</label>
<select name="id_kelas" class="form-control" style="min-width:180px;">
<option value="">-- Semua Kelas --</option>
<?php $__currentLoopData = $kelasList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $k): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($k->id); ?>" <?php echo e(request('id_kelas')==$k->id?'selected':''); ?>>
<?php echo e($k->kelompok->nama_kelompok ?? ''); ?> <?php echo e($k->nama_kelas); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<button type="submit" class="btn btn-primary btn-sm"><i class="fas fa-filter"></i> Filter</button>
</form>
</div>
<div class="content-box">
<?php if($santris->count() > 0): ?>
<div class="table-wrapper">
<table class="data-table" style="font-size:.84rem;">
<thead>
<tr>
<th>No</th>
<th>Nama</th>
<th class="text-center">Total Sesi</th>
<th class="text-center">
Hadir Efektif
<span style="display:block;font-weight:400;font-size:.73rem;color:#9CA3AF;">(Hadir+Terlambat)</span>
</th>
<th class="text-center">Terlambat</th>
<th class="text-center">Alpa</th>
<th class="text-center">Izin</th>
<th class="text-center">Sakit</th>
<th class="text-center" style="min-width:180px;">
% Kehadiran
<span style="display:block;font-weight:400;font-size:.73rem;color:#9CA3AF;">(hadir / total sesi)</span>
</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $santris; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $i => $s): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($santris->firstItem() + $i); ?></td>
<td>
<strong><?php echo e($s->nama_lengkap); ?></strong>
<div style="font-size:.75rem;color:#9CA3AF;"><code><?php echo e($s->id_santri); ?></code></div>
</td>
<td class="text-center"><?php echo e($s->total); ?></td>
<td class="text-center">
<span class="badge badge-success"><?php echo e($s->hadir); ?></span>
</td>
<td class="text-center">
<?php if(($s->terlambat ?? 0) > 0): ?>
<span class="badge badge-warning"><?php echo e($s->terlambat); ?></span>
<?php else: ?>
<span style="color:#9CA3AF;">0</span>
<?php endif; ?>
</td>
<td class="text-center">
<span class="badge badge-danger"><?php echo e($s->alpa); ?></span>
</td>
<td class="text-center">
<span class="badge badge-warning"><?php echo e($s->izin); ?></span>
</td>
<td class="text-center">
<span class="badge badge-info"><?php echo e($s->sakit); ?></span>
</td>
<td class="text-center">
<div class="progress-inline" style="justify-content:center;">
<div class="progress-bar-mini">
<div class="fill" style="width:<?php echo e($s->persen); ?>%;background:#EF4444;"></div>
</div>
<div>
<strong style="color:#EF4444;"><?php echo e($s->persen); ?>%</strong>
<div style="font-size:.72rem;color:#9CA3AF;">
<?php echo e($s->hadir); ?> dari <?php echo e($s->total); ?>
</div>
</div>
</div>
</td>
<td>
<a href="<?php echo e(route('admin.riwayat-kegiatan.detail-santri', $s->id_santri)); ?>"
class="btn btn-sm btn-info" title="Lihat Riwayat Lengkap">
<i class="fas fa-history"></i> Riwayat
</a>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<div style="margin-top:16px;"><?php echo e($santris->links()); ?></div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-check-circle" style="color:#10B981;font-size:2rem;"></i>
<h3>Alhamdulillah!</h3>
<p>Tidak ada santri dengan kehadiran di bawah 70%.</p>
</div>
<?php endif; ?>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kegiatan/laporan/santri-perlu-perhatian.blade.php ENDPATH**/ ?>

View File

@ -1,270 +0,0 @@

<?php $__env->startSection('title', 'Import Absensi Mesin'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-file-import"></i> Import Absensi Fingerprint</h2>
<a href="<?php echo e(route('admin.kegiatan.index')); ?>" class="btn btn-sm btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger">
<i class="fas fa-times-circle"></i> <?php echo e(session('error')); ?>
</div>
<?php endif; ?>
<?php if($belumMapping > 0): ?>
<div class="alert alert-warning">
<i class="fas fa-exclamation-triangle"></i>
<strong><?php echo e($belumMapping); ?></strong> ID mesin belum dipetakan ke santri.
Data santri tersebut tidak akan tersimpan saat import.
<a href="<?php echo e(route('admin.mesin.mapping-santri.index')); ?>"
class="btn btn-sm btn-warning" style="margin-left:8px;">
Lengkapi Mapping
</a>
</div>
<?php endif; ?>
<div class="content-box" style="margin-bottom:14px">
<h4 style="margin:0 0 12px;color:var(--primary-color)">
<i class="fas fa-info-circle"></i> Cara Kerja Matching
</h4>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px">
<div style="background:#FFF3E8;border:1px solid #FDBA74;border-radius:8px;padding:12px">
<div style="font-size:18px;margin-bottom:4px"></div>
<div style="font-weight:700;color:#C05621;margin-bottom:4px">Mesin Sholat</div>
<div style="font-size:12px;color:#374151;line-height:1.6">
JK1 Masuk Shubuh<br>
JK1 Pulang Dhuhur<br>
JK2 Masuk Ashar<br>
JK2 Pulang Maghrib<br>
Lb Masuk Isya
</div>
</div>
<div style="background:#EFF6FF;border:1px solid #BFDBFE;border-radius:8px;padding:12px">
<div style="font-size:18px;margin-bottom:4px"></div>
<div style="font-weight:700;color:#1D4ED8;margin-bottom:4px">Mesin Ngaji</div>
<div style="font-size:12px;color:#374151;line-height:1.6">
JK1 Masuk Ngaji Shubuh<br>
JK1 Pulang sekolah<br>
JK2 Masuk Ngaji Siang<br>
JK2 Pulang Ngaji Maghrib<br>
Lb Masuk Ngaji Malam
</div>
</div>
<div style="background:#FEF9C3;border:1px solid #FDE68A;border-radius:8px;padding:12px">
<div style="font-size:18px;margin-bottom:4px"></div>
<div style="font-weight:700;color:#92400E;margin-bottom:4px">Konflik</div>
<div style="font-size:12px;color:#374151;line-height:1.6">
Jika santri sudah punya absen<br>
Manual/RFID, sistem akan<br>
minta pilihan Anda di halaman<br>
preview sebelum disimpan.
</div>
</div>
</div>
</div>
<div class="content-box">
<h4 style="margin:0 0 16px">
<i class="fas fa-upload" style="color:var(--primary-color)"></i>
Upload File GLog.txt
</h4>
<form action="<?php echo e(route('admin.mesin.import.preview')); ?>"
method="POST"
enctype="multipart/form-data">
<?php echo csrf_field(); ?>
<div class="form-group" style="margin-bottom:16px">
<label style="font-weight:600;font-size:14px">
<i class="fas fa-database" style="color:#1A56DB"></i>
File GLog.txt <span style="color:red">*</span>
</label>
<input type="file" name="file_glog" class="form-control"
accept=".txt,.csv,.xls,.xlsx" required>
<small class="text-muted">
Export dari software Eppos: menu
<strong>Report Download Log</strong>.
Pilih periode tanggal yang diinginkan lalu export.
</small>
<?php $__errorArgs = ['file_glog'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<div style="color:#EF4444;font-size:12px;margin-top:4px">
<?php echo e($message); ?>
</div>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px">
<div class="form-group" style="margin:0">
<label style="font-weight:600;font-size:14px">
<i class="fas fa-clock"></i>
Toleransi Sebelum Kegiatan (menit)
</label>
<input type="number" name="tol_sebelum" class="form-control"
value="15" min="0" max="60">
<small class="text-muted">
Scan diterima berapa menit <strong>sebelum</strong> kegiatan mulai
</small>
</div>
<div class="form-group" style="margin:0">
<label style="font-weight:600;font-size:14px">
<i class="fas fa-clock"></i>
Toleransi Sesudah Kegiatan (menit)
</label>
<input type="number" name="tol_sesudah" class="form-control"
value="10" min="0" max="60">
<small class="text-muted">
Scan diterima berapa menit <strong>setelah</strong> kegiatan selesai
</small>
</div>
</div>
<div class="form-group" style="margin-bottom:20px">
<div style="display:flex;align-items:center;gap:10px;
background:#F8FAFC;border:1px solid #E2E8F0;
border-radius:8px;padding:12px">
<input type="checkbox" name="isi_alpa" value="1"
id="isiAlpa" checked
style="width:18px;height:18px;cursor:pointer">
<label for="isiAlpa" style="margin:0;cursor:pointer;font-weight:500">
Isi <strong>Alpa</strong> otomatis untuk santri yang tidak scan
<span style="color:#6B7280;font-size:12px;display:block;font-weight:400">
Jika tidak dicentang, santri yang tidak scan tidak akan diisi apapun
</span>
</label>
</div>
</div>
<div class="form-group" style="margin-bottom:20px">
<label style="font-weight:600;font-size:14px;margin-bottom:8px;display:block">
<i class="fas fa-exchange-alt" style="color:#DC2626"></i>
Jika ada konflik dengan data absen yang sudah ada:
</label>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px">
<label style="background:#DCFCE7;border:2px solid #86EFAC;border-radius:8px;padding:12px;cursor:pointer;display:flex;align-items:flex-start;gap:8px;margin:0"
id="lbl_mesin">
<input type="radio" name="conflict_strategy" value="mesin" checked
style="margin-top:3px;width:16px;height:16px">
<div>
<div style="font-weight:700;color:#166534">Utamakan Data Mesin</div>
<div style="font-size:11px;color:#374151;margin-top:2px">
Timpa semua data lama dengan hasil mesin. Paling umum dipakai.
</div>
</div>
</label>
<label style="background:#DBEAFE;border:2px solid #93C5FD;border-radius:8px;padding:12px;cursor:pointer;display:flex;align-items:flex-start;gap:8px;margin:0"
id="lbl_exist">
<input type="radio" name="conflict_strategy" value="exist"
style="margin-top:3px;width:16px;height:16px">
<div>
<div style="font-weight:700;color:#1D4ED8">Pertahankan Data Lama</div>
<div style="font-size:11px;color:#374151;margin-top:2px">
Data Manual/RFID yang sudah ada tidak diubah.
</div>
</div>
</label>
<label style="background:#FEF9C3;border:2px solid #FDE68A;border-radius:8px;padding:12px;cursor:pointer;display:flex;align-items:flex-start;gap:8px;margin:0"
id="lbl_manual">
<input type="radio" name="conflict_strategy" value="manual"
style="margin-top:3px;width:16px;height:16px">
<div>
<div style="font-weight:700;color:#92400E">Pilih Manual per Sel</div>
<div style="font-size:11px;color:#374151;margin-top:2px">
Review tiap konflik satu per satu di halaman preview.
</div>
</div>
</label>
</div>
</div>
<div style="display:flex;gap:10px;align-items:center">
<button type="submit" class="btn btn-primary"
style="padding:10px 28px;font-size:15px">
<i class="fas fa-search"></i> Preview Data Import
</button>
<a href="<?php echo e(route('admin.mesin.mapping-santri.index')); ?>"
class="btn btn-secondary" style="padding:10px 20px">
<i class="fas fa-link"></i> Kelola Mapping Santri
</a>
</div>
</form>
</div>
<?php if($riwayat->count() > 0): ?>
<div class="content-box" style="margin-top:14px">
<h4 style="margin:0 0 12px">
<i class="fas fa-history"></i> Riwayat Import Terakhir
</h4>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>Waktu</th>
<th>Jumlah Scan</th>
<th>Berhasil</th>
<th>Konflik Selesai</th>
<th>Duplikat</th>
<th>Tanpa Mapping</th>
<th>Oleh</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $riwayat; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $r): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($r->created_at->format('d/m/Y H:i')); ?></td>
<td><?php echo e(number_format($r->jumlah_scan)); ?></td>
<td>
<span class="badge badge-success"><?php echo e($r->berhasil); ?></span>
</td>
<td>
<?php if($r->konflik_selesai > 0): ?>
<span class="badge badge-warning"><?php echo e($r->konflik_selesai); ?></span>
<?php else: ?> <span style="color:#9CA3AF">-</span>
<?php endif; ?>
</td>
<td>
<?php if($r->dilewati > 0): ?>
<span class="badge badge-secondary"><?php echo e($r->dilewati); ?></span>
<?php else: ?> <span style="color:#9CA3AF">-</span>
<?php endif; ?>
</td>
<td>
<?php if($r->no_santri > 0): ?>
<span class="badge badge-danger"><?php echo e($r->no_santri); ?></span>
<?php else: ?> <span style="color:#9CA3AF">-</span>
<?php endif; ?>
</td>
<td style="color:#6B7280"><?php echo e($r->user->name ?? '-'); ?></td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/mesin/import/index.blade.php ENDPATH**/ ?>

View File

@ -1,298 +0,0 @@

<?php $__env->startSection('title', 'Preview Kenaikan Kelas'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-users"></i> Preview Kenaikan Kelas - <?php echo e($kelas->nama_kelas); ?></h2>
<p class="text-muted">Pilih santri yang akan dinaikkan kelasnya</p>
</div>
<!-- Flash Messages -->
<?php if(session('success')): ?>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<?php endif; ?>
<!-- Info Cards -->
<div class="content-box" style="margin-bottom: 14px;">
<div class="row-cards">
<div class="card card-info">
<h3>Kelas Asal</h3>
<div class="card-value-small"><?php echo e($kelas->nama_kelas); ?></div>
<p class="text-muted" style="margin: 0;"><?php echo e($kelas->kelompok->nama_kelompok); ?></p>
</div>
<div class="card card-success">
<h3>Total Santri</h3>
<div class="card-value"><?php echo e($santriList->count()); ?></div>
<p class="text-muted" style="margin: 0;">Santri aktif di kelas ini</p>
</div>
<div class="card card-warning">
<h3>Tahun Ajaran</h3>
<div class="card-value-small"><?php echo e($tahunAjaranAktif); ?></div>
<div style="margin-top: 8px; font-size: 0.9rem; color: var(--text-light);">
<i class="fas fa-arrow-down"></i>
</div>
<div class="card-value-small" style="color: var(--success-color);"><?php echo e($tahunAjaranBaru); ?></div>
</div>
</div>
</div>
<!-- Form Kenaikan Kelas -->
<div class="content-box">
<form action="<?php echo e(route('admin.kelas.kenaikan.process-selected')); ?>" method="POST" id="formKenaikanKelas">
<?php echo csrf_field(); ?>
<input type="hidden" name="id_kelas_asal" value="<?php echo e($kelas->id); ?>">
<!-- Pilih Kelas Tujuan -->
<div class="form-group">
<label for="id_kelas_tujuan">
<i class="fas fa-graduation-cap"></i> Kelas Tujuan <span class="text-danger">*</span>
</label>
<select class="form-control <?php $__errorArgs = ['id_kelas_tujuan'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?> is-invalid <?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>"
id="id_kelas_tujuan"
name="id_kelas_tujuan"
required>
<option value="">-- Pilih Kelas Tujuan --</option>
<?php $__currentLoopData = $kelasOptions; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelompok): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<optgroup label="<?php echo e($kelompok->nama_kelompok); ?>">
<?php $__currentLoopData = $kelompok->kelas; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelasOption): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php if($kelasOption->id != $kelas->id): ?>
<option value="<?php echo e($kelasOption->id); ?>">
<?php echo e($kelasOption->nama_kelas); ?>
</option>
<?php endif; ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</optgroup>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
<?php $__errorArgs = ['id_kelas_tujuan'];
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
if ($__bag->has($__errorArgs[0])) :
if (isset($message)) { $__messageOriginal = $message; }
$message = $__bag->first($__errorArgs[0]); ?>
<div class="invalid-feedback"><?php echo e($message); ?></div>
<?php unset($message);
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
endif;
unset($__errorArgs, $__bag); ?>
<small class="form-text text-muted">
Pilih kelas yang akan menjadi tujuan kenaikan untuk santri yang dipilih
</small>
</div>
<hr>
<!-- Daftar Santri -->
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
<h4 style="margin: 0;">
<i class="fas fa-users"></i> Daftar Santri
<span class="badge badge-info" id="selectedCount">0 dipilih</span>
</h4>
<div>
<button type="button" class="btn btn-sm btn-info" id="btnSelectAll">
<i class="fas fa-check-square"></i> Pilih Semua
</button>
<button type="button" class="btn btn-sm btn-secondary" id="btnDeselectAll">
<i class="fas fa-square"></i> Batal Pilih
</button>
</div>
</div>
<?php if($santriList->count() > 0): ?>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">
<input type="checkbox" id="checkAll" style="width: 18px; height: 18px; cursor: pointer;">
</th>
<th style="width: 50px;">No</th>
<th>Foto</th>
<th>NIS</th>
<th>Nama Santri</th>
<th>Jenis Kelamin</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $santriList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $santri): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td>
<input type="checkbox"
name="santri_ids[]"
value="<?php echo e($santri->id_santri); ?>"
class="santri-checkbox"
style="width: 18px; height: 18px; cursor: pointer;">
</td>
<td><?php echo e($index + 1); ?></td>
<td>
<?php if($santri->foto): ?>
<img src="<?php echo e($santri->foto_url); ?>"
alt="<?php echo e($santri->nama_lengkap); ?>"
class="santri-avatar">
<?php else: ?>
<div class="santri-avatar-initial">
<?php echo e(strtoupper(substr($santri->nama_lengkap, 0, 1))); ?>
</div>
<?php endif; ?>
</td>
<td><?php echo e($santri->nis ?? '-'); ?></td>
<td><strong><?php echo e($santri->nama_lengkap); ?></strong></td>
<td>
<?php if($santri->jenis_kelamin === 'Laki-laki'): ?>
<i class="fas fa-mars text-primary"></i> Laki-laki
<?php else: ?>
<i class="fas fa-venus" style="color: #FF8B94;"></i> Perempuan
<?php endif; ?>
</td>
<td>
<span class="badge badge-success">
<i class="fas fa-check-circle"></i> <?php echo e($santri->status); ?>
</span>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<hr>
<!-- Action Buttons -->
<div class="alert alert-warning">
<i class="fas fa-exclamation-triangle"></i> <strong>Perhatian:</strong>
<ul class="mb-0 mt-2">
<li>Pastikan kelas tujuan sudah dipilih</li>
<li>Pilih santri yang akan dinaikkan kelasnya (minimal 1 santri)</li>
<li>Proses kenaikan kelas akan memindahkan santri ke tahun ajaran <strong><?php echo e($tahunAjaranBaru); ?></strong></li>
<li>Santri yang dipilih akan otomatis terdaftar di kelas tujuan</li>
</ul>
</div>
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
<button type="submit" class="btn btn-success" id="btnSubmit" disabled>
<i class="fas fa-arrow-up"></i> Naikkan Kelas yang Dipilih
</button>
<a href="<?php echo e(route('admin.kelas.kenaikan.index')); ?>" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
<?php else: ?>
<div class="text-center py-5">
<i class="fas fa-users fa-3x text-muted mb-3"></i>
<h5 class="text-muted">Tidak ada santri aktif di kelas ini</h5>
<p class="text-muted">Kelas <?php echo e($kelas->nama_kelas); ?> tidak memiliki santri aktif.</p>
<a href="<?php echo e(route('admin.kelas.kenaikan.index')); ?>" class="btn btn-secondary mt-2">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
<?php endif; ?>
</form>
</div>
<?php $__env->stopSection(); ?>
<?php $__env->startSection('scripts'); ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
const checkAll = document.getElementById('checkAll');
const checkboxes = document.querySelectorAll('.santri-checkbox');
const selectedCount = document.getElementById('selectedCount');
const btnSubmit = document.getElementById('btnSubmit');
const btnSelectAll = document.getElementById('btnSelectAll');
const btnDeselectAll = document.getElementById('btnDeselectAll');
const kelasSelect = document.getElementById('id_kelas_tujuan');
function updateSelectedCount() {
const checked = document.querySelectorAll('.santri-checkbox:checked').length;
selectedCount.textContent = `${checked} dipilih`;
// Enable submit button if kelas tujuan selected and at least 1 santri checked
if (kelasSelect.value && checked > 0) {
btnSubmit.disabled = false;
} else {
btnSubmit.disabled = true;
}
}
// Check all functionality
if (checkAll) {
checkAll.addEventListener('change', function() {
checkboxes.forEach(checkbox => {
checkbox.checked = this.checked;
});
updateSelectedCount();
});
}
// Individual checkbox
checkboxes.forEach(checkbox => {
checkbox.addEventListener('change', function() {
// Update check all status
const allChecked = Array.from(checkboxes).every(cb => cb.checked);
if (checkAll) {
checkAll.checked = allChecked;
}
updateSelectedCount();
});
});
// Select all button
if (btnSelectAll) {
btnSelectAll.addEventListener('click', function() {
checkboxes.forEach(checkbox => checkbox.checked = true);
if (checkAll) checkAll.checked = true;
updateSelectedCount();
});
}
// Deselect all button
if (btnDeselectAll) {
btnDeselectAll.addEventListener('click', function() {
checkboxes.forEach(checkbox => checkbox.checked = false);
if (checkAll) checkAll.checked = false;
updateSelectedCount();
});
}
// Kelas tujuan change
if (kelasSelect) {
kelasSelect.addEventListener('change', updateSelectedCount);
}
// Form submit confirmation
const form = document.getElementById('formKenaikanKelas');
if (form) {
form.addEventListener('submit', function(e) {
const checked = document.querySelectorAll('.santri-checkbox:checked').length;
const kelasText = kelasSelect.options[kelasSelect.selectedIndex].text;
if (!confirm(`Apakah Anda yakin ingin menaikkan ${checked} santri ke kelas "${kelasText}"?\n\nProses ini tidak dapat dibatalkan.`)) {
e.preventDefault();
}
});
}
// Initial count
updateSelectedCount();
});
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kelas/kenaikan/preview.blade.php ENDPATH**/ ?>

View File

@ -108,8 +108,6 @@
<a href="<?php echo e(route('admin.kepulangan.create')); ?>" class="btn btn-primary"> <a href="<?php echo e(route('admin.kepulangan.create')); ?>" class="btn btn-primary">
<i class="fas fa-plus"></i> Tambah Izin Kepulangan <i class="fas fa-plus"></i> Tambah Izin Kepulangan
</a> </a>
<a href="<?php echo e(route('admin.kepulangan.pengajuan')); ?>" class="btn btn-warning"> <a href="<?php echo e(route('admin.kepulangan.pengajuan')); ?>" class="btn btn-warning">
<i class="fas fa-mobile-alt"></i> Pengajuan izin <i class="fas fa-mobile-alt"></i> Pengajuan izin
<?php if($pendingPengajuan > 0): ?> <?php if($pendingPengajuan > 0): ?>
@ -126,14 +124,8 @@
<form method="GET" action="<?php echo e(route('admin.kepulangan.index')); ?>" id="filterForm" style="margin-bottom: 14px;"> <form method="GET" action="<?php echo e(route('admin.kepulangan.index')); ?>" id="filterForm" style="margin-bottom: 14px;">
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 11px; align-items: end;"> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 11px; align-items: end;">
<div class="form-group" style="margin-bottom: 0;"> <div class="form-group" style="margin-bottom: 0;">
<input type="text" <input type="text" name="search" class="form-control" placeholder="Cari nama, ID, atau alasan..." value="<?php echo e(request('search')); ?>" id="searchInput">
name="search"
class="form-control"
placeholder="Cari nama, ID, atau alasan..."
value="<?php echo e(request('search')); ?>"
id="searchInput">
</div> </div>
<div class="form-group" style="margin-bottom: 0;"> <div class="form-group" style="margin-bottom: 0;">
<select name="status" class="form-control" onchange="document.getElementById('filterForm').submit();"> <select name="status" class="form-control" onchange="document.getElementById('filterForm').submit();">
<option value="">Semua Status</option> <option value="">Semua Status</option>
@ -143,19 +135,14 @@ class="form-control"
<option value="Selesai" <?php echo e(request('status') == 'Selesai' ? 'selected' : ''); ?>>Selesai</option> <option value="Selesai" <?php echo e(request('status') == 'Selesai' ? 'selected' : ''); ?>>Selesai</option>
</select> </select>
</div> </div>
<div class="form-group" style="margin-bottom: 0;"> <div class="form-group" style="margin-bottom: 0;">
<select name="tahun" class="form-control" onchange="document.getElementById('filterForm').submit();"> <select name="tahun" class="form-control" onchange="document.getElementById('filterForm').submit();">
<option value="">Semua Tahun</option> <option value="">Semua Tahun</option>
<?php $__currentLoopData = $tahunList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $tahun): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> <?php $__currentLoopData = $tahunList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $tahun): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($tahun); ?>" <?php echo e(request('tahun') == $tahun ? 'selected' : ''); ?>> <option value="<?php echo e($tahun); ?>" <?php echo e(request('tahun') == $tahun ? 'selected' : ''); ?>><?php echo e($tahun); ?></option>
<?php echo e($tahun); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?> <?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select> </select>
</div> </div>
<div class="form-group" style="margin-bottom: 0;"> <div class="form-group" style="margin-bottom: 0;">
<select name="bulan" class="form-control" onchange="document.getElementById('filterForm').submit();"> <select name="bulan" class="form-control" onchange="document.getElementById('filterForm').submit();">
<option value="">Semua Bulan</option> <option value="">Semua Bulan</option>
@ -167,14 +154,9 @@ class="form-control"
<?php endfor; ?> <?php endfor; ?>
</select> </select>
</div> </div>
<div style="display: flex; gap: 10px;"> <div style="display: flex; gap: 10px;">
<button type="submit" class="btn btn-primary"> <button type="submit" class="btn btn-primary"><i class="fas fa-search"></i> Filter</button>
<i class="fas fa-search"></i> Filter <a href="<?php echo e(route('admin.kepulangan.index')); ?>" class="btn btn-secondary"><i class="fas fa-redo"></i> Reset</a>
</button>
<a href="<?php echo e(route('admin.kepulangan.index')); ?>" class="btn btn-secondary">
<i class="fas fa-redo"></i> Reset
</a>
</div> </div>
</div> </div>
</form> </form>
@ -206,8 +188,7 @@ class="form-control"
<td> <td>
<strong><?php echo e($item->id_kepulangan); ?></strong> <strong><?php echo e($item->id_kepulangan); ?></strong>
<?php if($isOverLimit): ?> <?php if($isOverLimit): ?>
<span style="display: inline-block; background: #dc3545; color: white; padding: 2px 6px; border-radius: 4px; font-size: 0.75rem; margin-left: 5px; animation: pulse 2s infinite;" <span style="display: inline-block; background: #dc3545; color: white; padding: 2px 6px; border-radius: 4px; font-size: 0.75rem; margin-left: 5px; animation: pulse 2s infinite;" title="Over Limit: <?php echo e($totalHariTerpakai); ?> hari">
title="Over Limit: <?php echo e($totalHariTerpakai); ?> hari">
<i class="fas fa-exclamation-triangle"></i> <i class="fas fa-exclamation-triangle"></i>
</span> </span>
<?php endif; ?> <?php endif; ?>
@ -215,10 +196,7 @@ class="form-control"
<td> <td>
<div> <div>
<strong><?php echo e($item->santri->nama_lengkap ?? 'N/A'); ?></strong><br> <strong><?php echo e($item->santri->nama_lengkap ?? 'N/A'); ?></strong><br>
<small style="color: #7F8C8D;"> <small style="color: #7F8C8D;"><?php echo e($item->santri->id_santri ?? ''); ?> | <?php echo e($item->santri->kelas ?? ''); ?></small>
<?php echo e($item->santri->id_santri ?? ''); ?> | <?php echo e($item->santri->kelas ?? ''); ?>
</small>
</div> </div>
</td> </td>
<td><?php echo e($item->tanggal_pulang_formatted); ?></td> <td><?php echo e($item->tanggal_pulang_formatted); ?></td>
@ -232,11 +210,7 @@ class="form-control"
<?php <?php
$kuotaSantri = \App\Models\Kepulangan::getSisaKuotaSantri($item->id_santri); $kuotaSantri = \App\Models\Kepulangan::getSisaKuotaSantri($item->id_santri);
$badgeColor = $kuotaSantri['badge_color']; $badgeColor = $kuotaSantri['badge_color'];
$badgeColors = [ $badgeColors = ['success' => '#28a745', 'warning' => '#ffc107', 'danger' => '#dc3545'];
'success' => '#28a745',
'warning' => '#ffc107',
'danger' => '#dc3545'
];
$bgColor = $badgeColors[$badgeColor] ?? '#6c757d'; $bgColor = $badgeColors[$badgeColor] ?? '#6c757d';
$textColor = $badgeColor == 'warning' ? '#000' : '#fff'; $textColor = $badgeColor == 'warning' ? '#000' : '#fff';
?> ?>
@ -277,49 +251,32 @@ class="form-control"
</td> </td>
<td class="text-center"> <td class="text-center">
<div style="display: flex; gap: 5px; justify-content: center; flex-wrap: wrap;"> <div style="display: flex; gap: 5px; justify-content: center; flex-wrap: wrap;">
<a href="<?php echo e(route('admin.kepulangan.show', $item->id_kepulangan)); ?>" <a href="<?php echo e(route('admin.kepulangan.show', $item->id_kepulangan)); ?>" class="btn btn-sm btn-primary" title="Detail">
class="btn btn-sm btn-primary" title="Detail">
<i class="fas fa-eye"></i> <i class="fas fa-eye"></i>
</a> </a>
<?php if($item->status == 'Menunggu'): ?> <?php if($item->status == 'Menunggu'): ?>
<a href="<?php echo e(route('admin.kepulangan.edit', $item->id_kepulangan)); ?>" <a href="<?php echo e(route('admin.kepulangan.edit', $item->id_kepulangan)); ?>" class="btn btn-sm btn-warning" title="Edit">
class="btn btn-sm btn-warning" title="Edit">
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
</a> </a>
<button type="button" <button type="button" class="btn btn-sm btn-success" onclick="approveKepulangan('<?php echo e($item->id_kepulangan); ?>')" title="Setujui">
class="btn btn-sm btn-success"
onclick="approveKepulangan('<?php echo e($item->id_kepulangan); ?>')"
title="Setujui">
<i class="fas fa-check"></i> <i class="fas fa-check"></i>
</button> </button>
<button type="button" <button type="button" class="btn btn-sm btn-danger" onclick="rejectKepulangan('<?php echo e($item->id_kepulangan); ?>')" title="Tolak">
class="btn btn-sm btn-danger"
onclick="rejectKepulangan('<?php echo e($item->id_kepulangan); ?>')"
title="Tolak">
<i class="fas fa-times"></i> <i class="fas fa-times"></i>
</button> </button>
<?php endif; ?> <?php endif; ?>
<?php if($item->status == 'Disetujui'): ?> <?php if($item->status == 'Disetujui'): ?>
<a href="<?php echo e(route('admin.kepulangan.print', $item->id_kepulangan)); ?>" <a href="<?php echo e(route('admin.kepulangan.print', $item->id_kepulangan)); ?>" class="btn btn-sm btn-secondary" target="_blank" title="Cetak Surat">
class="btn btn-sm btn-secondary"
target="_blank" title="Cetak Surat">
<i class="fas fa-print"></i> <i class="fas fa-print"></i>
</a> </a>
<button type="button" <button type="button" class="btn btn-sm btn-success"
class="btn btn-sm btn-success"
onclick="completeKepulangan('<?php echo e($item->id_kepulangan); ?>', '<?php echo e($item->santri->nama_lengkap); ?>', '<?php echo e($item->tanggal_pulang->format('Y-m-d')); ?>', '<?php echo e($item->tanggal_kembali->format('Y-m-d')); ?>', <?php echo e($item->durasi_izin); ?>)" onclick="completeKepulangan('<?php echo e($item->id_kepulangan); ?>', '<?php echo e($item->santri->nama_lengkap); ?>', '<?php echo e($item->tanggal_pulang->format('Y-m-d')); ?>', '<?php echo e($item->tanggal_kembali->format('Y-m-d')); ?>', <?php echo e($item->durasi_izin); ?>)"
title="Selesaikan"> title="Selesaikan">
<i class="fas fa-check-double"></i> <i class="fas fa-check-double"></i>
</button> </button>
<?php endif; ?> <?php endif; ?>
<?php if(in_array($item->status, ['Menunggu', 'Ditolak', 'Selesai'])): ?> <?php if(in_array($item->status, ['Menunggu', 'Ditolak', 'Selesai'])): ?>
<button type="button" <button type="button" class="btn btn-sm btn-danger" onclick="deleteKepulangan('<?php echo e($item->id_kepulangan); ?>')" title="Hapus">
class="btn btn-sm btn-danger"
onclick="deleteKepulangan('<?php echo e($item->id_kepulangan); ?>')"
title="Hapus">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
</button> </button>
<?php endif; ?> <?php endif; ?>
@ -342,14 +299,8 @@ class="btn btn-sm btn-danger"
<?php if($kepulangan->hasPages()): ?> <?php if($kepulangan->hasPages()): ?>
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 14px; flex-wrap: wrap; gap: 11px;"> <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 14px; flex-wrap: wrap; gap: 11px;">
<div> <div>Menampilkan <?php echo e($kepulangan->firstItem() ?? 0); ?> - <?php echo e($kepulangan->lastItem() ?? 0); ?> dari <?php echo e($kepulangan->total()); ?> data</div>
Menampilkan <?php echo e($kepulangan->firstItem() ?? 0); ?> - <?php echo e($kepulangan->lastItem() ?? 0); ?> <div><?php echo e($kepulangan->appends(request()->query())->links()); ?></div>
dari <?php echo e($kepulangan->total()); ?> data
</div>
<div>
<?php echo e($kepulangan->appends(request()->query())->links()); ?>
</div>
</div> </div>
<?php endif; ?> <?php endif; ?>
</div> </div>
@ -360,19 +311,14 @@ class="btn btn-sm btn-danger"
<div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;"> <div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;">
<form id="approveForm"> <form id="approveForm">
<?php echo csrf_field(); ?> <?php echo csrf_field(); ?>
<div style="margin-bottom: 14px;"> <div style="margin-bottom: 14px;"><h3 style="margin: 0; color: #2C3E50;">Setujui Izin Kepulangan</h3></div>
<h3 style="margin: 0; color: #2C3E50;">Setujui Izin Kepulangan</h3>
</div>
<div class="form-group"> <div class="form-group">
<label>Catatan (Opsional):</label> <label>Catatan (Opsional):</label>
<textarea name="catatan" class="form-control" rows="3" <textarea name="catatan" class="form-control" rows="3" placeholder="Tambahkan catatan untuk persetujuan ini..."></textarea>
placeholder="Tambahkan catatan untuk persetujuan ini..."></textarea>
</div> </div>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;"> <div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;">
<button type="button" class="btn btn-secondary" onclick="closeModal('approveModal')">Batal</button> <button type="button" class="btn btn-secondary" onclick="closeModal('approveModal')">Batal</button>
<button type="submit" class="btn btn-success"> <button type="submit" class="btn btn-success"><i class="fas fa-check"></i> Setujui</button>
<i class="fas fa-check"></i> Setujui
</button>
</div> </div>
</form> </form>
</div> </div>
@ -385,19 +331,14 @@ class="btn btn-sm btn-danger"
<div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;"> <div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;">
<form id="rejectForm"> <form id="rejectForm">
<?php echo csrf_field(); ?> <?php echo csrf_field(); ?>
<div style="margin-bottom: 14px;"> <div style="margin-bottom: 14px;"><h3 style="margin: 0; color: #2C3E50;">Tolak Izin Kepulangan</h3></div>
<h3 style="margin: 0; color: #2C3E50;">Tolak Izin Kepulangan</h3>
</div>
<div class="form-group"> <div class="form-group">
<label>Alasan Penolakan: <span style="color: #dc3545;">*</span></label> <label>Alasan Penolakan: <span style="color: #dc3545;">*</span></label>
<textarea name="alasan_penolakan" class="form-control" rows="3" <textarea name="alasan_penolakan" class="form-control" rows="3" placeholder="Jelaskan alasan penolakan..." required></textarea>
placeholder="Jelaskan alasan penolakan..." required></textarea>
</div> </div>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;"> <div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;">
<button type="button" class="btn btn-secondary" onclick="closeModal('rejectModal')">Batal</button> <button type="button" class="btn btn-secondary" onclick="closeModal('rejectModal')">Batal</button>
<button type="submit" class="btn btn-danger"> <button type="submit" class="btn btn-danger"><i class="fas fa-times"></i> Tolak</button>
<i class="fas fa-times"></i> Tolak
</button>
</div> </div>
</form> </form>
</div> </div>
@ -408,16 +349,12 @@ class="btn btn-sm btn-danger"
<div class="modal fade" id="deleteModal" tabindex="-1" style="display: none;"> <div class="modal fade" id="deleteModal" tabindex="-1" style="display: none;">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;"> <div class="modal-content" style="background: white; border-radius: 12px; padding: 14px;">
<div style="margin-bottom: 14px;"> <div style="margin-bottom: 14px;"><h3 style="margin: 0; color: #2C3E50;">Konfirmasi Hapus</h3></div>
<h3 style="margin: 0; color: #2C3E50;">Konfirmasi Hapus</h3>
</div>
<p>Apakah Anda yakin ingin menghapus data kepulangan ini?</p> <p>Apakah Anda yakin ingin menghapus data kepulangan ini?</p>
<p style="color: #dc3545; font-size: 0.9rem;">Data yang sudah dihapus tidak dapat dikembalikan.</p> <p style="color: #dc3545; font-size: 0.9rem;">Data yang sudah dihapus tidak dapat dikembalikan.</p>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;"> <div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;">
<button type="button" class="btn btn-secondary" onclick="closeModal('deleteModal')">Batal</button> <button type="button" class="btn btn-secondary" onclick="closeModal('deleteModal')">Batal</button>
<button type="button" class="btn btn-danger" id="confirmDeleteBtn"> <button type="button" class="btn btn-danger" id="confirmDeleteBtn"><i class="fas fa-trash"></i> Hapus</button>
<i class="fas fa-trash"></i> Hapus
</button>
</div> </div>
</div> </div>
</div> </div>
@ -430,12 +367,8 @@ class="btn btn-sm btn-danger"
<form id="completeForm"> <form id="completeForm">
<?php echo csrf_field(); ?> <?php echo csrf_field(); ?>
<div style="margin-bottom: 14px;"> <div style="margin-bottom: 14px;">
<h3 style="margin: 0; color: #2C3E50;"> <h3 style="margin: 0; color: #2C3E50;"><i class="fas fa-check-circle" style="color: #28a745;"></i> Selesaikan Kepulangan</h3>
<i class="fas fa-check-circle" style="color: #28a745;"></i>
Selesaikan Kepulangan
</h3>
</div> </div>
<div style="background: #E8F7F2; padding: 15px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #6FBA9D;"> <div style="background: #E8F7F2; padding: 15px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #6FBA9D;">
<p style="margin: 5px 0;"><strong>ID Kepulangan:</strong> <span id="completeIdKepulangan"></span></p> <p style="margin: 5px 0;"><strong>ID Kepulangan:</strong> <span id="completeIdKepulangan"></span></p>
<p style="margin: 5px 0;"><strong>Santri:</strong> <span id="completeNamaSantri"></span></p> <p style="margin: 5px 0;"><strong>Santri:</strong> <span id="completeNamaSantri"></span></p>
@ -443,32 +376,20 @@ class="btn btn-sm btn-danger"
<p style="margin: 5px 0;"><strong>Rencana Kembali:</strong> <span id="completeTanggalKembaliRencana"></span></p> <p style="margin: 5px 0;"><strong>Rencana Kembali:</strong> <span id="completeTanggalKembaliRencana"></span></p>
<p style="margin: 5px 0;"><strong>Durasi Rencana:</strong> <span id="completeDurasiRencana"></span> hari</p> <p style="margin: 5px 0;"><strong>Durasi Rencana:</strong> <span id="completeDurasiRencana"></span> hari</p>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="tanggal_kembali_aktual"> <label for="tanggal_kembali_aktual">
<i class="fas fa-calendar-check"></i> <i class="fas fa-calendar-check"></i> Tanggal Kembali Aktual <span style="color: #dc3545;">*</span>
Tanggal Kembali Aktual <span style="color: #dc3545;">*</span>
</label> </label>
<input type="date" <input type="date" name="tanggal_kembali_aktual" id="tanggal_kembali_aktual" class="form-control" required>
name="tanggal_kembali_aktual" <small style="color: #7F8C8D; margin-top: 5px; display: block;">Masukkan tanggal santri kembali ke pesantren.</small>
id="tanggal_kembali_aktual"
class="form-control"
required>
<small style="color: #7F8C8D; margin-top: 5px; display: block;">
Masukkan tanggal santri kembali ke pesantren. Jika pulang lebih cepat, kuota akan disesuaikan otomatis.
</small>
</div> </div>
<div id="durasiAktualInfo" style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #007bff; display: none;"> <div id="durasiAktualInfo" style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-bottom: 14px; border-left: 4px solid #007bff; display: none;">
<p style="margin: 0;"><strong>Durasi Aktual:</strong> <span id="durasiAktual" style="font-weight: 600; color: #007bff;">-</span> hari</p> <p style="margin: 0;"><strong>Durasi Aktual:</strong> <span id="durasiAktual" style="font-weight: 600; color: #007bff;">-</span> hari</p>
<p style="margin: 5px 0 0 0; font-size: 0.9rem; color: #7F8C8D;" id="selisihInfo"></p> <p style="margin: 5px 0 0 0; font-size: 0.9rem; color: #7F8C8D;" id="selisihInfo"></p>
</div> </div>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;"> <div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;">
<button type="button" class="btn btn-secondary" onclick="closeModal('completeModal')">Batal</button> <button type="button" class="btn btn-secondary" onclick="closeModal('completeModal')">Batal</button>
<button type="submit" class="btn btn-success"> <button type="submit" class="btn btn-success"><i class="fas fa-check"></i> Selesaikan</button>
<i class="fas fa-check"></i> Selesaikan
</button>
</div> </div>
</form> </form>
</div> </div>
@ -479,26 +400,26 @@ class="form-control"
.modal.fade { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center; } .modal.fade { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center; }
.modal-dialog { max-width: 500px; width: 90%; margin: auto; } .modal-dialog { max-width: 500px; width: 90%; margin: auto; }
.modal-content { max-height: 90vh; overflow-y: auto; } .modal-content { max-height: 90vh; overflow-y: auto; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
</style> </style>
<script>
const KEPULANGAN_BASE_URL = "<?php echo e(url('admin/kepulangan')); ?>";
const CSRF_TOKEN = "<?php echo e(csrf_token()); ?>";
</script>
<script> <script>
let currentActionId = null; let currentActionId = null;
// Auto submit search dengan debounce // Auto submit search
let searchTimeout; let searchTimeout;
document.getElementById('searchInput')?.addEventListener('input', function() { document.getElementById('searchInput')?.addEventListener('input', function() {
clearTimeout(searchTimeout); clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => { searchTimeout = setTimeout(() => document.getElementById('filterForm').submit(), 500);
document.getElementById('filterForm').submit();
}, 500);
}); });
// Approve // ===== APPROVE =====
function approveKepulangan(id) { function approveKepulangan(id) {
currentActionId = id; currentActionId = id;
document.getElementById('approveModal').style.display = 'flex'; document.getElementById('approveModal').style.display = 'flex';
@ -509,33 +430,25 @@ function approveKepulangan(id) {
const formData = new FormData(this); const formData = new FormData(this);
const submitBtn = this.querySelector('button[type="submit"]'); const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML; const originalText = submitBtn.innerHTML;
submitBtn.disabled = true; submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...'; submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...';
fetch(`/admin/kepulangan/${currentActionId}/approve`, { // ✅ FIX: pakai KEPULANGAN_BASE_URL
fetch(`${KEPULANGAN_BASE_URL}/${currentActionId}/approve`, {
method: 'POST', method: 'POST',
body: formData, body: formData,
headers: { 'X-CSRF-TOKEN': '<?php echo e(csrf_token()); ?>' } headers: { 'X-CSRF-TOKEN': CSRF_TOKEN }
}) })
.then(response => response.json()) .then(r => r.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) { closeModal('approveModal'); showAlert('success', data.message); setTimeout(() => location.reload(), 1000); }
closeModal('approveModal'); else showAlert('danger', data.message);
showAlert('success', data.message);
setTimeout(() => window.location.reload(), 1000);
} else {
showAlert('danger', data.message);
}
}) })
.catch(error => showAlert('danger', 'Error: ' + error.message)) .catch(e => showAlert('danger', 'Error: ' + e.message))
.finally(() => { .finally(() => { submitBtn.disabled = false; submitBtn.innerHTML = originalText; });
submitBtn.disabled = false;
submitBtn.innerHTML = originalText;
});
}); });
// Reject // ===== REJECT =====
function rejectKepulangan(id) { function rejectKepulangan(id) {
currentActionId = id; currentActionId = id;
document.getElementById('rejectModal').style.display = 'flex'; document.getElementById('rejectModal').style.display = 'flex';
@ -546,150 +459,92 @@ function rejectKepulangan(id) {
const formData = new FormData(this); const formData = new FormData(this);
const submitBtn = this.querySelector('button[type="submit"]'); const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML; const originalText = submitBtn.innerHTML;
submitBtn.disabled = true; submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...'; submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...';
fetch(`/admin/kepulangan/${currentActionId}/reject`, { // ✅ FIX: pakai KEPULANGAN_BASE_URL
fetch(`${KEPULANGAN_BASE_URL}/${currentActionId}/reject`, {
method: 'POST', method: 'POST',
body: formData, body: formData,
headers: { 'X-CSRF-TOKEN': '<?php echo e(csrf_token()); ?>' } headers: { 'X-CSRF-TOKEN': CSRF_TOKEN }
}) })
.then(response => response.json()) .then(r => r.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) { closeModal('rejectModal'); showAlert('success', data.message); setTimeout(() => location.reload(), 1000); }
closeModal('rejectModal'); else showAlert('danger', data.message);
showAlert('success', data.message);
setTimeout(() => window.location.reload(), 1000);
} else {
showAlert('danger', data.message);
}
}) })
.catch(error => showAlert('danger', 'Error: ' + error.message)) .catch(e => showAlert('danger', 'Error: ' + e.message))
.finally(() => { .finally(() => { submitBtn.disabled = false; submitBtn.innerHTML = originalText; });
submitBtn.disabled = false;
submitBtn.innerHTML = originalText;
});
}); });
// Complete (Selesaikan Kepulangan) // ===== COMPLETE =====
let currentCompleteData = {}; let currentCompleteData = {};
function completeKepulangan(id, namaSantri, tanggalPulang, tanggalKembaliRencana, durasiRencana) { function completeKepulangan(id, namaSantri, tanggalPulang, tanggalKembaliRencana, durasiRencana) {
currentCompleteData = { currentCompleteData = { id, namaSantri, tanggalPulang, tanggalKembaliRencana, durasiRencana };
id: id,
namaSantri: namaSantri,
tanggalPulang: tanggalPulang,
tanggalKembaliRencana: tanggalKembaliRencana,
durasiRencana: durasiRencana
};
// Populate modal
document.getElementById('completeIdKepulangan').textContent = id; document.getElementById('completeIdKepulangan').textContent = id;
document.getElementById('completeNamaSantri').textContent = namaSantri; document.getElementById('completeNamaSantri').textContent = namaSantri;
document.getElementById('completeTanggalPulang').textContent = formatTanggal(tanggalPulang); document.getElementById('completeTanggalPulang').textContent = formatTanggal(tanggalPulang);
document.getElementById('completeTanggalKembaliRencana').textContent = formatTanggal(tanggalKembaliRencana); document.getElementById('completeTanggalKembaliRencana').textContent = formatTanggal(tanggalKembaliRencana);
document.getElementById('completeDurasiRencana').textContent = durasiRencana; document.getElementById('completeDurasiRencana').textContent = durasiRencana;
// Set default tanggal kembali aktual = hari ini
const today = new Date().toISOString().split('T')[0]; const today = new Date().toISOString().split('T')[0];
document.getElementById('tanggal_kembali_aktual').value = today; document.getElementById('tanggal_kembali_aktual').value = today;
document.getElementById('tanggal_kembali_aktual').min = tanggalPulang; document.getElementById('tanggal_kembali_aktual').min = tanggalPulang;
// Hitung durasi aktual
calculateDurasiAktual(); calculateDurasiAktual();
// Show modal
document.getElementById('completeModal').style.display = 'flex'; document.getElementById('completeModal').style.display = 'flex';
} }
// Calculate durasi aktual
function calculateDurasiAktual() { function calculateDurasiAktual() {
const tanggalPulang = currentCompleteData.tanggalPulang;
const tanggalKembaliAktual = document.getElementById('tanggal_kembali_aktual').value; const tanggalKembaliAktual = document.getElementById('tanggal_kembali_aktual').value;
if (!tanggalKembaliAktual || !currentCompleteData.tanggalPulang) return;
if (!tanggalKembaliAktual) return; const startDate = new Date(currentCompleteData.tanggalPulang);
const startDate = new Date(tanggalPulang);
const endDate = new Date(tanggalKembaliAktual); const endDate = new Date(tanggalKembaliAktual);
if (endDate < startDate) { document.getElementById('durasiAktualInfo').style.display = 'none'; return; }
if (endDate < startDate) { const durasiAktual = Math.ceil(Math.abs(endDate - startDate) / (1000 * 60 * 60 * 24)) + 1;
document.getElementById('durasiAktualInfo').style.display = 'none';
return;
}
const diffTime = Math.abs(endDate - startDate);
const durasiAktual = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1;
const durasiRencana = currentCompleteData.durasiRencana; const durasiRencana = currentCompleteData.durasiRencana;
document.getElementById('durasiAktual').textContent = durasiAktual; document.getElementById('durasiAktual').textContent = durasiAktual;
document.getElementById('durasiAktualInfo').style.display = 'block'; document.getElementById('durasiAktualInfo').style.display = 'block';
let selisihText = '', selisihColor = '#007bff';
// Show selisih
let selisihText = '';
let selisihColor = '#007bff';
if (durasiAktual < durasiRencana) { if (durasiAktual < durasiRencana) {
const selisih = durasiRencana - durasiAktual; selisihText = `Santri pulang ${durasiRencana - durasiAktual} hari lebih cepat. Kuota akan berkurang ${durasiAktual} hari.`;
selisihText = `✅ Santri pulang ${selisih} hari lebih cepat dari rencana. Kuota akan berkurang ${durasiAktual} hari.`;
selisihColor = '#28a745'; selisihColor = '#28a745';
} else if (durasiAktual > durasiRencana) { } else if (durasiAktual > durasiRencana) {
const selisih = durasiAktual - durasiRencana; selisihText = `Santri pulang ${durasiAktual - durasiRencana} hari lebih lambat. Kuota akan bertambah.`;
selisihText = `⚠️ Santri pulang ${selisih} hari lebih lambat dari rencana. Kuota akan bertambah ${selisih} hari.`;
selisihColor = '#ffc107'; selisihColor = '#ffc107';
} else { } else {
selisihText = `✓ Sesuai rencana (${durasiAktual} hari).`; selisihText = `Sesuai rencana (${durasiAktual} hari).`;
selisihColor = '#007bff';
} }
document.getElementById('selisihInfo').textContent = selisihText;
const selisihInfo = document.getElementById('selisihInfo'); document.getElementById('selisihInfo').style.color = selisihColor;
selisihInfo.textContent = selisihText;
selisihInfo.style.color = selisihColor;
document.getElementById('durasiAktual').style.color = selisihColor; document.getElementById('durasiAktual').style.color = selisihColor;
} }
// Event listener untuk tanggal kembali aktual
document.getElementById('tanggal_kembali_aktual')?.addEventListener('change', calculateDurasiAktual); document.getElementById('tanggal_kembali_aktual')?.addEventListener('change', calculateDurasiAktual);
// Submit form complete
document.getElementById('completeForm')?.addEventListener('submit', function(e) { document.getElementById('completeForm')?.addEventListener('submit', function(e) {
e.preventDefault(); e.preventDefault();
const formData = new FormData(this); const formData = new FormData(this);
const submitBtn = this.querySelector('button[type="submit"]'); const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML; const originalText = submitBtn.innerHTML;
submitBtn.disabled = true; submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...'; submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...';
fetch(`/admin/kepulangan/${currentCompleteData.id}/complete`, { // ✅ FIX: pakai KEPULANGAN_BASE_URL
fetch(`${KEPULANGAN_BASE_URL}/${currentCompleteData.id}/complete`, {
method: 'POST', method: 'POST',
body: formData, body: formData,
headers: { 'X-CSRF-TOKEN': '<?php echo e(csrf_token()); ?>' } headers: { 'X-CSRF-TOKEN': CSRF_TOKEN }
}) })
.then(response => response.json()) .then(r => r.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) { closeModal('completeModal'); showAlert('success', data.message); setTimeout(() => location.reload(), 1500); }
closeModal('completeModal'); else showAlert('danger', data.message);
showAlert('success', data.message);
setTimeout(() => window.location.reload(), 1500);
} else {
showAlert('danger', data.message);
}
}) })
.catch(error => showAlert('danger', 'Error: ' + error.message)) .catch(e => showAlert('danger', 'Error: ' + e.message))
.finally(() => { .finally(() => { submitBtn.disabled = false; submitBtn.innerHTML = originalText; });
submitBtn.disabled = false;
submitBtn.innerHTML = originalText;
});
}); });
// Helper: Format tanggal // ===== DELETE =====
function formatTanggal(dateString) {
const options = { year: 'numeric', month: 'long', day: 'numeric' };
return new Date(dateString).toLocaleDateString('id-ID', options);
}
// Delete
function deleteKepulangan(id) { function deleteKepulangan(id) {
currentActionId = id; currentActionId = id;
document.getElementById('deleteModal').style.display = 'flex'; document.getElementById('deleteModal').style.display = 'flex';
@ -698,61 +553,39 @@ function deleteKepulangan(id) {
document.getElementById('confirmDeleteBtn').addEventListener('click', function() { document.getElementById('confirmDeleteBtn').addEventListener('click', function() {
const btn = this; const btn = this;
const originalText = btn.innerHTML; const originalText = btn.innerHTML;
btn.disabled = true; btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Menghapus...'; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Menghapus...';
fetch(`/admin/kepulangan/${currentActionId}`, { // ✅ FIX: pakai KEPULANGAN_BASE_URL
fetch(`${KEPULANGAN_BASE_URL}/${currentActionId}`, {
method: 'DELETE', method: 'DELETE',
headers: { 'X-CSRF-TOKEN': '<?php echo e(csrf_token()); ?>' } headers: { 'X-CSRF-TOKEN': CSRF_TOKEN }
}) })
.then(response => response.json()) .then(r => r.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) { closeModal('deleteModal'); showAlert('success', data.message); setTimeout(() => location.reload(), 1000); }
closeModal('deleteModal'); else showAlert('danger', data.message);
showAlert('success', data.message);
setTimeout(() => window.location.reload(), 1000);
} else {
showAlert('danger', data.message);
}
}) })
.catch(error => showAlert('danger', 'Error: ' + error.message)) .catch(e => showAlert('danger', 'Error: ' + e.message))
.finally(() => { .finally(() => { btn.disabled = false; btn.innerHTML = originalText; });
btn.disabled = false;
btn.innerHTML = originalText;
});
}); });
// Helper functions // ===== HELPERS =====
function closeModal(modalId) { function formatTanggal(dateString) {
document.getElementById(modalId).style.display = 'none'; return new Date(dateString).toLocaleDateString('id-ID', { year: 'numeric', month: 'long', day: 'numeric' });
} }
function closeModal(modalId) { document.getElementById(modalId).style.display = 'none'; }
function showAlert(type, message) { function showAlert(type, message) {
const alertDiv = document.createElement('div'); const alertDiv = document.createElement('div');
alertDiv.className = `alert alert-${type}`; alertDiv.className = `alert alert-${type}`;
alertDiv.innerHTML = `<i class="fas fa-${type === 'success' ? 'check' : 'exclamation'}-circle"></i> ${message}`; alertDiv.innerHTML = `<i class="fas fa-${type === 'success' ? 'check' : 'exclamation'}-circle"></i> ${message}`;
document.querySelector('.page-header').insertAdjacentElement('afterend', alertDiv);
const pageHeader = document.querySelector('.page-header');
pageHeader.insertAdjacentElement('afterend', alertDiv);
setTimeout(() => alertDiv.remove(), 5000); setTimeout(() => alertDiv.remove(), 5000);
} }
// Close modals on ESC document.addEventListener('keydown', e => { if (e.key === 'Escape') document.querySelectorAll('.modal.fade').forEach(m => m.style.display = 'none'); });
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
document.querySelectorAll('.modal.fade').forEach(modal => modal.style.display = 'none');
}
});
// Close modal on outside click
document.querySelectorAll('.modal.fade').forEach(modal => { document.querySelectorAll('.modal.fade').forEach(modal => {
modal.addEventListener('click', function(e) { modal.addEventListener('click', function(e) { if (e.target === this) this.style.display = 'none'; });
if (e.target === this) {
this.style.display = 'none';
}
});
}); });
</script> </script>
<?php $__env->stopSection(); ?> <?php $__env->stopSection(); ?>

View File

@ -1,180 +0,0 @@

<?php $__env->startSection('title', 'Manajemen Akun Wali Santri'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-mobile-alt"></i> Manajemen Akun Wali Santri (Mobile App)</h2>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success"><?php echo session('success'); ?></div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger"><?php echo e(session('error')); ?></div>
<?php endif; ?>
<?php if(session('info')): ?>
<div class="alert alert-info"><?php echo e(session('info')); ?></div>
<?php endif; ?>
<div class="content-box">
<div class="alert alert-info">
<i class="fas fa-info-circle"></i> <strong>Info Login Wali (Mobile):</strong><br>
<strong>Username:</strong> Nama Orang Tua
<small class="text-muted">(jika ada nama orang tua yang sama, otomatis menjadi "Nama Orang Tua - Nama Santri")</small><br>
<strong>Password:</strong> NIS Santri
</div>
<h3>Daftar Akun Wali (<?php echo e($users->count()); ?>)</h3>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>ID Santri</th>
<th>Nama Santri</th>
<th>Nama Orang Tua</th>
<th>NIS</th>
<th>Username</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<?php $__empty_1 = true; $__currentLoopData = $users; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $user): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
<tr>
<td><?php echo e($user->id_santri); ?></td>
<td><?php echo e($user->santri->nama_lengkap ?? '-'); ?></td>
<td><?php echo e($user->santri->nama_orang_tua ?? '-'); ?></td>
<td><?php echo e($user->santri->nis ?? '-'); ?></td>
<td><code><?php echo e($user->username); ?></code></td>
<td>
<form action="<?php echo e(route('admin.users.wali_destroy', $user->id)); ?>"
method="POST" style="display:inline;"
onsubmit="return confirm('Yakin hapus akun wali <?php echo e($user->santri->nama_lengkap ?? ''); ?>?')">
<?php echo csrf_field(); ?>
<button type="submit" class="btn btn-sm btn-danger">
<i class="fas fa-trash"></i> Hapus
</button>
</form>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
<tr>
<td colspan="6" class="text-center">Belum ada akun wali.</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
<h3 style="margin-top:22px;">
Santri Belum Punya Akun Wali (<?php echo e($santris_tanpa_wali->count()); ?>)
</h3>
<?php if($santris_tanpa_wali->count() > 0): ?>
<div style="margin-bottom:12px;">
<form action="<?php echo e(route('admin.users.wali_buat_semua')); ?>" method="POST" style="display:inline;"
onsubmit="return confirm('Buat akun wali untuk SEMUA <?php echo e($santris_tanpa_wali->count()); ?> santri sekaligus?')">
<?php echo csrf_field(); ?>
<button type="submit" class="btn btn-success">
<i class="fas fa-users"></i> Buat Semua Sekaligus (<?php echo e($santris_tanpa_wali->count()); ?>)
</button>
</form>
</div>
<?php endif; ?>
<?php
// Kumpulkan nama ortu yang sudah dipakai di akun existing
// untuk preview username yang akan dibuat
$namaOrtuSudahAda = \App\Models\SantriAccount::where('role', 'wali')
->pluck('username')
->toArray();
$namaOrtuPreviewDipakai = [];
?>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>ID Santri</th>
<th>NIS</th>
<th>Nama Santri</th>
<th>Nama Orang Tua</th>
<th>Kelas</th>
<th>Username (Preview)</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<?php $__empty_1 = true; $__currentLoopData = $santris_tanpa_wali; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $santri): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
<?php
// Preview username: sama persis dgn logika resolveUsernameWali() di controller
$previewUsername = null;
if ($santri->nama_orang_tua) {
$usernameDefault = $santri->nama_orang_tua;
$sudahDiDb = in_array($usernameDefault, $namaOrtuSudahAda);
$sudahDiMemori = in_array($usernameDefault, $namaOrtuPreviewDipakai);
if ($sudahDiDb || $sudahDiMemori) {
$previewUsername = $usernameDefault . ' - ' . $santri->nama_lengkap;
} else {
$previewUsername = $usernameDefault;
}
$namaOrtuPreviewDipakai[] = $previewUsername;
}
?>
<tr>
<td><?php echo e($santri->id_santri); ?></td>
<td>
<?php if($santri->nis): ?>
<?php echo e($santri->nis); ?>
<?php else: ?>
<span class="text-danger">Belum ada NIS</span>
<?php endif; ?>
</td>
<td><?php echo e($santri->nama_lengkap); ?></td>
<td><?php echo e($santri->nama_orang_tua ?? '-'); ?></td>
<td><?php echo e($santri->kelas ?? '-'); ?></td>
<td>
<?php if($previewUsername): ?>
<code style="font-size:.78rem;"><?php echo e($previewUsername); ?></code>
<?php else: ?>
<span class="text-muted">-</span>
<?php endif; ?>
</td>
<td>
<?php if($santri->nis && $santri->nama_orang_tua): ?>
<form action="<?php echo e(route('admin.users.wali_buat_akun', $santri->id_santri)); ?>"
method="POST" style="display:inline;"
onsubmit="return confirm('Buat akun wali untuk <?php echo e($santri->nama_lengkap); ?>?')">
<?php echo csrf_field(); ?>
<button type="submit" class="btn btn-sm btn-primary">
<i class="fas fa-user-plus"></i> Buat Akun
</button>
</form>
<?php elseif(!$santri->nis): ?>
<span class="text-muted">Isi NIS dulu</span>
<?php else: ?>
<span class="text-muted">Isi nama orang tua dulu</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
<tr>
<td colspan="7" class="text-center text-success">
<i class="fas fa-check"></i> Semua santri sudah punya akun wali.
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', ['isAdmin' => true], \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/users/wali_accounts.blade.php ENDPATH**/ ?>

View File

@ -1,506 +0,0 @@
<?php $__env->startSection('title', 'Preview Import Absensi'); ?>
<?php $__env->startSection('content'); ?>
<?php
use Carbon\Carbon;
$statusStyle = [
'Hadir' => ['bg'=>'#DCFCE7','c'=>'#166534','ic'=>'✅'],
'Terlambat' => ['bg'=>'#FEF9C3','c'=>'#92400E','ic'=>'⏰'],
'Alpa' => ['bg'=>'#FEE2E2','c'=>'#991B1B','ic'=>'❌'],
'Pulang' => ['bg'=>'#FFF7ED','c'=>'#9A3412','ic'=>'🏠'],
'Izin' => ['bg'=>'#F3E8FF','c'=>'#6B21A8','ic'=>'📋'],
'Sakit' => ['bg'=>'#E0F2FE','c'=>'#0C4A6E','ic'=>'🏥'],
];
// ── 1. Kolom kegiatan: UNIK, diurutkan waktu_mulai ───────────────────────────
$kegiatanCols = collect($hasilEnriched)
->flatMap(fn($h) => $h['rows'])
->unique('kegiatan_id')
->sortBy('waktu_mulai')
->values()
->map(fn($r) => [
'kegiatan_id' => $r['kegiatan_id'],
'nama' => $r['nama_kegiatan'],
'waktu_mulai' => $r['waktu_mulai'],
]);
// ── 2. Susun data: [tanggal][id_santri_or_mesin] = data ──────────────────────
$byTanggalSantri = [];
$santriList = []; // untuk urutan santri konsisten
foreach ($hasilEnriched as $h) {
$tgl = $h['tanggal'];
$key = $h['id_santri'] ?? ('__'.$h['id_mesin']);
$byTanggalSantri[$tgl][$key] = $h;
if (!isset($santriList[$key])) {
$santriList[$key] = [
'nama' => $h['nama_web'] ?? $h['nama_mesin'],
'kelas' => $h['kelas'] ?? '-',
'status' => $h['match_status'],
];
}
}
ksort($byTanggalSantri);
// ── 3. Statistik ─────────────────────────────────────────────────────────────
$allRows = collect($hasilEnriched)->flatMap(fn($h) => $h['rows']);
$totalKonflik = $allRows->where('is_conflict', true)->count();
$hadir = $allRows->where('status_final','Hadir')->count();
$terlambat = $allRows->where('status_final','Terlambat')->count();
$alpa = $allRows->where('status_final','Alpa')->count();
$notMapped = collect($hasilEnriched)->where('match_status','NOT_MAPPED')->count();
?>
<style>
/* Sticky top bar */
.top-bar {
position: sticky; top: 0; z-index: 50;
background: #0F172A; color: #F1F5F9;
padding: 8px 16px; display: flex; align-items: center;
gap: 10px; flex-wrap: wrap; box-shadow: 0 2px 8px rgba(0,0,0,.3);
font-size: 13px;
}
.chip {
border-radius: 8px; padding: 4px 10px;
text-align: center; min-width: 56px;
font-size: 11px; line-height: 1.3;
}
.chip .n { font-size: 17px; font-weight: 700; display: block }
.btn-act {
border: none; border-radius: 6px; padding: 6px 12px;
cursor: pointer; font-weight: 600; font-size: 12px;
white-space: nowrap;
}
.btn-save {
border: none; border-radius: 8px; padding: 8px 20px;
cursor: pointer; font-weight: 700; font-size: 13px;
color: #fff; white-space: nowrap; transition: background .2s;
}
/* Matrix table */
.wrap { overflow-x: auto }
.mx { border-collapse: collapse; font-size: 12px; width: 100% }
.mx th, .mx td {
border: 1px solid #E5E7EB; padding: 0;
white-space: nowrap;
}
/* Sticky kolom tanggal + nama */
.col-tgl {
position: sticky; left: 0; z-index: 4;
background: #F8FAFC; min-width: 90px;
border-right: 2px solid #CBD5E1;
padding: 6px 10px; font-size: 11px;
}
.col-nama {
position: sticky; left: 90px; z-index: 4;
background: #F8FAFC; min-width: 130px;
border-right: 2px solid #CBD5E1;
padding: 6px 10px;
}
/* Header kegiatan (rotate) */
.th-wrap {
writing-mode: vertical-rl;
transform: rotate(180deg);
display: flex; align-items: center; justify-content: flex-end;
gap: 2px; height: 80px; padding: 5px 6px;
}
/* Status pill */
.pill {
display: inline-block; border-radius: 8px;
padding: 2px 6px; font-size: 10px; font-weight: 700;
}
/* Konflik cell */
.conf-cell { background: #FFF5F5 !important; border: 2px solid #FCA5A5 !important }
.conf-wrap { display: flex; flex-direction: column }
.conf-opt {
padding: 4px 8px; cursor: pointer;
font-size: 11px; display: flex; align-items: center; gap: 4px;
border-bottom: 1px solid #F1F5F9; transition: background .12s;
}
.conf-opt:last-child { border-bottom: none }
.conf-opt:hover { background: #F8FAFC }
.sel-m { background: #DCFCE7 !important }
.sel-e { background: #DBEAFE !important }
/* Date separator row */
.date-sep td {
background: #1E293B; color: #94A3B8; font-weight: 700;
font-size: 11px; padding: 5px 12px; border-bottom: 2px solid #334155;
}
/* Alternating santri rows */
.row-alt { background: #FAFAFA }
/* Sticky header */
.th-sticky {
position: sticky; top: 52px; z-index: 6;
background: #1E293B;
}
.th-tgl { position: sticky; left: 0; z-index: 8 }
.th-nama { position: sticky; left: 90px; z-index: 8 }
</style>
<form action="<?php echo e(route('admin.mesin.import.store')); ?>" method="POST" id="frm">
<?php echo csrf_field(); ?>
<input type="hidden" name="conflict_strategy" value="manual" id="stratInput">
<?php if(session('error')): ?>
<div style="background:#FEE2E2;border:1px solid #FCA5A5;border-left:4px solid #DC2626;
padding:12px 16px;font-size:13px;color:#991B1B">
<strong> Error:</strong> <?php echo e(session('error')); ?>
</div>
<?php endif; ?>
<div class="top-bar">
<div style="flex:1;min-width:160px">
<div style="color:#64748B;font-size:10px;text-transform:uppercase;letter-spacing:1px">
Preview Import
</div>
<div style="font-weight:700;font-size:14px;margin-top:1px">
<?php echo e(count($santriList)); ?> santri
<?php if($totalKonflik > 0): ?>
· <span style="color:#FCA5A5" id="lbl">
<span id="cnt"><?php echo e($totalKonflik); ?></span> konflik perlu diselesaikan
</span>
<?php else: ?>
· <span style="color:#86EFAC"> Siap disimpan</span>
<?php endif; ?>
</div>
</div>
<div class="chip" style="background:#DCFCE7;color:#166534">
<span class="n"><?php echo e($hadir); ?></span>Hadir
</div>
<div class="chip" style="background:#FEF9C3;color:#92400E">
<span class="n"><?php echo e($terlambat); ?></span>Telat
</div>
<div class="chip" style="background:#FEE2E2;color:#991B1B">
<span class="n"><?php echo e($alpa); ?></span>Alpa
</div>
<?php if($totalKonflik > 0): ?>
<div class="chip" style="background:#FEE2E2;color:#DC2626">
<span class="n" id="chip"><?php echo e($totalKonflik); ?></span>Konflik
</div>
<?php endif; ?>
<?php if($notMapped > 0): ?>
<div class="chip" style="background:#FFF3E8;color:#C05621">
<span class="n"><?php echo e($notMapped); ?></span>Blm Map
</div>
<?php endif; ?>
<?php if($totalKonflik > 0): ?>
<div style="display:flex;flex-direction:column;gap:3px;font-size:11px;color:#94A3B8">
Konflik:
</div>
<button type="button" class="btn-act" style="background:#DCFCE7;color:#166534"
onclick="resolveAll('m');document.getElementById('stratInput').value='mesin'">👆 Mesin</button>
<button type="button" class="btn-act" style="background:#DBEAFE;color:#1D4ED8"
onclick="resolveAll('e');document.getElementById('stratInput').value='exist'">🔒 Lama</button>
<?php endif; ?>
<button type="button" class="btn-save" id="saveBtn"
style="background:<?php echo e($totalKonflik > 0 ? '#64748B' : 'linear-gradient(135deg,#166534,#22C55E)'); ?>"
<?php echo e($totalKonflik > 0 ? 'disabled' : ''); ?>
onclick="submitForm()">
<?php if($totalKonflik > 0): ?> ⏳ Selesaikan konflik dulu
<?php else: ?> 💾 Simpan ke Database <?php endif; ?>
</button>
<a href="<?php echo e(route('admin.mesin.import.index')); ?>"
class="btn-act" style="background:#374151;color:#F1F5F9;text-decoration:none">
Kembali
</a>
</div>
<div style="display:flex;gap:8px;flex-wrap:wrap;padding:8px 16px;
background:#F8FAFC;border-bottom:1px solid #E5E7EB;font-size:11px">
<span style="color:#6B7280;font-weight:600">Status:</span>
<?php $__currentLoopData = $statusStyle; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $st => $s): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<span class="pill" style="background:<?php echo e($s['bg']); ?>;color:<?php echo e($s['c']); ?>">
<?php echo e($s['ic']); ?> <?php echo e($st); ?>
</span>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<span style="color:#9CA3AF;margin-left:4px">| = tidak ada data</span>
<span style="border:2px solid #FCA5A5;border-radius:4px;padding:1px 6px;color:#991B1B">
Konflik
</span>
<span style="color:#9CA3AF">= ada data berbeda, pilih salah satu</span>
<?php if($notMapped > 0): ?>
<span style="margin-left:auto">
⚠️ <?php echo e($notMapped); ?> belum dipetakan →
<a href="<?php echo e(route('admin.mesin.mapping-santri.index')); ?>" target="_blank">
Lengkapi Mapping
</a>
</span>
<?php endif; ?>
</div>
<div class="wrap">
<table class="mx">
<thead>
<tr>
<th class="th-sticky th-tgl"
style="min-width:90px;padding:8px 10px;text-align:left;
color:#94A3B8;font-size:10px;border-right:2px solid #334155">
Tanggal
</th>
<th class="th-sticky th-nama"
style="min-width:130px;padding:8px 10px;text-align:left;
color:#94A3B8;font-size:10px;border-right:2px solid #334155">
Santri
</th>
<?php $__currentLoopData = $kegiatanCols; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kg): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<th class="th-sticky" style="min-width:70px;vertical-align:bottom">
<div class="th-wrap">
<span style="color:#F1F5F9;font-size:10px;font-weight:600">
<?php echo e($kg['nama']); ?>
</span>
<span style="color:#64748B;font-size:9px">
<?php echo e($kg['waktu_mulai']); ?>
</span>
</div>
</th>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $byTanggalSantri; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $tgl => $santriRows): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$tglCarbon = Carbon::parse($tgl);
$tglLabel = $tglCarbon->locale('id')->isoFormat('ddd, D MMM');
$isOdd = ($loop->index % 2 === 1);
?>
<?php $__currentLoopData = $santriList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $key => $info): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$data = $santriRows[$key] ?? null;
$rowBg = ($loop->index % 2 === 0) ? 'white' : '#FAFAFA';
if ($data && $data['match_status'] === 'NOT_MAPPED') $rowBg = '#FFF5F5';
?>
<tr style="background:<?php echo e($rowBg); ?>">
<td class="col-tgl" style="background:<?php echo e($rowBg); ?>">
<?php if($loop->first): ?>
<strong style="color:#1E293B"><?php echo e($tglLabel); ?></strong>
<?php endif; ?>
</td>
<td class="col-nama" style="background:<?php echo e($rowBg); ?>">
<?php if($info['status'] === 'NOT_MAPPED'): ?>
<div style="font-size:10px;font-weight:700;color:#DC2626"> BELUM MAP</div>
<div style="font-size:10px;color:#9CA3AF"><?php echo e($info['nama']); ?></div>
<?php else: ?>
<div style="font-weight:600;color:#1F2937;font-size:12px">
<?php echo e($info['nama']); ?>
</div>
<div style="font-size:10px;color:#9CA3AF"><?php echo e($info['kelas']); ?></div>
<?php endif; ?>
</td>
<?php $__currentLoopData = $kegiatanCols; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kg): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$row = $data
? collect($data['rows'])->firstWhere('kegiatan_id', $kg['kegiatan_id'])
: null;
$sf = $row['status_final'] ?? null;
$st = $sf ? ($statusStyle[$sf] ?? null) : null;
$isConf = $row['is_conflict'] ?? false;
$key2 = "{$kg['kegiatan_id']}_{$data['id_santri']}_{$tgl}";
?>
<td style="padding:0;text-align:center;vertical-align:middle;min-width:70px"
class="<?php echo e($isConf ? 'conf-cell' : ''); ?>">
<?php if(!$data || !$row || $sf === null): ?>
<span style="color:#D1D5DB"></span>
<?php elseif($isConf): ?>
<?php
$ex = $row['existing'];
$exSt = $statusStyle[$ex['status']] ?? ['bg'=>'#F9FAFB','c'=>'#6B7280','ic'=>'?'];
?>
<div class="conf-wrap" data-key="<?php echo e($key2); ?>">
<div class="conf-opt" data-ch="m" onclick="pick('<?php echo e($key2); ?>','m',this)">
<input type="radio" name="conflict_choices[<?php echo e($key2); ?>]"
value="mesin" id="cm_<?php echo e($key2); ?>" style="display:none">
<span>👆</span>
<div>
<span class="pill" style="background:<?php echo e($st['bg']); ?>;color:<?php echo e($st['c']); ?>">
<?php echo e($st['ic']); ?> <?php echo e($sf); ?>
</span>
<div style="font-size:9px;color:#6B7280">
Mesin·<?php echo e($row['jam_scan'] ?? '-'); ?>
</div>
</div>
</div>
<div class="conf-opt" data-ch="e" onclick="pick('<?php echo e($key2); ?>','e',this)">
<input type="radio" name="conflict_choices[<?php echo e($key2); ?>]"
value="exist" id="ce_<?php echo e($key2); ?>" style="display:none">
<span>🔒</span>
<div>
<span class="pill" style="background:<?php echo e($exSt['bg']); ?>;color:<?php echo e($exSt['c']); ?>">
<?php echo e($exSt['ic']); ?> <?php echo e($ex['status']); ?>
</span>
<div style="font-size:9px;color:#6B7280">
<?php echo e($ex['metode'] ?? 'Manual'); ?>
<?php if($ex['waktu']): ?> ·<?php echo e(substr($ex['waktu'],0,5)); ?><?php endif; ?>
</div>
</div>
</div>
<div style="background:#FEE2E2;padding:1px 4px;font-size:9px;
color:#DC2626;font-weight:700;text-align:center">
pilih
</div>
</div>
<?php else: ?>
<div style="padding:5px 3px">
<span class="pill" style="background:<?php echo e($st['bg']); ?>;color:<?php echo e($st['c']); ?>">
<?php echo e($st['ic']); ?> <?php echo e($sf); ?>
</span>
<?php if($row['jam_scan']): ?>
<div style="font-size:9px;color:#9CA3AF;margin-top:1px">
<?php echo e($row['jam_scan']); ?>
<?php if(($row['selisih_menit'] ?? 0) > 0): ?>
<span style="color:#F59E0B">+<?php echo e($row['selisih_menit']); ?>m</span>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
</td>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
<tfoot>
<tr>
<th style="background:#1E293B;color:#94A3B8;font-size:10px;
padding:6px 10px;border-right:2px solid #334155;
position:sticky;left:0">Tanggal</th>
<th style="background:#1E293B;color:#94A3B8;font-size:10px;
padding:6px 10px;border-right:2px solid #334155;
position:sticky;left:90px">Santri</th>
<?php $__currentLoopData = $kegiatanCols; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kg): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<th style="background:#1E293B;color:#94A3B8;font-size:9px;padding:4px 6px">
<?php echo e($kg['nama']); ?>
</th>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tr>
</tfoot>
</table>
</div>
<div style="padding:8px 16px;background:#F8FAFC;border-top:1px solid #E5E7EB;
font-size:11px;color:#6B7280;display:flex;gap:12px;flex-wrap:wrap">
<span>📊 <?php echo e(count($santriList)); ?> santri · <?php echo e(count($byTanggalSantri)); ?> hari</span>
<span> <?php echo e($hadir); ?> Hadir</span>
<span> <?php echo e($terlambat); ?> Terlambat</span>
<span> <?php echo e($alpa); ?> Alpa</span>
<?php if($totalKonflik > 0): ?>
<span style="color:#DC2626"> <?php echo e($totalKonflik); ?> Konflik</span>
<?php endif; ?>
<span style="margin-left:auto">
Toleransi: <?php echo e($tolSebelum); ?>m sebelum / <?php echo e($tolSesudah); ?>m sesudah
</span>
</div>
</form>
<script>
const totalK = <?php echo e($totalKonflik); ?>;
const done = new Set();
function pick(key, ch, el) {
const wrap = el.closest('.conf-wrap');
wrap.querySelectorAll('.conf-opt').forEach(o => {
o.classList.remove('sel-m','sel-e');
});
el.classList.add(ch === 'm' ? 'sel-m' : 'sel-e');
const radio = document.getElementById((ch==='m'?'cm_':'ce_') + key);
if (radio) radio.checked = true;
done.add(key);
updateUI();
}
function resolveAll(ch) {
document.querySelectorAll('.conf-wrap').forEach(wrap => {
const key = wrap.dataset.key;
const opt = wrap.querySelector('[data-ch="'+ch+'"]');
if (opt) pick(key, ch, opt);
});
}
function submitForm() {
const btn = document.getElementById('saveBtn');
btn.disabled = true;
btn.style.background = '#64748B';
btn.textContent = '⏳ Menyimpan...';
document.getElementById('frm').submit();
}
function updateUI() {
const rem = totalK - done.size;
const btn = document.getElementById('saveBtn');
const lbl = document.getElementById('lbl');
const chip = document.getElementById('chip');
if (rem <= 0) {
btn.disabled = false;
btn.style.background = 'linear-gradient(135deg,#166534,#22C55E)';
btn.textContent = '💾 Simpan ke Database';
if (lbl) lbl.innerHTML = '<span style="color:#86EFAC">✅ Semua konflik selesai</span>';
if (chip) chip.textContent = '0';
} else {
btn.disabled = true;
btn.style.background = '#64748B';
btn.textContent = '⏳ Selesaikan ' + rem + ' konflik';
if (lbl) lbl.innerHTML = '<span style="color:#FCA5A5">⚡ <span id="cnt">'+rem+'</span> konflik</span>';
if (chip) chip.textContent = rem;
}
}
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/mesin/import/preview.blade.php ENDPATH**/ ?>

View File

@ -1,183 +0,0 @@
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-history"></i> Riwayat Capaian Santri</h2>
</div>
<div class="content-box" style="margin-bottom: 14px;">
<div style="display: flex; align-items: center; gap: 20px;">
<div class="icon-wrapper icon-wrapper-lg">
<i class="fas fa-user-graduate"></i>
</div>
<div style="flex: 1;">
<h3 style="margin: 0 0 5px 0;"><?php echo e($santri->nama_lengkap); ?></h3>
<p style="margin: 0; color: var(--text-light);">
<strong>NIS:</strong> <?php echo e($santri->nis); ?> |
<strong>Kelas:</strong> <span class="badge badge-secondary"><?php echo e($santri->kelas); ?></span>
</p>
</div>
<div style="text-align: right; display: flex; gap: 10px; justify-content: flex-end;">
<a href="<?php echo e(route('admin.capaian.index')); ?>" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali ke Data Capaian
</a>
<a href="<?php echo e(route('admin.santri.show', $santri)); ?>" class="btn btn-info">
<i class="fas fa-user"></i> Profil Santri
</a>
</div>
</div>
</div>
<div class="row-cards">
<div class="card card-info">
<h3>Total Capaian</h3>
<div class="card-value"><?php echo e($totalCapaian); ?></div>
<p class="text-muted">Data capaian tercatat</p>
<i class="fas fa-clipboard-list card-icon"></i>
</div>
<div class="card card-success">
<h3>Rata-rata Progress</h3>
<div class="card-value"><?php echo e(number_format($rataRataPersentase, 1)); ?>%</div>
<p class="text-muted">Progress keseluruhan</p>
<i class="fas fa-chart-line card-icon"></i>
</div>
<div class="card card-primary">
<h3>Al-Qur'an</h3>
<div class="card-value-small"><?php echo e(number_format($statistikKategori['Al-Qur\'an'] ?? 0, 1)); ?>%</div>
<p class="text-muted">Progress kategori</p>
<i class="fas fa-book-quran card-icon"></i>
</div>
<div class="card card-warning">
<h3>Hadist</h3>
<div class="card-value-small"><?php echo e(number_format($statistikKategori['Hadist'] ?? 0, 1)); ?>%</div>
<p class="text-muted">Progress kategori</p>
<i class="fas fa-scroll card-icon"></i>
</div>
</div>
<div class="content-box" style="margin-bottom: 14px;">
<form method="GET" action="<?php echo e(route('admin.capaian.riwayat-santri', $santri->id_santri)); ?>" class="filter-form-inline">
<select name="id_semester" class="form-control" style="width: 250px;">
<option value="">Semua Semester</option>
<?php $__currentLoopData = $semesters; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $semester): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($semester->id_semester); ?>" <?php echo e(request('id_semester') == $semester->id_semester ? 'selected' : ''); ?>>
<?php echo e($semester->nama_semester); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
<input type="text" name="search" class="form-control" placeholder="Cari nama materi..."
value="<?php echo e(request('search')); ?>" style="width: 300px;">
<button type="submit" class="btn btn-primary">
<i class="fas fa-search"></i> Filter
</button>
<?php if(request()->filled('id_semester') || request()->filled('search')): ?>
<a href="<?php echo e(route('admin.capaian.riwayat-santri', $santri->id_santri)); ?>" class="btn btn-secondary">
<i class="fas fa-redo"></i> Reset
</a>
<?php endif; ?>
<a href="<?php echo e(route('admin.capaian.create', ['id_santri' => $santri->id_santri])); ?>" class="btn btn-success" style="margin-left: auto;">
<i class="fas fa-plus"></i> Tambah Capaian
</a>
</form>
</div>
<div class="content-box">
<?php if($capaians->count() > 0): ?>
<?php
$groupedCapaians = $capaians->groupBy(function($item) {
return $item->materi->kategori;
});
?>
<?php $__currentLoopData = ['Al-Qur\'an', 'Hadist', 'Materi Tambahan']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kategori): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php if(isset($groupedCapaians[$kategori]) && $groupedCapaians[$kategori]->count() > 0): ?>
<div style="margin-bottom: 22px;">
<h4 style="color: var(--primary-dark); margin-bottom: 15px; padding-bottom: 10px; border-bottom: 2px solid var(--primary-light);">
<i class="fas fa-<?php echo e($kategori == 'Al-Qur\'an' ? 'book-quran' : ($kategori == 'Hadist' ? 'scroll' : 'book')); ?>"></i>
Kategori: <?php echo e($kategori); ?>
</h4>
<table class="data-table">
<thead>
<tr>
<th style="width: 5%;">No</th>
<th style="width: 25%;">Materi</th>
<th style="width: 15%;">Semester</th>
<th style="width: 15%;">Halaman</th>
<th style="width: 15%;">Progress</th>
<th style="width: 15%;">Tanggal Input</th>
<th class="text-center" style="width: 10%;">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $groupedCapaians[$kategori]; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $capaian): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($index + 1); ?></td>
<td>
<strong><?php echo e($capaian->materi->nama_kitab); ?></strong><br>
<small class="text-muted">Total: <?php echo e($capaian->materi->total_halaman); ?> hal</small>
</td>
<td>
<small><?php echo e($capaian->semester->nama_semester); ?></small>
</td>
<td class="text-center">
<span class="badge badge-info">
<?php echo e($capaian->jumlah_halaman_selesai); ?> / <?php echo e($capaian->materi->total_halaman); ?>
</span>
</td>
<td>
<?php echo $capaian->persentase_badge; ?>
<div class="progress-bar" style="margin-top: 5px; height: 8px;">
<div class="progress-fill" style="width: <?php echo e($capaian->persentase); ?>%; background: linear-gradient(90deg, var(--primary-color), var(--success-color));"></div>
</div>
</td>
<td><?php echo e($capaian->tanggal_input->format('d/m/Y')); ?></td>
<td class="text-center">
<div class="btn-group">
<a href="<?php echo e(route('admin.capaian.show', $capaian)); ?>"
class="btn btn-sm btn-info" title="Detail">
<i class="fas fa-eye"></i>
</a>
<a href="<?php echo e(route('admin.capaian.edit', $capaian)); ?>"
class="btn btn-sm btn-warning" title="Edit">
<i class="fas fa-edit"></i>
</a>
</div>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<?php endif; ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<div style="margin-top: 14px;">
<?php echo e($capaians->links()); ?>
</div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-clipboard-list"></i>
<h3>Belum Ada Capaian</h3>
<p>Santri ini belum memiliki data capaian.</p>
<a href="<?php echo e(route('admin.capaian.create', ['id_santri' => $santri->id_santri])); ?>" class="btn btn-primary">
<i class="fas fa-plus"></i> Tambah Capaian Pertama
</a>
</div>
<?php endif; ?>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/capaian/riwayat-santri.blade.php ENDPATH**/ ?>

View File

@ -1,264 +0,0 @@
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-chart-bar"></i> Rekap Absensi: <?php echo e($kegiatan->nama_kegiatan); ?></h2>
</div>
<div style="background: #fff; border-radius: 12px; padding: 18px 22px; margin-bottom: 16px; box-shadow: 0 2px 12px rgba(0,0,0,0.06); border-left: 4px solid #2563eb;">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 12px;">
<div>
<h3 style="margin: 0; font-size: 1rem; color: #1a2332;">
<i class="fas fa-users" style="color: #2563eb;"></i> Total Semua Santri: <strong><?php echo e($totalSantriEligible); ?></strong>
</h3>
<p style="margin: 4px 0 0; font-size: 0.84rem; color: #6b7280;">
Sudah absen: <strong style="color: #059669;"><?php echo e($santriSudahAbsen); ?></strong>
&nbsp;·&nbsp;
Belum absen: <strong style="color: <?php echo e($belumAbsen > 0 ? '#dc2626' : '#059669'); ?>;"><?php echo e($belumAbsen); ?></strong>
</p>
</div>
<div style="text-align: right;">
<div style="font-size: 1.6rem; font-weight: 800; color: <?php echo e($persenHadir >= 85 ? '#059669' : ($persenHadir >= 70 ? '#d97706' : '#dc2626')); ?>;">
<?php echo e($persenHadir); ?>%
</div>
<div style="font-size: 0.78rem; color: #6b7280;">Kehadiran</div>
</div>
</div>
<div style="height: 28px; background: #f3f4f6; border-radius: 14px; overflow: hidden; display: flex;">
<?php
$pctHadir = $totalSantriEligible > 0 ? round(($stats['Hadir'] ?? 0) / $totalSantriEligible * 100, 1) : 0;
$pctTerlambat = $totalSantriEligible > 0 ? round(($stats['Terlambat'] ?? 0) / $totalSantriEligible * 100, 1) : 0;
$pctIzin = $totalSantriEligible > 0 ? round(($stats['Izin'] ?? 0) / $totalSantriEligible * 100, 1) : 0;
$pctSakit = $totalSantriEligible > 0 ? round(($stats['Sakit'] ?? 0) / $totalSantriEligible * 100, 1) : 0;
$pctAlpa = $totalSantriEligible > 0 ? round(($stats['Alpa'] ?? 0) / $totalSantriEligible * 100, 1) : 0;
$pctBelum = $totalSantriEligible > 0 ? round($belumAbsen / $totalSantriEligible * 100, 1) : 0;
?>
<?php if($pctHadir > 0): ?>
<div style="width: <?php echo e($pctHadir); ?>%; background: #22c55e; display: flex; align-items: center; justify-content: center; color: white; font-size: 0.73rem; font-weight: 700;" title="Hadir: <?php echo e($stats['Hadir'] ?? 0); ?>">
<?php echo e(($stats['Hadir'] ?? 0) > 0 ? ($stats['Hadir'] ?? 0) : ''); ?>
</div>
<?php endif; ?>
<?php if($pctTerlambat > 0): ?>
<div style="width: <?php echo e($pctTerlambat); ?>%; background: #FF9800; display: flex; align-items: center; justify-content: center; color: white; font-size: 0.73rem; font-weight: 700;" title="Terlambat: <?php echo e($stats['Terlambat'] ?? 0); ?>">
<?php echo e(($stats['Terlambat'] ?? 0) > 0 ? ($stats['Terlambat'] ?? 0) : ''); ?>
</div>
<?php endif; ?>
<?php if($pctIzin > 0): ?>
<div style="width: <?php echo e($pctIzin); ?>%; background: #f59e0b; display: flex; align-items: center; justify-content: center; color: white; font-size: 0.73rem; font-weight: 700;" title="Izin: <?php echo e($stats['Izin'] ?? 0); ?>">
<?php echo e(($stats['Izin'] ?? 0) > 0 ? ($stats['Izin'] ?? 0) : ''); ?>
</div>
<?php endif; ?>
<?php if($pctSakit > 0): ?>
<div style="width: <?php echo e($pctSakit); ?>%; background: #3b82f6; display: flex; align-items: center; justify-content: center; color: white; font-size: 0.73rem; font-weight: 700;" title="Sakit: <?php echo e($stats['Sakit'] ?? 0); ?>">
<?php echo e(($stats['Sakit'] ?? 0) > 0 ? ($stats['Sakit'] ?? 0) : ''); ?>
</div>
<?php endif; ?>
<?php if($pctAlpa > 0): ?>
<div style="width: <?php echo e($pctAlpa); ?>%; background: #ef4444; display: flex; align-items: center; justify-content: center; color: white; font-size: 0.73rem; font-weight: 700;" title="Alpa: <?php echo e($stats['Alpa'] ?? 0); ?>">
<?php echo e(($stats['Alpa'] ?? 0) > 0 ? ($stats['Alpa'] ?? 0) : ''); ?>
</div>
<?php endif; ?>
<?php if($pctBelum > 0): ?>
<div style="width: <?php echo e($pctBelum); ?>%; background: #d1d5db; display: flex; align-items: center; justify-content: center; color: #6b7280; font-size: 0.73rem; font-weight: 700;" title="Belum Absen: <?php echo e($belumAbsen); ?>">
<?php echo e($belumAbsen > 0 ? $belumAbsen : ''); ?>
</div>
<?php endif; ?>
</div>
<div style="display: flex; gap: 14px; flex-wrap: wrap; margin-top: 8px; font-size: 0.75rem; color: #6b7280;">
<span><span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#22c55e;margin-right:3px;"></span> Hadir</span>
<span><span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#FF9800;margin-right:3px;"></span> Terlambat</span>
<span><span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#f59e0b;margin-right:3px;"></span> Izin</span>
<span><span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#3b82f6;margin-right:3px;"></span> Sakit</span>
<span><span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#ef4444;margin-right:3px;"></span> Alpa</span>
<span><span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#d1d5db;margin-right:3px;"></span> Belum Absen</span>
</div>
</div>
<div class="row-cards">
<div class="card card-success">
<h3>Hadir</h3>
<div class="card-value"><?php echo e($stats['Hadir'] ?? 0); ?></div>
<i class="fas fa-check-circle card-icon"></i>
</div>
<div class="card" style="border-top: 3px solid #FF9800;">
<h3>Terlambat</h3>
<div class="card-value"><?php echo e($stats['Terlambat'] ?? 0); ?></div>
<i class="fas fa-clock card-icon" style="color: #FF9800;"></i>
</div>
<div class="card card-warning">
<h3>Izin</h3>
<div class="card-value"><?php echo e($stats['Izin'] ?? 0); ?></div>
<i class="fas fa-info-circle card-icon"></i>
</div>
<div class="card card-info">
<h3>Sakit</h3>
<div class="card-value"><?php echo e($stats['Sakit'] ?? 0); ?></div>
<i class="fas fa-heartbeat card-icon"></i>
</div>
<div class="card card-danger">
<h3>Alpa</h3>
<div class="card-value"><?php echo e($stats['Alpa'] ?? 0); ?></div>
<i class="fas fa-times-circle card-icon"></i>
</div>
<div class="card" style="border-top: 3px solid #9ca3af;">
<h3>Belum Absen</h3>
<div class="card-value" style="color: <?php echo e($belumAbsen > 0 ? '#dc2626' : '#6b7280'); ?>;"><?php echo e($belumAbsen); ?></div>
<i class="fas fa-hourglass-half card-icon" style="color: #9ca3af;"></i>
</div>
</div>
<div class="content-box">
<div style="margin-bottom: 14px;">
<form method="GET" class="filter-form-inline">
<input type="date" name="tanggal" class="form-control" value="<?php echo e(request('tanggal')); ?>">
<input type="month" name="bulan" class="form-control" value="<?php echo e(request('bulan')); ?>" placeholder="Pilih Bulan">
<select name="kelas_id" class="form-control" style="max-width: 200px;">
<option value="">Semua Kelas</option>
<?php $__currentLoopData = $kelasFilterList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelas): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($kelas->id); ?>" <?php echo e(request('kelas_id') == $kelas->id ? 'selected' : ''); ?>>
<?php echo e($kelas->nama_kelas); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
<button type="submit" class="btn btn-primary">
<i class="fas fa-filter"></i> Filter
</button>
<?php if(request()->hasAny(['tanggal', 'bulan', 'kelas_id'])): ?>
<a href="<?php echo e(route('admin.absensi-kegiatan.rekap', $kegiatan->kegiatan_id)); ?>" class="btn btn-secondary">
<i class="fas fa-times"></i> Reset
</a>
<?php endif; ?>
<a href="<?php echo e(route('admin.kegiatan.index')); ?>" class="btn btn-secondary" style="margin-left: auto;">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</form>
</div>
<?php if($absensis->count() > 0): ?>
<?php $__currentLoopData = $absensiPerKelas; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $namaKelas => $kelasAbsensis): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div class="content-box" style="margin-bottom: 18px;">
<h4 style="margin: 0 0 12px; color: var(--primary-color);">
<i class="fas fa-school"></i> Kelas: <?php echo e($namaKelas); ?>
<span class="badge badge-secondary" style="font-size: 0.8rem; margin-left: 6px;">
<?php echo e($kelasAbsensis->count()); ?> data
</span>
</h4>
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">No</th>
<th style="width: 100px;">Tanggal</th>
<th style="width: 100px;">ID Santri</th>
<th>Nama Santri</th>
<th style="width: 120px; text-align: center;">Status</th>
<th style="width: 100px;">Metode</th>
<th style="width: 100px;">Waktu</th>
<th style="width: 120px; text-align: center;">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $kelasAbsensis; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $absensi): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($index + 1); ?></td>
<td><?php echo e($absensi->tanggal->format('d/m/Y')); ?></td>
<td><strong><?php echo e($absensi->id_santri); ?></strong></td>
<td><?php echo e($absensi->santri->nama_lengkap); ?></td>
<td class="text-center"><?php echo $absensi->status_badge; ?></td>
<td>
<?php if($absensi->metode_absen == 'RFID'): ?>
<span class="badge badge-primary"><i class="fas fa-id-card"></i> RFID</span>
<?php elseif($absensi->metode_absen == 'Import_Mesin'): ?>
<span class="badge" style="background: #7c3aed; color: white;"><i class="fas fa-desktop"></i> Mesin</span>
<?php else: ?>
<span class="badge badge-secondary"><i class="fas fa-hand-pointer"></i> Manual</span>
<?php endif; ?>
</td>
<td><?php echo e($absensi->waktu_absen ? date('H:i', strtotime($absensi->waktu_absen)) : '-'); ?></td>
<td class="text-center">
<div style="display: flex; gap: 4px; justify-content: center;">
<a href="<?php echo e(route('admin.absensi-kegiatan.edit', $absensi->id)); ?>" class="btn btn-sm btn-warning" title="Edit">
<i class="fas fa-edit"></i>
</a>
<form action="<?php echo e(route('admin.absensi-kegiatan.hapus', $absensi->id)); ?>" method="POST" style="display: inline;" onsubmit="return confirm('Yakin hapus absensi <?php echo e($absensi->santri->nama_lengkap); ?>?');">
<?php echo csrf_field(); ?>
<?php echo method_field('DELETE'); ?>
<button type="submit" class="btn btn-sm btn-danger" title="Hapus">
<i class="fas fa-trash"></i>
</button>
</form>
</div>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-clipboard"></i>
<h3>Belum Ada Data Absensi</h3>
<p>Silakan input absensi terlebih dahulu.</p>
<a href="<?php echo e(route('admin.absensi-kegiatan.input', $kegiatan->kegiatan_id)); ?>" class="btn btn-success">
<i class="fas fa-clipboard-check"></i> Input Absensi
</a>
</div>
<?php endif; ?>
<?php if($santriBelumAbsen->count() > 0): ?>
<div class="content-box" style="margin-top: 18px; border-left: 4px solid #f59e0b;">
<h4 style="margin: 0 0 12px; color: #d97706;">
<i class="fas fa-exclamation-triangle"></i> Santri Belum Absen (<?php echo e($santriBelumAbsen->count()); ?> orang)
<?php if(request('tanggal')): ?>
<span style="font-size: 0.8rem; font-weight: 400; color: #6b7280; margin-left: 6px;">
Tanggal: <?php echo e(\Carbon\Carbon::parse(request('tanggal'))->format('d/m/Y')); ?>
</span>
<?php endif; ?>
</h4>
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">No</th>
<th style="width: 100px;">ID Santri</th>
<th>Nama Santri</th>
<th style="width: 150px;">Kelas</th>
<th style="width: 120px; text-align: center;">Status</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $santriBelumAbsen; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $santri): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($index + 1); ?></td>
<td><strong><?php echo e($santri->id_santri); ?></strong></td>
<td><?php echo e($santri->nama_lengkap); ?></td>
<td><?php echo e(optional(optional($santri->kelasPrimary)->kelas)->nama_kelas ?? '-'); ?></td>
<td class="text-center">
<span class="badge" style="background: #fef3c7; color: #92400e; padding: 4px 10px; border-radius: 12px; font-size: 0.8rem;">
<i class="fas fa-hourglass-half"></i> Belum Absen
</span>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kegiatan/absensi/rekap.blade.php ENDPATH**/ ?>

View File

@ -1,194 +0,0 @@

<?php $__env->startSection('title', 'Master Pelanggaran'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-list-ul"></i> Kategori Pelanggaran</h2>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger">
<i class="fas fa-exclamation-circle"></i> <?php echo e(session('error')); ?>
</div>
<?php endif; ?>
<!-- Filter -->
<div class="content-box" style="margin-bottom: 14px;">
<form method="GET" action="<?php echo e(route('admin.kategori-pelanggaran.index')); ?>">
<div style="display: grid; grid-template-columns: 2fr 1fr auto; gap: 11px; align-items: end;">
<div class="form-group" style="margin-bottom: 0;">
<label for="id_klasifikasi">
<i class="fas fa-filter form-icon"></i>
Filter Klasifikasi
</label>
<select name="id_klasifikasi" id="id_klasifikasi" class="form-control">
<option value="">-- Semua Klasifikasi --</option>
<?php $__currentLoopData = $klasifikasiList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kl): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($kl->id_klasifikasi); ?>"
<?php echo e(request('id_klasifikasi') == $kl->id_klasifikasi ? 'selected' : ''); ?>>
<?php echo e($kl->nama_klasifikasi); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div class="form-group" style="margin-bottom: 0;">
<label for="is_active">
<i class="fas fa-toggle-on form-icon"></i>
Status
</label>
<select name="is_active" id="is_active" class="form-control">
<option value="">-- Semua Status --</option>
<option value="1" <?php echo e(request('is_active') == '1' ? 'selected' : ''); ?>>Aktif</option>
<option value="0" <?php echo e(request('is_active') == '0' ? 'selected' : ''); ?>>Nonaktif</option>
</select>
</div>
<div class="btn-group" style="margin-bottom: 0;">
<button type="submit" class="btn btn-primary">
<i class="fas fa-search"></i> Filter
</button>
<a href="<?php echo e(route('admin.kategori-pelanggaran.index')); ?>" class="btn btn-secondary">
<i class="fas fa-redo"></i> Reset
</a>
</div>
</div>
</form>
</div>
<!-- Tabel Data -->
<div class="content-box">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px;">
<h3 style="margin: 0; color: var(--primary-color);">
<i class="fas fa-table"></i> Daftar Pelanggaran
</h3>
<div style="display: flex; gap: 10px;">
<a href="<?php echo e(route('admin.klasifikasi-pelanggaran.index')); ?>" class="btn btn-warning">
<i class="fas fa-tags"></i> Klasifikasi Pelanggaran
</a>
<a href="<?php echo e(route('admin.kategori-pelanggaran.create')); ?>" class="btn btn-primary">
<i class="fas fa-plus-circle"></i> Tambah Pelanggaran
</a>
</div>
</div>
<?php if($data->isNotEmpty()): ?>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 50px;">No</th>
<th style="width: 100px;">ID</th>
<th style="width: 150px;">Klasifikasi</th>
<th>Nama Pelanggaran</th>
<th style="width: 80px; text-align: center;">Poin</th>
<th style="width: 100px; text-align: center;">Digunakan</th>
<th style="width: 100px; text-align: center;">Status</th>
<th style="width: 200px; text-align: center;">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $data; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($index + 1); ?></td>
<td><span class="badge badge-primary"><?php echo e($item->id_kategori); ?></span></td>
<td>
<?php if($item->klasifikasi): ?>
<span class="badge badge-info"><?php echo e($item->klasifikasi->nama_klasifikasi); ?></span>
<?php else: ?>
<span class="badge badge-secondary">-</span>
<?php endif; ?>
</td>
<td>
<strong><?php echo e($item->nama_pelanggaran); ?></strong>
<?php if($item->kafaroh): ?>
<br><small style="color: var(--text-light);">
<i class="fas fa-hands"></i> Kafaroh: <?php echo e(Str::limit($item->kafaroh, 50)); ?>
</small>
<?php endif; ?>
</td>
<td style="text-align: center;">
<span class="badge badge-danger" style="font-size: 0.9em;">
<i class="fas fa-star"></i> <?php echo e($item->poin); ?>
</span>
</td>
<td style="text-align: center;">
<span class="badge badge-secondary">
<?php echo e($item->riwayatPelanggaran->count()); ?>x
</span>
</td>
<td style="text-align: center;">
<?php if($item->is_active): ?>
<span class="badge badge-success">Aktif</span>
<?php else: ?>
<span class="badge badge-secondary">Nonaktif</span>
<?php endif; ?>
</td>
<td style="text-align: center;">
<div style="display: flex; justify-content: center; gap: 8px;">
<a href="<?php echo e(route('admin.kategori-pelanggaran.show', $item)); ?>"
class="btn btn-sm btn-success"
title="Detail">
<i class="fas fa-eye"></i>
</a>
<a href="<?php echo e(route('admin.kategori-pelanggaran.edit', $item)); ?>"
class="btn btn-sm btn-warning"
title="Edit">
<i class="fas fa-edit"></i>
</a>
<form action="<?php echo e(route('admin.kategori-pelanggaran.destroy', $item)); ?>"
method="POST"
style="display: inline;"
onsubmit="return confirm('Yakin ingin menghapus pelanggaran <?php echo e($item->nama_pelanggaran); ?>?');">
<?php echo csrf_field(); ?>
<?php echo method_field('DELETE'); ?>
<button type="submit"
class="btn btn-sm btn-danger"
title="Hapus">
<i class="fas fa-trash"></i>
</button>
</form>
</div>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-folder-open"></i>
<h3>Belum ada data pelanggaran</h3>
<p>Silakan tambah pelanggaran baru menggunakan tombol di atas.</p>
<a href="<?php echo e(route('admin.kategori-pelanggaran.create')); ?>" class="btn btn-primary">
<i class="fas fa-plus"></i> Tambah Pelanggaran
</a>
</div>
<?php endif; ?>
</div>
<script>
// Auto hide alerts after 5 seconds
setTimeout(function() {
const alerts = document.querySelectorAll('.alert');
alerts.forEach(alert => {
alert.style.transition = 'opacity 0.5s';
alert.style.opacity = '0';
setTimeout(() => alert.remove(), 500);
});
}, 5000);
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kategori_pelanggaran/index.blade.php ENDPATH**/ ?>

View File

@ -1,465 +0,0 @@
<?php $__env->startSection('content'); ?>
<style>
.page-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; }
.page-header h2 { margin: 0; color: var(--primary-dark); font-size: 1.5rem; display: flex; align-items: center; gap: 10px; }
.btn-back { padding: 8px 16px; background: #6B7280; color: #fff; border: none; border-radius: 8px; font-size: 0.85rem; text-decoration: none; display: inline-flex; align-items: center; gap: 6px; transition: background 0.2s; }
.btn-back:hover { background: #4B5563; color: #fff; }
.info-box-header { background: linear-gradient(135deg, var(--primary-color), #059669); color: #fff; padding: 20px 24px; border-radius: 12px; margin-bottom: 14px; box-shadow: 0 4px 12px rgba(16,185,129,0.2); }
.info-box-header h3 { margin: 0 0 6px; font-size: 1.3rem; display: flex; align-items: center; gap: 10px; }
.info-box-header .meta { opacity: 0.9; font-size: 0.88rem; display: flex; flex-wrap: wrap; gap: 12px; margin-top: 6px; }
.info-box-header .periode-tag { background: rgba(255,255,255,0.2); padding: 3px 10px; border-radius: 20px; font-size: 0.8rem; display: inline-flex; align-items: center; gap: 5px; }
/* 6 KPI cards */
.stats-row {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 12px;
margin-bottom: 14px;
}
@media (max-width: 1100px) { .stats-row { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 600px) { .stats-row { grid-template-columns: repeat(2, 1fr); } }
.stat-card { background: #fff; padding: 14px 12px; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); display: flex; align-items: center; gap: 12px; }
.stat-card .icon { font-size: 1.4rem; width: 40px; height: 40px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; border-radius: 10px; }
.stat-card.hadir .icon { background: #D1FAE5; color: #065F46; }
.stat-card.terlambat .icon { background: #FFF3E0; color: #E65100; }
.stat-card.izin .icon { background: #FEF3C7; color: #92400E; }
.stat-card.sakit .icon { background: #DBEAFE; color: #1E40AF; }
.stat-card.alpa .icon { background: #FEE2E2; color: #991B1B; }
.stat-card.pulang .icon { background: #F3E8FF; color: #6B21A8; }
.stat-card .content { flex: 1; min-width: 0; }
.stat-card .label { font-size: 0.78rem; color: var(--text-light); margin-bottom: 2px; }
.stat-card .value { font-size: 1.5rem; font-weight: 700; color: var(--primary-dark); line-height: 1.2; }
.filter-box { background: #fff; padding: 14px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); margin-bottom: 14px; }
.filter-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 11px; }
.form-group { margin: 0; }
.form-group label { display: block; font-size: 0.85rem; margin-bottom: 5px; color: var(--text-light); font-weight: 500; }
.form-control { width: 100%; padding: 8px 12px; border: 1px solid #e2e8f0; border-radius: 8px; font-size: 0.85rem; }
.btn-filter { background: var(--primary-color); color: #fff; border: none; padding: 9px 16px; border-radius: 8px; cursor: pointer; font-size: 0.85rem; display: inline-flex; align-items: center; gap: 6px; transition: all 0.2s; }
.btn-filter:hover { background: #059669; }
.btn-reset { background: #6B7280; color: #fff; border: none; padding: 9px 12px; border-radius: 8px; font-size: 0.85rem; display: inline-flex; align-items: center; gap: 6px; text-decoration: none; }
.btn-reset:hover { background: #4B5563; color: #fff; }
.day-group { margin-bottom: 18px; background: #fff; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); overflow: hidden; }
.day-header { background: linear-gradient(135deg, #f0fdf4 0%, #E8F7F2 100%); padding: 14px 18px; display: flex; justify-content: space-between; align-items: center; border-bottom: 2px solid #E8F7F2; cursor: pointer; transition: background 0.2s; user-select: none; }
.day-header:hover { background: linear-gradient(135deg, #E8F7F2 0%, #d1f2e8 100%); }
.day-title { font-weight: 700; font-size: 1rem; color: var(--primary-dark); display: flex; align-items: center; gap: 8px; }
.day-title i { color: var(--primary-color); }
.day-stats { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.mini-badge { padding: 4px 10px; border-radius: 20px; font-size: 0.75rem; font-weight: 600; display: inline-flex; align-items: center; gap: 4px; }
.mini-badge.hadir { background: #D1FAE5; color: #065F46; }
.mini-badge.terlambat { background: #FFF3E0; color: #E65100; }
.mini-badge.izin { background: #FEF3C7; color: #92400E; }
.mini-badge.sakit { background: #DBEAFE; color: #1E40AF; }
.mini-badge.alpa { background: #FEE2E2; color: #991B1B; }
.mini-badge.pulang { background: #F3E8FF; color: #6B21A8; }
.day-body table { width: 100%; border-collapse: collapse; }
.day-body table thead { background: #f8fafc; }
.day-body table th { padding: 10px 14px; text-align: left; font-weight: 600; font-size: 0.82rem; color: #64748b; border-bottom: 1px solid #e2e8f0; }
.day-body table td { padding: 9px 14px; font-size: 0.85rem; border-bottom: 1px solid #f1f5f9; }
.day-body table tbody tr:last-child td { border-bottom: none; }
.day-body table tbody tr:hover { background: #f8fafc; }
.toggle-icon { transition: transform 0.3s; font-size: 0.85rem; color: #94a3b8; }
.toggle-icon.collapsed { transform: rotate(-90deg); }
.empty-state { text-align: center; padding: 36px 20px; color: var(--text-light); background: #fff; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
.empty-state i { font-size: 3.5rem; margin-bottom: 14px; opacity: 0.3; display: block; }
.pagination { display: flex; justify-content: center; align-items: center; gap: 6px; margin-top: 14px; }
.pagination a, .pagination span { padding: 6px 12px; border: 1px solid #e2e8f0; border-radius: 6px; font-size: 0.82rem; text-decoration: none; color: var(--text-dark); transition: all 0.2s; }
.pagination a:hover { background: var(--primary-color); color: #fff; border-color: var(--primary-color); }
.pagination .active { background: var(--primary-color); color: #fff; border-color: var(--primary-color); font-weight: 600; }
.pagination .disabled { color: #cbd5e1; cursor: not-allowed; }
@media (max-width: 768px) {
.day-header { flex-direction: column; align-items: flex-start; gap: 8px; }
.day-body table th:nth-child(2), .day-body table td:nth-child(2) { display: none; }
.day-body table th:nth-child(7), .day-body table td:nth-child(7) { display: none; }
}
</style>
<?php
// Ambil range dari query string (diteruskan dari index)
$defaultDari = now()->startOfWeek(\Carbon\Carbon::MONDAY)->format('Y-m-d');
$defaultSampai = now()->endOfWeek(\Carbon\Carbon::SUNDAY)->format('Y-m-d');
$filterDari = request('tanggal_dari', $defaultDari);
$filterSampai = request('tanggal_sampai', $defaultSampai);
$filterBulan = request('bulan', '');
if ($filterBulan) {
$periodeLabel = 'Bulan ' . \Carbon\Carbon::parse($filterBulan . '-01')->locale('id')->isoFormat('MMMM Y');
} else {
$periodeLabel = \Carbon\Carbon::parse($filterDari)->locale('id')->isoFormat('D MMM Y')
. ' '
. \Carbon\Carbon::parse($filterSampai)->locale('id')->isoFormat('D MMM Y');
}
// Hitung KPI dari data yang sudah difilter (semua halaman, bukan hanya halaman ini)
// $stats sudah dihitung di controller berdasarkan filter — gunakan langsung
// Tapi jika controller belum menghitung per filter, hitung dari koleksi paginator saat ini
// Gunakan $stats dari controller jika ada, fallback ke hitung manual
$statsHadir = $stats['Hadir'] ?? 0;
$statsTerlambat = $stats['Terlambat'] ?? 0;
$statsIzin = $stats['Izin'] ?? 0;
$statsSakit = $stats['Sakit'] ?? 0;
$statsAlpa = $stats['Alpa'] ?? 0;
$statsPulang = $stats['Pulang'] ?? 0;
?>
<div class="page-header">
<h2><i class="fas fa-file-alt"></i> Detail Riwayat: <?php echo e($kegiatan->nama_kegiatan); ?></h2>
<a href="<?php echo e(route('admin.riwayat-kegiatan.index', ['tanggal_dari' => $filterDari, 'tanggal_sampai' => $filterSampai])); ?>"
class="btn-back">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
<div class="info-box-header">
<h3><i class="fas fa-clipboard-check"></i> <?php echo e($kegiatan->nama_kegiatan); ?></h3>
<div class="meta">
<span><i class="fas fa-tag"></i> <?php echo e($kegiatan->kategori->nama_kategori); ?></span>
<span><i class="fas fa-clock"></i> <?php echo e(date('H:i', strtotime($kegiatan->waktu_mulai))); ?> - <?php echo e(date('H:i', strtotime($kegiatan->waktu_selesai))); ?></span>
<span><i class="fas fa-calendar-day"></i> <?php echo e($kegiatan->hari); ?></span>
<?php if($kegiatan->kelasKegiatan->count() > 0): ?>
<span><i class="fas fa-users"></i> <?php echo e($kegiatan->kelasKegiatan->pluck('nama_kelas')->implode(', ')); ?></span>
<?php else: ?>
<span><i class="fas fa-globe"></i> Umum</span>
<?php endif; ?>
<span class="periode-tag"><i class="fas fa-calendar-check"></i> <?php echo e($periodeLabel); ?></span>
</div>
</div>
<?php if(isset($totalSantriEligible)): ?>
<div style="background: #fff; border-radius: 12px; padding: 16px 20px; margin-bottom: 14px; box-shadow: 0 2px 12px rgba(0,0,0,0.06); border-left: 4px solid #2563eb;">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 10px;">
<div>
<h4 style="margin: 0; font-size: 1rem; color: #1a2332;">
<i class="fas fa-users" style="color: #2563eb;"></i> Total Semua Santri: <strong><?php echo e($totalSantriEligible); ?></strong>
</h4>
<p style="margin: 4px 0 0; font-size: 0.84rem; color: #6b7280;">
Sudah absen: <strong style="color: #059669;"><?php echo e($totalRecorded); ?></strong>
&nbsp;·&nbsp;
Belum absen: <strong style="color: <?php echo e(($totalSantriEligible - $totalRecorded) > 0 ? '#dc2626' : '#059669'); ?>;"><?php echo e(max(0, $totalSantriEligible - $totalRecorded)); ?></strong>
</p>
</div>
<div style="text-align: right;">
<div style="font-size: 1.5rem; font-weight: 800; color: <?php echo e($persenHadir >= 85 ? '#059669' : ($persenHadir >= 70 ? '#d97706' : '#dc2626')); ?>;">
<?php echo e($persenHadir); ?>%
</div>
<div style="font-size: 0.78rem; color: #6b7280;">Kehadiran</div>
</div>
</div>
<?php
$pctSudah = $totalSantriEligible > 0 ? round($totalRecorded / $totalSantriEligible * 100, 1) : 0;
$pctBelumRiwayat = 100 - $pctSudah;
?>
<div style="height: 24px; background: #f3f4f6; border-radius: 12px; overflow: hidden; display: flex;">
<?php if($pctSudah > 0): ?>
<div style="width: <?php echo e($pctSudah); ?>%; background: linear-gradient(90deg, #22c55e, #16a34a); display: flex; align-items: center; justify-content: center; color: white; font-size: 0.73rem; font-weight: 700;" title="Sudah Absen: <?php echo e($totalRecorded); ?>">
<?php echo e($totalRecorded); ?>
</div>
<?php endif; ?>
<?php if($pctBelumRiwayat > 0 && ($totalSantriEligible - $totalRecorded) > 0): ?>
<div style="width: <?php echo e($pctBelumRiwayat); ?>%; background: #d1d5db; display: flex; align-items: center; justify-content: center; color: #6b7280; font-size: 0.73rem; font-weight: 700;" title="Belum Absen: <?php echo e($totalSantriEligible - $totalRecorded); ?>">
<?php echo e($totalSantriEligible - $totalRecorded); ?>
</div>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<div class="stats-row">
<div class="stat-card hadir">
<div class="icon"><i class="fas fa-check-circle"></i></div>
<div class="content">
<div class="label">Hadir</div>
<div class="value"><?php echo e($statsHadir); ?></div>
</div>
</div>
<div class="stat-card terlambat">
<div class="icon"><i class="fas fa-clock"></i></div>
<div class="content">
<div class="label">Terlambat</div>
<div class="value"><?php echo e($statsTerlambat); ?></div>
</div>
</div>
<div class="stat-card izin">
<div class="icon"><i class="fas fa-envelope"></i></div>
<div class="content">
<div class="label">Izin</div>
<div class="value"><?php echo e($statsIzin); ?></div>
</div>
</div>
<div class="stat-card sakit">
<div class="icon"><i class="fas fa-heartbeat"></i></div>
<div class="content">
<div class="label">Sakit</div>
<div class="value"><?php echo e($statsSakit); ?></div>
</div>
</div>
<div class="stat-card alpa">
<div class="icon"><i class="fas fa-times-circle"></i></div>
<div class="content">
<div class="label">Alpa</div>
<div class="value"><?php echo e($statsAlpa); ?></div>
</div>
</div>
<div class="stat-card pulang">
<div class="icon"><i class="fas fa-home"></i></div>
<div class="content">
<div class="label">Pulang</div>
<div class="value"><?php echo e($statsPulang); ?></div>
</div>
</div>
</div>
<div class="filter-box">
<form method="GET">
<input type="hidden" name="tanggal_dari" value="<?php echo e($filterDari); ?>">
<input type="hidden" name="tanggal_sampai" value="<?php echo e($filterSampai); ?>">
<div class="filter-grid">
<div class="form-group">
<label for="id_santri">Santri</label>
<select name="id_santri" id="id_santri" class="form-control">
<option value="">-- Semua Santri --</option>
<?php $__currentLoopData = $santris; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $s): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($s->id_santri); ?>" <?php echo e(request('id_santri') == $s->id_santri ? 'selected' : ''); ?>>
<?php echo e($s->nama_lengkap); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div class="form-group">
<label for="id_kelas">Kelas</label>
<select name="id_kelas" id="id_kelas" class="form-control">
<option value="">-- Semua Kelas --</option>
<?php $__currentLoopData = $kelasList->groupBy('kelompok.nama_kelompok'); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelompokNama => $kelasList_group): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<optgroup label="<?php echo e($kelompokNama); ?>">
<?php $__currentLoopData = $kelasList_group; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelas): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($kelas->id); ?>" <?php echo e(request('id_kelas') == $kelas->id ? 'selected' : ''); ?>>
<?php echo e($kelas->nama_kelas); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</optgroup>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div class="form-group">
<label for="status">Status</label>
<select name="status" id="status" class="form-control">
<option value="">-- Semua Status --</option>
<option value="Hadir" <?php echo e(request('status') == 'Hadir' ? 'selected' : ''); ?>>Hadir</option>
<option value="Terlambat" <?php echo e(request('status') == 'Terlambat' ? 'selected' : ''); ?>>Terlambat</option>
<option value="Izin" <?php echo e(request('status') == 'Izin' ? 'selected' : ''); ?>>Izin</option>
<option value="Sakit" <?php echo e(request('status') == 'Sakit' ? 'selected' : ''); ?>>Sakit</option>
<option value="Alpa" <?php echo e(request('status') == 'Alpa' ? 'selected' : ''); ?>>Alpa</option>
<option value="Pulang" <?php echo e(request('status') == 'Pulang' ? 'selected' : ''); ?>>Pulang</option>
</select>
</div>
<div class="form-group">
<label for="tanggal_spesifik">Filter Tanggal Spesifik</label>
<input type="date" name="tanggal_spesifik" id="tanggal_spesifik" class="form-control"
value="<?php echo e(request('tanggal_spesifik')); ?>"
min="<?php echo e($filterDari); ?>" max="<?php echo e($filterSampai); ?>">
</div>
<div style="display: flex; align-items: flex-end; gap: 10px;">
<button type="submit" class="btn-filter" style="flex: 1;">
<i class="fas fa-filter"></i> Filter
</button>
<?php if(request()->hasAny(['id_santri', 'id_kelas', 'status', 'tanggal_spesifik'])): ?>
<a href="<?php echo e(route('admin.riwayat-kegiatan.show', $kegiatan->id)); ?>?tanggal_dari=<?php echo e($filterDari); ?>&tanggal_sampai=<?php echo e($filterSampai); ?>"
class="btn-reset">
<i class="fas fa-times"></i>
</a>
<?php endif; ?>
</div>
</div>
</form>
</div>
<?php if($riwayats->count() > 0): ?>
<?php
$grouped = $riwayats->getCollection()->groupBy(function($item) {
return $item->tanggal->format('Y-m-d');
})->sortKeysDesc();
?>
<?php $__currentLoopData = $grouped; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $tanggal => $records): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$tglCarbon = \Carbon\Carbon::parse($tanggal);
$hariIndo = $tglCarbon->locale('id')->isoFormat('dddd');
$tglFormatted = $tglCarbon->locale('id')->isoFormat('D MMMM Y');
$dayHadir = $records->where('status', 'Hadir')->count();
$dayTerlambat = $records->where('status', 'Terlambat')->count();
$dayIzin = $records->where('status', 'Izin')->count();
$daySakit = $records->where('status', 'Sakit')->count();
$dayAlpa = $records->where('status', 'Alpa')->count();
$dayPulang = $records->where('status', 'Pulang')->count();
$dayTotal = $records->count();
// Group per kelas kegiatan (khusus) atau kelas_name santri (umum)
$isUmum = $kegiatan->kelasKegiatan->isEmpty();
if ($isUmum) {
$recordsPerKelas = $records->groupBy(fn($r) =>
optional(optional($r->santri->kelasSantri->first())->kelas)->nama_kelas ?? 'Tanpa Kelas'
)->sortKeys();
} else {
$recordsPerKelas = collect();
$placedIds = [];
foreach ($kegiatan->kelasKegiatan as $kls) {
$inKelas = $records->filter(function($r) use ($kls, &$placedIds) {
if (in_array($r->id, $placedIds)) return false;
return $r->santri->kelasSantri->contains('id_kelas', $kls->id);
});
foreach ($inKelas as $r) $placedIds[] = $r->id;
if ($inKelas->count() > 0) $recordsPerKelas[$kls->nama_kelas] = $inKelas;
}
$lainnya = $records->filter(fn($r) => !in_array($r->id, $placedIds));
if ($lainnya->count() > 0) $recordsPerKelas['Kelas Lain'] = $lainnya;
}
?>
<div class="day-group">
<div class="day-header" onclick="toggleDay(this)">
<div class="day-title">
<i class="fas fa-calendar-day"></i>
<?php echo e($hariIndo); ?>, <?php echo e($tglFormatted); ?>
<span style="font-weight: 400; font-size: 0.85rem; color: #94a3b8; margin-left: 4px;">(<?php echo e($dayTotal); ?> santri)</span>
</div>
<div class="day-stats">
<?php if($dayHadir > 0): ?>
<span class="mini-badge hadir"><i class="fas fa-check"></i> <?php echo e($dayHadir); ?></span>
<?php endif; ?>
<?php if($dayTerlambat > 0): ?>
<span class="mini-badge terlambat"><i class="fas fa-clock"></i> <?php echo e($dayTerlambat); ?></span>
<?php endif; ?>
<?php if($dayIzin > 0): ?>
<span class="mini-badge izin"><i class="fas fa-envelope"></i> <?php echo e($dayIzin); ?></span>
<?php endif; ?>
<?php if($daySakit > 0): ?>
<span class="mini-badge sakit"><i class="fas fa-heartbeat"></i> <?php echo e($daySakit); ?></span>
<?php endif; ?>
<?php if($dayAlpa > 0): ?>
<span class="mini-badge alpa"><i class="fas fa-times"></i> <?php echo e($dayAlpa); ?></span>
<?php endif; ?>
<?php if($dayPulang > 0): ?>
<span class="mini-badge pulang"><i class="fas fa-home"></i> <?php echo e($dayPulang); ?></span>
<?php endif; ?>
<i class="fas fa-chevron-down toggle-icon"></i>
</div>
</div>
<div class="day-body">
<?php $__currentLoopData = $recordsPerKelas; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $namaKelas => $kelasRecords): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div style="background: linear-gradient(135deg, #f0fdf4, #e8f5e9); padding: 8px 18px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #e2e8f0;">
<span style="font-size: 0.85rem; font-weight: 600; color: #065f46;">
<i class="fas fa-school"></i> <?php echo e($namaKelas); ?>
</span>
<span style="background: #6FBAA5; color: white; padding: 2px 10px; border-radius: 10px; font-size: 0.75rem; font-weight: 600;">
<?php echo e($kelasRecords->count()); ?> santri
</span>
</div>
<table>
<thead>
<tr>
<th style="width: 45px;">No</th>
<th style="width: 90px;">ID Santri</th>
<th>Nama Santri</th>
<th style="width: 90px; text-align: center;">Status</th>
<th style="width: 80px; text-align: center;">Waktu</th>
<th style="width: 80px;">Metode</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $kelasRecords->values(); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $riwayat): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td><?php echo e($index + 1); ?></td>
<td><strong><?php echo e($riwayat->id_santri); ?></strong></td>
<td>
<a href="<?php echo e(route('admin.riwayat-kegiatan.detail-santri', $riwayat->id_santri)); ?>"
style="color: var(--primary-color); text-decoration: none; font-weight: 500;">
<?php echo e($riwayat->santri->nama_lengkap); ?>
</a>
</td>
<td style="text-align: center;"><?php echo $riwayat->status_badge; ?></td>
<td style="text-align: center;">
<?php echo e($riwayat->waktu_absen ? \Carbon\Carbon::parse($riwayat->waktu_absen)->format('H:i') : '-'); ?>
</td>
<td>
<?php if($riwayat->metode_absen == 'RFID'): ?>
<span style="background: #DBEAFE; color: #1E40AF; padding: 3px 8px; border-radius: 10px; font-size: 0.75rem; font-weight: 600;">
<i class="fas fa-id-card"></i> RFID
</span>
<?php elseif($riwayat->metode_absen == 'Import_Mesin'): ?>
<span style="background: #EDE9FE; color: #6B21A8; padding: 3px 8px; border-radius: 10px; font-size: 0.75rem; font-weight: 600;">
<i class="fas fa-desktop"></i> Mesin
</span>
<?php else: ?>
<span style="background: #E5E7EB; color: #374151; padding: 3px 8px; border-radius: 10px; font-size: 0.75rem; font-weight: 600;">
<i class="fas fa-hand-pointer"></i> Manual
</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<div class="pagination">
<?php echo $riwayats->appends(request()->query())->links('pagination::simple-bootstrap-4'); ?>
</div>
<?php else: ?>
<div class="empty-state">
<i class="fas fa-inbox"></i>
<h3>Tidak Ada Riwayat</h3>
<p>Tidak ada data absensi untuk periode <strong><?php echo e($periodeLabel); ?></strong>.</p>
</div>
<?php endif; ?>
<script>
function toggleDay(header) {
var body = header.nextElementSibling;
var icon = header.querySelector('.toggle-icon');
if (body.style.display === 'none') {
body.style.display = 'block';
icon.classList.remove('collapsed');
} else {
body.style.display = 'none';
icon.classList.add('collapsed');
}
}
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kegiatan/riwayat/show.blade.php ENDPATH**/ ?>

View File

@ -1,138 +0,0 @@

<?php $__env->startSection('title', 'Manajemen Akun Santri'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-user-cog"></i> Manajemen Akun Santri (Web)</h2>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success"><?php echo session('success'); ?></div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger"><?php echo e(session('error')); ?></div>
<?php endif; ?>
<?php if(session('info')): ?>
<div class="alert alert-info"><?php echo e(session('info')); ?></div>
<?php endif; ?>
<div class="content-box">
<div class="alert alert-info">
<i class="fas fa-info-circle"></i> <strong>Info Login Santri (Web) : </strong>
Username = Nama Lengkap Santri &nbsp;|&nbsp; Password = NIS Santri
</div>
<h3>Daftar Akun Santri (<?php echo e($users->count()); ?>)</h3>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>ID Santri</th>
<th>Nama Santri</th>
<th>NIS</th>
<th>Username</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<?php $__empty_1 = true; $__currentLoopData = $users; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $user): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
<tr>
<td><?php echo e($user->id_santri); ?></td>
<td><?php echo e($user->santri->nama_lengkap ?? '-'); ?></td>
<td><?php echo e($user->santri->nis ?? '-'); ?></td>
<td><code><?php echo e($user->username); ?></code></td>
<td>
<form action="<?php echo e(route('admin.users.santri_destroy', $user->id)); ?>"
method="POST" style="display:inline;"
onsubmit="return confirm('Yakin hapus akun santri <?php echo e($user->santri->nama_lengkap ?? ''); ?>?')">
<?php echo csrf_field(); ?>
<button type="submit" class="btn btn-sm btn-danger">
<i class="fas fa-trash"></i> Hapus
</button>
</form>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
<tr>
<td colspan="5" class="text-center">Belum ada akun santri.</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
<h3 style="margin-top:22px;">
Santri Belum Punya Akun (<?php echo e($santris_tanpa_akun->count()); ?>)
</h3>
<?php if($santris_tanpa_akun->count() > 0): ?>
<div style="margin-bottom:12px;">
<form action="<?php echo e(route('admin.users.santri_buat_semua')); ?>" method="POST" style="display:inline;"
onsubmit="return confirm('Buat akun untuk SEMUA <?php echo e($santris_tanpa_akun->count()); ?> santri sekaligus?')">
<?php echo csrf_field(); ?>
<button type="submit" class="btn btn-success">
<i class="fas fa-users"></i> Buat Semua Sekaligus (<?php echo e($santris_tanpa_akun->count()); ?>)
</button>
</form>
</div>
<?php endif; ?>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>ID Santri</th>
<th>NIS</th>
<th>Nama Santri</th>
<th>Kelas</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<?php $__empty_1 = true; $__currentLoopData = $santris_tanpa_akun; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $santri): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
<tr>
<td><?php echo e($santri->id_santri); ?></td>
<td>
<?php if($santri->nis): ?>
<?php echo e($santri->nis); ?>
<?php else: ?>
<span class="text-danger">Belum ada NIS</span>
<?php endif; ?>
</td>
<td><?php echo e($santri->nama_lengkap); ?></td>
<td><?php echo e($santri->kelas ?? '-'); ?></td>
<td>
<?php if($santri->nis): ?>
<form action="<?php echo e(route('admin.users.santri_buat_akun', $santri->id_santri)); ?>"
method="POST" style="display:inline;"
onsubmit="return confirm('Buat akun untuk <?php echo e($santri->nama_lengkap); ?>?')">
<?php echo csrf_field(); ?>
<button type="submit" class="btn btn-sm btn-primary">
<i class="fas fa-user-plus"></i> Buat Akun
</button>
</form>
<?php else: ?>
<span class="text-muted">Isi NIS dulu</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
<tr>
<td colspan="5" class="text-center text-success">
<i class="fas fa-check"></i> Semua santri sudah punya akun.
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', ['isAdmin' => true], \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/users/santri_accounts.blade.php ENDPATH**/ ?>

View File

@ -1,298 +1,456 @@
<?php $__env->startSection('content'); ?> <?php $__env->startSection('content'); ?>
<style> <style>
.day-group { margin-bottom: 18px; background: #fff; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); overflow: hidden; } /* ============================================================
.day-header { background: linear-gradient(135deg, #f0fdf4 0%, #E8F7F2 100%); padding: 13px 18px; display: flex; justify-content: space-between; align-items: center; border-bottom: 2px solid #E8F7F2; cursor: pointer; transition: background 0.2s; user-select: none; } RIWAYAT KEGIATAN INDEX (v3)
.day-header:hover{ background: linear-gradient(135deg, #E8F7F2 0%, #d1f2e8 100%); } ============================================================ */
.day-title { font-weight: 700; font-size: 1rem; color: var(--primary-dark); display: flex; align-items: center; gap: 8px; }
.day-title i { color: var(--primary-color); }
.day-meta { display: flex; gap: 10px; align-items: center; }
.day-count { background: var(--primary-color); color: #fff; padding: 3px 10px; border-radius: 20px; font-size: 0.78rem; font-weight: 600; }
.toggle-icon { transition: transform 0.3s; font-size: 0.85rem; color: #94a3b8; }
.toggle-icon.collapsed { transform: rotate(-90deg); }
.day-body { overflow: hidden; }
.day-body table { width: 100%; border-collapse: collapse; }
.day-body thead { background: #f8fafc; }
.day-body th { padding: 9px 14px; text-align: left; font-weight: 600; font-size: 0.8rem; color: #64748b; border-bottom: 1px solid #e2e8f0; }
.day-body td { padding: 10px 14px; font-size: 0.85rem; border-bottom: 1px solid #f1f5f9; vertical-align: middle; }
.day-body tbody tr:last-child td { border-bottom: none; }
.day-body tbody tr:hover { background: #f8fafc; }
.stat-chips { display: flex; gap: 5px; flex-wrap: wrap; } .rw-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:16px; flex-wrap:wrap; gap:10px; }
.chip { padding: 2px 8px; border-radius: 10px; font-size: 0.74rem; font-weight: 600; display: inline-flex; align-items: center; gap: 3px; } .rw-header h2 { margin:0; font-size:1.35rem; color:var(--primary-dark); display:flex; align-items:center; gap:9px; }
.chip-hadir { background: #D1FAE5; color: #065F46; } .rw-header h2 i { color:var(--primary-color); }
.chip-terlambat { background: #FFF3E0; color: #E65100; }
.chip-izin { background: #FEF3C7; color: #92400E; }
.chip-sakit { background: #DBEAFE; color: #1E40AF; }
.chip-alpa { background: #FEE2E2; color: #991B1B; }
.chip-pulang { background: #F3E8FF; color: #6B21A8; }
.chip-none { background: #F1F5F9; color: #94a3b8; }
.kelas-tag { display: inline-block; background: #E8F7F2; color: var(--primary-dark); padding: 2px 7px; border-radius: 8px; font-size: 0.74rem; margin: 2px 2px 0 0; }
.umum-tag { display: inline-block; background: #F1F5F9; color: #64748b; padding: 2px 7px; border-radius: 8px; font-size: 0.74rem; }
.btn-detail { padding: 5px 12px; background: var(--primary-color); color: #fff; border: none; border-radius: 6px; font-size: 0.8rem; text-decoration: none; display: inline-flex; align-items: center; gap: 4px; transition: all 0.2s; }
.btn-detail:hover { background: #059669; color: #fff; transform: translateY(-1px); }
.filter-box { background: #fff; padding: 14px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); margin-bottom: 14px; } /* Filter */
.filter-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 11px; } .rw-filter { background:#fff; border-radius:12px; box-shadow:0 2px 10px rgba(0,0,0,.06); padding:14px 18px; margin-bottom:14px; }
.form-group { margin: 0; } .rw-mode-tabs { display:flex; gap:6px; margin-bottom:14px; flex-wrap:wrap; }
.form-group label { display: block; font-size: 0.85rem; margin-bottom: 5px; color: var(--text-light); font-weight: 500; } .rw-tab { padding:7px 18px; border-radius:22px; border:1.5px solid #e2e8f0; background:#fff;
.form-control { width: 100%; padding: 8px 12px; border: 1px solid #e2e8f0; border-radius: 8px; font-size: 0.85rem; } font-size:0.82rem; font-weight:600; cursor:pointer; text-decoration:none;
.btn-filter { background: var(--primary-color); color: #fff; border: none; padding: 9px 16px; border-radius: 8px; cursor: pointer; font-size: 0.85rem; display: inline-flex; align-items: center; gap: 6px; transition: all 0.2s; } color:#64748b; transition:all .18s; display:inline-flex; align-items:center; gap:6px; }
.btn-filter:hover { background: #059669; transform: translateY(-1px); } .rw-tab:hover { border-color:var(--primary-color); color:var(--primary-color); background:#f0fdf4; }
.btn-reset { background: #6B7280; color: #fff; border: none; padding: 9px 12px; border-radius: 8px; cursor: pointer; font-size: 0.85rem; display: inline-flex; align-items: center; gap: 6px; text-decoration: none; } .rw-tab.active { background:var(--primary-color); color:#fff; border-color:var(--primary-color); box-shadow:0 2px 8px rgba(16,185,129,.25); }
.btn-reset:hover { background: #4B5563; } .rw-filter-row { display:flex; gap:10px; align-items:flex-end; flex-wrap:wrap; }
.rw-fg { display:flex; flex-direction:column; gap:4px; }
.rw-fg label { font-size:0.78rem; font-weight:600; color:#64748b; }
.rw-fg .form-control { padding:7px 11px; font-size:0.84rem; border:1.5px solid #e2e8f0; border-radius:8px; }
.rw-fg .form-control:focus { border-color:var(--primary-color); outline:none; }
.btn-rw-apply { background:var(--primary-color); color:#fff; border:none; padding:8px 18px; border-radius:8px;
font-size:0.84rem; font-weight:600; cursor:pointer; display:inline-flex; align-items:center; gap:6px;
align-self:flex-end; white-space:nowrap; }
.btn-rw-apply:hover { background:#059669; }
.btn-rw-reset { background:#f1f5f9; color:#64748b; border:1.5px solid #e2e8f0; padding:8px 12px; border-radius:8px;
font-size:0.84rem; font-weight:600; text-decoration:none;
display:inline-flex; align-items:center; gap:6px; align-self:flex-end; }
.btn-rw-reset:hover { background:#e2e8f0; }
.period-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; } /* Periode label */
.period-tab { padding: 5px 14px; border-radius: 20px; border: 1px solid #e2e8f0; background: #fff; font-size: 0.82rem; cursor: pointer; text-decoration: none; color: var(--text-dark); transition: all 0.2s; display: inline-flex; align-items: center; gap: 5px; } .rw-periode { background:linear-gradient(90deg,#f0fdf4,#e8f7f2); border-left:3px solid var(--primary-color);
.period-tab:hover, .period-tab.active { background: var(--primary-color); color: #fff; border-color: var(--primary-color); } border-radius:8px; padding:9px 14px; margin-bottom:14px; font-size:0.84rem; color:#374151;
display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.rw-periode i { color:var(--primary-color); }
.periode-info { font-size: 0.82rem; color: var(--text-light); margin-bottom: 12px; padding: 8px 12px; background: #f0fdf4; border-radius: 8px; border-left: 3px solid var(--primary-color); } /* KPI strip */
.periode-info strong { color: var(--primary-color); } .rw-kpi-strip { display:grid; grid-template-columns:repeat(auto-fit,minmax(105px,1fr)); gap:8px; margin-bottom:14px; }
.rw-kpi { background:#fff; border-radius:10px; padding:11px 14px; box-shadow:0 2px 8px rgba(0,0,0,.05); text-align:center; }
.rw-kpi-val { font-size:1.45rem; font-weight:800; line-height:1; }
.rw-kpi-lbl { font-size:0.73rem; color:#94a3b8; margin-top:4px; font-weight:500; }
.rw-kpi-sub { font-size:0.68rem; color:#cbd5e1; margin-top:2px; }
.empty-state { text-align: center; padding: 44px 14px; color: var(--text-light); background: #fff; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); } /* Per-date block */
.empty-state i { font-size: 3.5rem; margin-bottom: 14px; opacity: 0.3; display: block; } .rw-date-block { margin-bottom:20px; }
.empty-state h3 { margin: 0 0 6px; } .rw-date-header { display:flex; align-items:center; gap:10px; padding:10px 16px; flex-wrap:wrap;
background:linear-gradient(90deg,var(--primary-color),#0ea574);
border-radius:10px 10px 0 0; color:#fff; }
.rw-date-today { background:linear-gradient(90deg,#0ea574,#059669); }
.dh-date { font-size:1rem; font-weight:700; }
.dh-hari { background:rgba(255,255,255,.22); padding:2px 10px; border-radius:12px; font-size:0.78rem; font-weight:600; }
.dh-count { margin-left:auto; font-size:0.78rem; background:rgba(255,255,255,.2); padding:3px 10px; border-radius:12px; }
@media (max-width: 768px) { /* Table */
.day-header { flex-direction: column; align-items: flex-start; gap: 6px; } .rw-tbl-wrap { background:#fff; border-radius:0 0 10px 10px; box-shadow:0 3px 12px rgba(0,0,0,.07); overflow-x:auto; }
.day-body th:nth-child(3), .day-body td:nth-child(3), .rw-table { width:100%; border-collapse:collapse; min-width:680px; }
.day-body th:nth-child(4), .day-body td:nth-child(4) { display: none; } .rw-table thead th { padding:9px 13px; text-align:left; font-size:0.78rem; font-weight:700;
color:#475569; background:#f8fafc; border-bottom:1.5px solid #e2e8f0; white-space:nowrap; }
.rw-table tbody td { padding:9px 13px; font-size:0.83rem; border-bottom:1px solid #f8fafc; vertical-align:middle; }
.rw-table tbody tr:last-child td { border-bottom:none; }
.rw-table tbody tr:hover { background:#f8fafc; }
.rw-table tfoot td { padding:8px 13px; }
/* Tags */
.rw-kelas-tag { background:#e8f7f2; color:var(--primary-dark); padding:2px 7px; border-radius:6px; font-size:.72rem; font-weight:600; margin-right:2px; display:inline-block; }
.rw-umum-tag { background:#f1f5f9; color:#64748b; padding:2px 7px; border-radius:6px; font-size:.72rem; font-weight:600; display:inline-block; }
.rw-kat-tag { background:#dbeafe; color:#1e40af; padding:2px 7px; border-radius:6px; font-size:.72rem; font-weight:600; display:inline-block; }
/* Mini progress */
.rw-mini-prog { height:6px; background:#f1f5f9; border-radius:3px; overflow:hidden; display:flex; min-width:70px; }
/* Button table */
.btn-tbl-detail { padding:5px 11px; background:var(--primary-color); color:#fff; border:none; border-radius:6px;
font-size:0.76rem; font-weight:600; text-decoration:none; display:inline-flex; align-items:center; gap:4px; white-space:nowrap; }
.btn-tbl-detail:hover { background:#059669; color:#fff; }
/* Cards (hari_ini) */
.rw-card { background:#fff; border-radius:12px; box-shadow:0 2px 10px rgba(0,0,0,.06); border:1px solid #f0f0f0; overflow:hidden; margin-bottom:10px; }
.rw-card:hover { box-shadow:0 4px 18px rgba(0,0,0,.1); }
.rw-card-head { display:flex; align-items:flex-start; justify-content:space-between; gap:12px; padding:14px 18px 10px; border-bottom:1px solid #f1f5f9; flex-wrap:wrap; }
.rw-card-title { font-size:1rem; font-weight:700; color:var(--primary-dark); margin:0 0 5px; display:flex; align-items:center; gap:8px; }
.rw-card-meta { display:flex; gap:10px; flex-wrap:wrap; font-size:.8rem; color:#64748b; align-items:center; }
.rw-card-meta span{ display:inline-flex; align-items:center; gap:4px; }
.rw-status { padding:4px 12px; border-radius:20px; font-size:.76rem; font-weight:700; white-space:nowrap; flex-shrink:0; display:inline-flex; align-items:center; gap:5px; }
.rw-status.belum { background:#f1f5f9; color:#64748b; }
.rw-status.selesai{ background:#d1fae5; color:#065f46; }
.rw-status.brlgs { background:#fef9c3; color:#854d0e; }
.rw-card-body { padding:10px 18px 14px; }
.rw-stats-row { display:flex; gap:6px; flex-wrap:wrap; align-items:center; margin-bottom:10px; }
.rw-chip { padding:4px 10px; border-radius:10px; font-size:.76rem; font-weight:700; display:inline-flex; align-items:center; gap:4px; }
.rw-chip.hadir { background:#d1fae5; color:#065f46; }
.rw-chip.terlambat{ background:#fff3e0; color:#e65100; }
.rw-chip.izin { background:#fef3c7; color:#92400e; }
.rw-chip.sakit { background:#dbeafe; color:#1e40af; }
.rw-chip.alpa { background:#fee2e2; color:#991b1b; }
.rw-chip.pulang { background:#f3e8ff; color:#6b21a8; }
.rw-chip.none { background:#f1f5f9; color:#94a3b8; }
.rw-progress-wrap { height:8px; background:#f1f5f9; border-radius:4px; overflow:hidden; display:flex; margin-bottom:6px; }
.rw-prog-hadir { background:#22c55e; }
.rw-prog-terlambat{ background:#FF9800; }
.rw-prog-izin { background:#f59e0b; }
.rw-prog-sakit { background:#3b82f6; }
.rw-prog-alpa { background:#ef4444; }
.rw-prog-pulang { background:#a855f7; }
.rw-prog-belum { background:#e2e8f0; }
.rw-card-foot { display:flex; align-items:center; justify-content:space-between; padding:8px 18px; background:#fafafa; border-top:1px solid #f1f5f9; flex-wrap:wrap; gap:8px; }
.rw-total-txt { font-size:.78rem; color:#94a3b8; }
.rw-total-txt strong { color:#374151; }
.btn-rw-detail { padding:6px 16px; background:var(--primary-color); color:#fff; border:none; border-radius:7px; font-size:.82rem; font-weight:600; text-decoration:none; display:inline-flex; align-items:center; gap:5px; }
.btn-rw-detail:hover { background:#059669; color:#fff; }
/* Empty */
.rw-empty { text-align:center; padding:48px 20px; background:#fff; border-radius:12px; box-shadow:0 2px 10px rgba(0,0,0,.06); }
.rw-empty i { font-size:3rem; color:#cbd5e1; display:block; margin-bottom:12px; }
.rw-empty h3 { margin:0 0 6px; color:var(--primary-dark); }
.rw-empty p { margin:0; color:var(--text-light); font-size:.88rem; }
@media(max-width:640px) {
.rw-filter-row { flex-direction:column; }
.rw-fg { width:100%; }
.rw-fg .form-control { width:100%; }
.btn-rw-apply,.btn-rw-reset { width:100%; justify-content:center; }
.rw-kpi-strip { grid-template-columns:repeat(3,1fr); }
.dh-count { display:none; }
} }
</style> </style>
<?php <?php
// Default: minggu ini $mode = $mode ?? 'hari_ini';
$defaultDari = now()->startOfWeek(\Carbon\Carbon::MONDAY)->format('Y-m-d'); $dari = $dari ?? now()->format('Y-m-d');
$defaultSampai = now()->endOfWeek(\Carbon\Carbon::SUNDAY)->format('Y-m-d'); $sampai = $sampai ?? now()->format('Y-m-d');
$tanggal = $tanggal ?? now()->format('Y-m-d');
$kategoriId = $kategoriId ?? '';
$passParams = ['mode' => $mode, 'dari' => $dari, 'sampai' => $sampai, 'tanggal' => $tanggal];
$activeDari = request('tanggal_dari', $defaultDari); $totalAbsensi = $summary['total_absensi'] ?? 0;
$activeSampai = request('tanggal_sampai', $defaultSampai); $totalHadir = $summary['hadir'] ?? 0;
$activeKategori = request('kategori_id', ''); $pctHadirGlbl = $totalAbsensi > 0 ? round($totalHadir / $totalAbsensi * 100, 1) : 0;
$activeBulan = request('bulan', '');
// Label periode
if ($activeBulan) {
$periodeLabel = 'Bulan ' . \Carbon\Carbon::parse($activeBulan . '-01')->locale('id')->isoFormat('MMMM Y');
} else {
$periodeLabel = \Carbon\Carbon::parse($activeDari)->locale('id')->isoFormat('D MMM Y')
. ' '
. \Carbon\Carbon::parse($activeSampai)->locale('id')->isoFormat('D MMM Y');
}
// Cek shortcut aktif
$isMingguIni = !$activeBulan
&& $activeDari == $defaultDari
&& $activeSampai == $defaultSampai;
$isBulanIni = !$activeBulan
&& $activeDari == now()->startOfMonth()->format('Y-m-d')
&& $activeSampai == now()->endOfMonth()->format('Y-m-d');
?> ?>
<div class="page-header">
<h2><i class="fas fa-history"></i> Riwayat Kegiatan & Absensi</h2> <div class="rw-header">
<h2><i class="fas fa-history"></i> Riwayat Kegiatan &amp; Absensi</h2>
</div> </div>
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div> <div class="rw-filter">
<?php endif; ?> <div class="rw-mode-tabs">
<a href="<?php echo e(route('admin.riwayat-kegiatan.index', ['mode'=>'hari_ini','tanggal'=>$tanggal])); ?>"
class="rw-tab <?php echo e($mode==='hari_ini'?'active':''); ?>">
<div class="filter-box"> <i class="fas fa-calendar-day"></i> Hari Ini
</a>
<a href="<?php echo e(route('admin.riwayat-kegiatan.index', ['mode'=>'minggu_ini'])); ?>"
<div class="period-tabs"> class="rw-tab <?php echo e($mode==='minggu_ini'?'active':''); ?>">
<a href="<?php echo e(route('admin.riwayat-kegiatan.index', ['tanggal_dari' => $defaultDari, 'tanggal_sampai' => $defaultSampai, 'kategori_id' => $activeKategori])); ?>"
class="period-tab <?php echo e($isMingguIni ? 'active' : ''); ?>">
<i class="fas fa-calendar-week"></i> Minggu Ini <i class="fas fa-calendar-week"></i> Minggu Ini
</a> </a>
<a href="<?php echo e(route('admin.riwayat-kegiatan.index', ['tanggal_dari' => now()->startOfMonth()->format('Y-m-d'), 'tanggal_sampai' => now()->endOfMonth()->format('Y-m-d'), 'kategori_id' => $activeKategori])); ?>" <a href="<?php echo e(route('admin.riwayat-kegiatan.index', ['mode'=>'custom','dari'=>$dari,'sampai'=>$sampai])); ?>"
class="period-tab <?php echo e($isBulanIni ? 'active' : ''); ?>"> class="rw-tab <?php echo e($mode==='custom'?'active':''); ?>">
<i class="fas fa-calendar-alt"></i> Bulan Ini <i class="fas fa-sliders-h"></i> Rentang Tanggal
</a>
<a href="<?php echo e(route('admin.riwayat-kegiatan.index')); ?>"
class="period-tab <?php echo e(!$isMingguIni && !$isBulanIni ? 'active' : ''); ?>"
style="<?php echo e(!$isMingguIni && !$isBulanIni ? '' : 'display:none'); ?>">
<i class="fas fa-filter"></i> Custom
</a> </a>
</div> </div>
<form method="GET"> <form method="GET" action="<?php echo e(route('admin.riwayat-kegiatan.index')); ?>">
<div class="filter-grid">
<div class="form-group">
<label for="kategori_id">Kategori</label>
<select name="kategori_id" id="kategori_id" class="form-control">
<option value="">-- Semua Kategori --</option>
<?php $__currentLoopData = $kategoris; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $k): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($k->kategori_id); ?>" <?php echo e($activeKategori == $k->kategori_id ? 'selected' : ''); ?>>
<?php echo e($k->nama_kategori); ?>
</option> <?php if($mode === 'hari_ini'): ?>
<input type="hidden" name="mode" value="hari_ini">
<div class="rw-filter-row">
<div class="rw-fg">
<label><i class="fas fa-calendar-alt"></i> Tanggal</label>
<input type="date" name="tanggal" class="form-control" value="<?php echo e($tanggal); ?>" style="max-width:180px;">
</div>
<div class="rw-fg">
<label><i class="fas fa-tag"></i> Kategori</label>
<select name="kategori_id" class="form-control" style="max-width:200px;">
<option value="">Semua Kategori</option>
<?php $__currentLoopData = $kategoris; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $k): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($k->kategori_id); ?>" <?php echo e($kategoriId==$k->kategori_id?'selected':''); ?>><?php echo e($k->nama_kategori); ?></option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?> <?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select> </select>
</div> </div>
<div class="form-group"> <button type="submit" class="btn-rw-apply"><i class="fas fa-search"></i> Tampilkan</button>
<label for="tanggal_dari">Tanggal Dari</label> <a href="<?php echo e(route('admin.riwayat-kegiatan.index')); ?>" class="btn-rw-reset"><i class="fas fa-undo"></i> Reset</a>
<input type="date" name="tanggal_dari" id="tanggal_dari" class="form-control" value="<?php echo e($activeDari); ?>">
</div> </div>
<div class="form-group">
<label for="tanggal_sampai">Tanggal Sampai</label> <?php elseif($mode === 'minggu_ini'): ?>
<input type="date" name="tanggal_sampai" id="tanggal_sampai" class="form-control" value="<?php echo e($activeSampai); ?>"> <input type="hidden" name="mode" value="minggu_ini">
<div class="rw-filter-row">
<div class="rw-fg">
<label><i class="fas fa-tag"></i> Kategori</label>
<select name="kategori_id" class="form-control" style="max-width:200px;">
<option value="">Semua Kategori</option>
<?php $__currentLoopData = $kategoris; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $k): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($k->kategori_id); ?>" <?php echo e($kategoriId==$k->kategori_id?'selected':''); ?>><?php echo e($k->nama_kategori); ?></option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div> </div>
<div class="form-group"> <button type="submit" class="btn-rw-apply"><i class="fas fa-search"></i> Tampilkan</button>
<label for="bulan">Atau Pilih Bulan</label> <a href="<?php echo e(route('admin.riwayat-kegiatan.index', ['mode'=>'minggu_ini'])); ?>" class="btn-rw-reset"><i class="fas fa-undo"></i> Reset</a>
<input type="month" name="bulan" id="bulan" class="form-control" value="<?php echo e($activeBulan); ?>">
</div> </div>
<div style="display: flex; align-items: flex-end; gap: 10px;">
<button type="submit" class="btn-filter" style="flex: 1;"> <?php else: ?>
<i class="fas fa-filter"></i> Filter <input type="hidden" name="mode" value="custom">
</button> <div class="rw-filter-row">
<a href="<?php echo e(route('admin.riwayat-kegiatan.index')); ?>" class="btn-reset" title="Reset ke minggu ini"> <div class="rw-fg">
<i class="fas fa-undo"></i> <label><i class="fas fa-calendar-alt"></i> Dari Tanggal</label>
</a> <input type="date" name="dari" class="form-control" value="<?php echo e($dari); ?>" style="max-width:180px;" required>
</div> </div>
<div class="rw-fg">
<label><i class="fas fa-calendar-alt"></i> Sampai Tanggal</label>
<input type="date" name="sampai" class="form-control" value="<?php echo e($sampai); ?>" style="max-width:180px;" required>
</div> </div>
<div class="rw-fg">
<label><i class="fas fa-tag"></i> Kategori</label>
<select name="kategori_id" class="form-control" style="max-width:200px;">
<option value="">Semua Kategori</option>
<?php $__currentLoopData = $kategoris; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $k): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($k->kategori_id); ?>" <?php echo e($kategoriId==$k->kategori_id?'selected':''); ?>><?php echo e($k->nama_kategori); ?></option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<button type="submit" class="btn-rw-apply"><i class="fas fa-search"></i> Tampilkan</button>
<a href="<?php echo e(route('admin.riwayat-kegiatan.index', ['mode'=>'custom'])); ?>" class="btn-rw-reset"><i class="fas fa-undo"></i> Reset</a>
</div>
<?php endif; ?>
</form> </form>
</div> </div>
<p class="periode-info"> <div class="rw-periode">
<i class="fas fa-calendar-check"></i> Menampilkan kegiatan periode: <strong><?php echo e($periodeLabel); ?></strong> <i class="fas fa-calendar-check"></i>
Menampilkan: <strong><?php echo e($periodeLabel); ?></strong>
<?php if($mode !== 'hari_ini' && ($summary['jumlah_hari'] ?? 0) > 0): ?>
<span style="color:#94a3b8;">·</span>
<strong style="color:var(--primary-color);"><?php echo e($summary['jumlah_hari']); ?></strong> hari aktif
<span style="color:#94a3b8;">·</span>
<strong style="color:var(--primary-color);"><?php echo e($summary['jumlah_kegiatan']); ?></strong> sesi
<?php endif; ?>
</div>
<?php if($totalAbsensi > 0): ?>
<div class="rw-kpi-strip">
<div class="rw-kpi">
<div class="rw-kpi-val" style="color:#065f46;"><?php echo e($summary['hadir']); ?></div>
<div class="rw-kpi-lbl"><i class="fas fa-check" style="color:#22c55e;"></i> Hadir Efektif</div>
<?php if($summary['terlambat'] > 0): ?>
<div class="rw-kpi-sub">+<?php echo e($summary['terlambat']); ?> terlambat</div>
<?php endif; ?>
</div>
<div class="rw-kpi">
<div class="rw-kpi-val" style="color:#e65100;"><?php echo e($summary['terlambat']); ?></div>
<div class="rw-kpi-lbl"><i class="fas fa-clock" style="color:#FF9800;"></i> Terlambat</div>
</div>
<div class="rw-kpi">
<div class="rw-kpi-val" style="color:#92400e;"><?php echo e($summary['izin']); ?></div>
<div class="rw-kpi-lbl"><i class="fas fa-envelope" style="color:#f59e0b;"></i> Izin</div>
</div>
<div class="rw-kpi">
<div class="rw-kpi-val" style="color:#1e40af;"><?php echo e($summary['sakit']); ?></div>
<div class="rw-kpi-lbl"><i class="fas fa-heartbeat" style="color:#3b82f6;"></i> Sakit</div>
</div>
<div class="rw-kpi">
<div class="rw-kpi-val" style="color:#991b1b;"><?php echo e($summary['alpa']); ?></div>
<div class="rw-kpi-lbl"><i class="fas fa-times-circle" style="color:#ef4444;"></i> Alpa</div>
</div>
<div class="rw-kpi" style="border-top:2px solid var(--primary-color);">
<div class="rw-kpi-val" style="color:<?php echo e($pctHadirGlbl>=85?'#059669':($pctHadirGlbl>=70?'#d97706':'#dc2626')); ?>;"><?php echo e($pctHadirGlbl); ?>%</div>
<div class="rw-kpi-lbl"><i class="fas fa-chart-pie" style="color:var(--primary-color);"></i> Rata-rata</div>
<div class="rw-kpi-sub">dari <?php echo e($totalAbsensi); ?> tercatat
<?php if($mode !== 'hari_ini' && ($summary['jumlah_kegiatan']??0) > 0): ?>
· <?php echo e($summary['jumlah_kegiatan']); ?> sesi
<?php endif; ?>
</div>
</div>
</div>
<?php endif; ?>
<?php if($mode === 'hari_ini'): ?>
<?php if($kegiatans && $kegiatans->count() > 0): ?>
<?php $__currentLoopData = $kegiatans; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kegiatan): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php echo $__env->make('admin.kegiatan.riwayat._card', ['kegiatan' => $kegiatan, 'passParams' => $passParams], \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<div style="margin-top:16px;"><?php echo $kegiatans->appends(request()->query())->links('pagination::simple-bootstrap-4'); ?></div>
<?php else: ?>
<div class="rw-empty">
<i class="fas fa-calendar-times"></i>
<h3>Tidak Ada Kegiatan</h3>
<p>Tidak ada kegiatan pada <strong><?php echo e($periodeLabel); ?></strong>.</p>
<p style="margin-top:8px; font-size:.82rem;">
Coba tanggal lain atau lihat <a href="<?php echo e(route('admin.riwayat-kegiatan.index', ['mode'=>'minggu_ini'])); ?>" style="color:var(--primary-color);">riwayat minggu ini</a>.
</p> </p>
</div>
<?php endif; ?>
<?php if($kegiatans->count() > 0): ?>
<?php else: ?>
<?php if($kegiatanPerTanggal && $kegiatanPerTanggal->count() > 0): ?>
<?php $__currentLoopData = $kegiatanPerTanggal; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $tgl => $items): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php <?php
$hariOrder = ['Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu', 'Ahad']; $tglCarbon = \Carbon\Carbon::parse($tgl);
$grouped = $kegiatans->getCollection()->groupBy('hari'); $isHariIni = ($tgl === now()->format('Y-m-d'));
$hariLabel = $tglCarbon->locale('id')->isoFormat('dddd');
$tglLabel = $tglCarbon->locale('id')->isoFormat('D MMMM Y');
$tglHadir = $items->sum('hadir') + $items->sum('terlambat');
$tglTotal = $items->sum('total_absensi');
$tglPct = $tglTotal > 0 ? round($tglHadir / $tglTotal * 100) : 0;
?> ?>
<?php $__currentLoopData = $hariOrder; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $hari): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> <div class="rw-date-block">
<?php if($grouped->has($hari)): ?> <div class="rw-date-header <?php echo e($isHariIni ? 'rw-date-today' : ''); ?>">
<?php $items = $grouped[$hari]; ?> <span class="dh-date"><?php echo e($tglLabel); ?></span>
<div class="day-group"> <span class="dh-hari"><?php echo e($hariLabel); ?><?php echo e($isHariIni ? ' · Hari Ini' : ''); ?></span>
<div class="day-header" onclick="toggleDay(this)"> <span class="dh-count">
<div class="day-title"> <?php echo e($items->count()); ?> kegiatan
<i class="fas fa-calendar-day"></i> <?php echo e($hari); ?> &nbsp;·&nbsp;
<strong><?php echo e($tglHadir); ?></strong>/<?php echo e($tglTotal); ?> hadir
</div> <?php if($tglTotal > 0): ?>
<div class="day-meta"> <span style="background:rgba(255,255,255,.15); padding:1px 7px; border-radius:8px; margin-left:4px;"><?php echo e($tglPct); ?>%</span>
<span class="day-count"><?php echo e($items->count()); ?> kegiatan</span> <?php endif; ?>
<i class="fas fa-chevron-down toggle-icon"></i> </span>
</div>
</div> </div>
<div class="day-body"> <div class="rw-tbl-wrap">
<table> <table class="rw-table">
<thead> <thead>
<tr> <tr>
<th style="width: 40px;">No</th> <th style="width:36px; text-align:center;">No</th>
<th>Nama Kegiatan</th> <th>Nama Kegiatan</th>
<th style="width: 110px;">Waktu</th> <th style="width:95px;">Waktu</th>
<th>Kelas</th> <th style="width:110px;">Kategori</th>
<th style="width: 130px;">Kategori</th> <th style="width:140px;">Kelas</th>
<th style="width: 250px; text-align: center;">Statistik Absensi</th> <th style="width:58px; text-align:center; color:#22c55e;" title="Hadir efektif (termasuk terlambat)">Hadir</th>
<th style="width: 90px; text-align: center;">Aksi</th> <th style="width:52px; text-align:center; color:#FF9800;" title="Terlambat">Tlbt</th>
<th style="width:48px; text-align:center; color:#f59e0b;" title="Izin">Izin</th>
<th style="width:48px; text-align:center; color:#3b82f6;" title="Sakit">Skt</th>
<th style="width:48px; text-align:center; color:#ef4444;" title="Alpa">Alpa</th>
<th style="width:90px;">Progress</th>
<th style="width:88px; text-align:center;">Aksi</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<?php $__currentLoopData = $items; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $i => $kegiatan): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> <?php $__currentLoopData = $items; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $idx => $kegiatan): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$hadirEfektif = $kegiatan->hadir + $kegiatan->terlambat;
$totalKeg = $kegiatan->total_absensi;
$kelasNames = $kegiatan->kelasKegiatan->pluck('nama_kelas');
$isUmum = $kelasNames->isEmpty();
?>
<tr> <tr>
<td><?php echo e($i + 1); ?></td> <td style="color:#94a3b8; font-size:.76rem; text-align:center;"><?php echo e($idx + 1); ?></td>
<td><strong><?php echo e($kegiatan->nama_kegiatan); ?></strong></td> <td>
<td style="white-space: nowrap; color: #64748b; font-size: 0.82rem;"> <div style="font-weight:700; font-size:.87rem; color:var(--primary-dark);"><?php echo e($kegiatan->nama_kegiatan); ?></div>
<i class="fas fa-clock" style="color: var(--primary-color);"></i> </td>
<?php echo e(date('H:i', strtotime($kegiatan->waktu_mulai))); ?><?php echo e(date('H:i', strtotime($kegiatan->waktu_selesai))); ?> <td style="font-size:.79rem; color:#64748b; white-space:nowrap;">
<?php echo e(date('H:i', strtotime($kegiatan->waktu_mulai))); ?><br>
<span style="color:#94a3b8; font-size:.7rem;">s/d <?php echo e(date('H:i', strtotime($kegiatan->waktu_selesai))); ?></span>
</td> </td>
<td> <td>
<?php if($kegiatan->kelasKegiatan->isEmpty()): ?> <?php if($kegiatan->kategori): ?>
<span class="umum-tag"><i class="fas fa-globe"></i> Umum</span> <span class="rw-kat-tag"><?php echo e($kegiatan->kategori->nama_kategori); ?></span>
<?php endif; ?>
</td>
<td>
<?php if($isUmum): ?>
<span class="rw-umum-tag"><i class="fas fa-globe-asia"></i> Umum</span>
<?php else: ?> <?php else: ?>
<?php $__currentLoopData = $kegiatan->kelasKegiatan->take(3); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kls): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?> <?php $__currentLoopData = $kelasNames->take(2); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kn): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<span class="kelas-tag"><?php echo e($kls->nama_kelas); ?></span> <span class="rw-kelas-tag"><?php echo e($kn); ?></span>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?> <?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<?php if($kegiatan->kelasKegiatan->count() > 3): ?> <?php if($kelasNames->count() > 2): ?>
<span class="umum-tag">+<?php echo e($kegiatan->kelasKegiatan->count() - 3); ?></span> <span class="rw-umum-tag">+<?php echo e($kelasNames->count()-2); ?></span>
<?php endif; ?> <?php endif; ?>
<?php endif; ?> <?php endif; ?>
</td> </td>
<td style="text-align:center; font-weight:700; color:#065f46;"><?php echo e($hadirEfektif ?: ''); ?></td>
<td style="text-align:center; color:#e65100;"><?php echo e($kegiatan->terlambat ?: ''); ?></td>
<td style="text-align:center; color:#92400e;"><?php echo e($kegiatan->izin ?: ''); ?></td>
<td style="text-align:center; color:#1e40af;"><?php echo e($kegiatan->sakit ?: ''); ?></td>
<td style="text-align:center; color:#991b1b; font-weight:700;"><?php echo e($kegiatan->alpa ?: ''); ?></td>
<td> <td>
<span class="badge badge-success"><?php echo e($kegiatan->kategori->nama_kategori); ?></span> <?php if($totalKeg > 0): ?>
</td> <?php
<td style="text-align: center;"> $segs = [
<?php if($kegiatan->total_absensi > 0): ?> ['w'=>round($kegiatan->hadir/$totalKeg*100), 'c'=>'#22c55e'],
<div class="stat-chips" style="justify-content: center;"> ['w'=>round($kegiatan->terlambat/$totalKeg*100), 'c'=>'#FF9800'],
<?php if($kegiatan->hadir > 0): ?> ['w'=>round($kegiatan->izin/$totalKeg*100), 'c'=>'#f59e0b'],
<span class="chip chip-hadir"><i class="fas fa-check"></i> <?php echo e($kegiatan->hadir); ?></span> ['w'=>round($kegiatan->sakit/$totalKeg*100), 'c'=>'#3b82f6'],
<?php endif; ?> ['w'=>round($kegiatan->alpa/$totalKeg*100), 'c'=>'#ef4444'],
<?php if(($kegiatan->terlambat ?? 0) > 0): ?> ];
<span class="chip chip-terlambat"><i class="fas fa-clock"></i> <?php echo e($kegiatan->terlambat); ?></span> ?>
<?php endif; ?> <div class="rw-mini-prog">
<?php if($kegiatan->izin > 0): ?> <?php $__currentLoopData = $segs; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $s): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<span class="chip chip-izin"><i class="fas fa-envelope"></i> <?php echo e($kegiatan->izin); ?></span> <?php if($s['w'] > 0): ?><div style="width:<?php echo e($s['w']); ?>%;background:<?php echo e($s['c']); ?>;"></div><?php endif; ?>
<?php endif; ?> <?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<?php if($kegiatan->sakit > 0): ?>
<span class="chip chip-sakit"><i class="fas fa-heartbeat"></i> <?php echo e($kegiatan->sakit); ?></span>
<?php endif; ?>
<?php if($kegiatan->alpa > 0): ?>
<span class="chip chip-alpa"><i class="fas fa-times"></i> <?php echo e($kegiatan->alpa); ?></span>
<?php endif; ?>
<?php if(($kegiatan->pulang ?? 0) > 0): ?>
<span class="chip chip-pulang"><i class="fas fa-home"></i> <?php echo e($kegiatan->pulang); ?></span>
<?php endif; ?>
</div>
<div style="font-size: 0.74rem; color: #94a3b8; margin-top: 3px;">
Total: <?php echo e($kegiatan->total_absensi); ?>
</div> </div>
<div style="font-size:.67rem; color:#94a3b8; margin-top:2px;"><?php echo e($hadirEfektif); ?>/<?php echo e($totalKeg); ?></div>
<?php else: ?> <?php else: ?>
<span class="chip chip-none">Belum ada data</span> <span style="color:#cbd5e1; font-size:.76rem;"></span>
<?php endif; ?> <?php endif; ?>
</td> </td>
<td style="text-align:center;"> <td style="text-align:center;">
<a href="<?php echo e(route('admin.riwayat-kegiatan.show', $kegiatan->id)); ?>?mode=hari_ini&tanggal=<?php echo e($tgl); ?>&dari=<?php echo e($tgl); ?>&sampai=<?php echo e($tgl); ?>"
<a href="<?php echo e(route('admin.riwayat-kegiatan.show', $kegiatan->id)); ?>?tanggal_dari=<?php echo e($activeDari); ?>&tanggal_sampai=<?php echo e($activeSampai); ?>" class="btn-tbl-detail">
class="btn-detail"> <i class="fas fa-users"></i> Santri
<i class="fas fa-eye"></i> Detail
</a> </a>
</td> </td>
</tr> </tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?> <?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody> </tbody>
<?php if($items->count() > 1): ?>
<tfoot>
<tr style="background:#f0fdf4; border-top:1.5px solid #bbf7d0;">
<td colspan="5" style="font-size:.78rem; font-weight:700; color:#065f46; padding:8px 13px;">
<i class="fas fa-layer-group"></i> Total <?php echo e($tglLabel); ?>
</td>
<td style="text-align:center; font-weight:800; color:#065f46;"><?php echo e($tglHadir); ?></td>
<td style="text-align:center; font-weight:700; color:#e65100;"><?php echo e($items->sum('terlambat')); ?></td>
<td style="text-align:center; font-weight:700; color:#92400e;"><?php echo e($items->sum('izin')); ?></td>
<td style="text-align:center; font-weight:700; color:#1e40af;"><?php echo e($items->sum('sakit')); ?></td>
<td style="text-align:center; font-weight:700; color:#991b1b;"><?php echo e($items->sum('alpa')); ?></td>
<td colspan="2" style="font-size:.75rem; color:#94a3b8; padding:8px 13px;">
<?php echo e($tglTotal); ?> tercatat &nbsp;·&nbsp; <?php echo e($tglPct); ?>% hadir
</td>
</tr>
</tfoot>
<?php endif; ?>
</table> </table>
</div> </div>
</div> </div>
<?php endif; ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?> <?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<div class="pagination" style="margin-top: 16px;">
<?php echo $kegiatans->appends(request()->query())->links('pagination::simple-bootstrap-4'); ?>
</div>
<?php else: ?> <?php else: ?>
<div class="empty-state"> <div class="rw-empty">
<i class="fas fa-inbox"></i> <i class="fas fa-calendar-times"></i>
<h3>Tidak Ada Data</h3> <h3>Tidak Ada Data Absensi</h3>
<p>Tidak ada kegiatan pada periode <strong><?php echo e($periodeLabel); ?></strong>.</p> <p>Tidak ada absensi yang tercatat pada periode <strong><?php echo e($periodeLabel); ?></strong>.</p>
<?php if($mode === 'custom'): ?>
<p style="margin-top:8px; font-size:.82rem; color:#6b7280;">
Pastikan rentang tanggal sudah benar dan ada data absensi di periode tersebut.
</p>
<?php endif; ?>
</div> </div>
<?php endif; ?> <?php endif; ?>
<script> <?php endif; ?>
function toggleDay(header) {
var body = header.nextElementSibling;
var icon = header.querySelector('.toggle-icon');
if (body.style.display === 'none') {
body.style.display = 'block';
icon.classList.remove('collapsed');
} else {
body.style.display = 'none';
icon.classList.add('collapsed');
}
}
</script>
<?php $__env->stopSection(); ?> <?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kegiatan/riwayat/index.blade.php ENDPATH**/ ?> <?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kegiatan/riwayat/index.blade.php ENDPATH**/ ?>

View File

@ -1,632 +0,0 @@
<?php $__env->startSection('title', 'Kegiatan & Absensi'); ?>
<?php $__env->startSection('content'); ?>
<style>
:root {
--g: #1a7a5e;
--m: #2bbd8e;
--sf: #e8f7f2;
--gd: #f5a623;
--rd: #e53e3e;
--bl: #3b82f6;
--tx: #1a2332;
--mu: #6b7280;
--br: #e2e8f0;
--wh: #ffffff;
--bg: #f8fafb;
--ra: 14px;
--sh: 0 4px 20px rgba(0,0,0,0.07);
--shl: 0 8px 40px rgba(0,0,0,0.12);
}
/* ── HERO ── */
.kg-hero {
background: linear-gradient(135deg, #0d3b2e 0%, #1a7a5e 55%, #2bbd8e 100%);
border-radius: var(--ra);
padding: 26px 28px 22px;
margin-bottom: 16px;
position: relative;
overflow: hidden;
color: white;
}
.kg-hero::before { content:''; position:absolute; top:-50px; right:-50px; width:180px; height:180px; border-radius:50%; background:rgba(255,255,255,0.05); pointer-events:none; }
.kg-hero::after { content:''; position:absolute; bottom:-40px; left:38%; width:140px; height:140px; border-radius:50%; background:rgba(255,255,255,0.04); pointer-events:none; }
.kg-hero-row { display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:10px; position:relative; z-index:1; }
.kg-hero-title { font-size:1.25rem; font-weight:800; margin:0 0 3px; }
.kg-hero-sub { font-size:0.85rem; opacity:0.8; margin:0; }
.kg-hero-right { text-align:right; }
.kg-hero-day { font-size:1rem; font-weight:700; opacity:0.9; }
.kg-hero-date { font-size:0.8rem; opacity:0.7; }
.kg-hero-badges { display:flex; gap:7px; flex-wrap:wrap; margin-top:14px; position:relative; z-index:1; }
.kg-badge {
background:rgba(255,255,255,0.14); border:1px solid rgba(255,255,255,0.2);
padding:4px 11px; border-radius:20px; font-size:0.79rem; font-weight:600;
display:inline-flex; align-items:center; gap:5px;
}
.kg-badge.fire { background:linear-gradient(135deg,#f59e0b,#f97316); border:none; }
/* ── KPI CARDS ── */
.kg-kpi-row { display:grid; grid-template-columns:repeat(5,1fr); gap:10px; margin-bottom:16px; }
.kg-kpi { background:white; border-radius:12px; padding:14px 12px; box-shadow:var(--sh); text-align:center; border-top:3px solid transparent; transition:transform 0.18s,box-shadow 0.18s; }
.kg-kpi:hover { transform:translateY(-3px); box-shadow:var(--shl); }
.kg-kpi.c-green { border-top-color:#2bbd8e; }
.kg-kpi.c-blue { border-top-color:#3b82f6; }
.kg-kpi.c-gold { border-top-color:#f5a623; }
.kg-kpi.c-orange { border-top-color:#f97316; }
.kg-kpi.c-red { border-top-color:#e53e3e; }
.kg-kpi-ic { width:36px; height:36px; border-radius:9px; display:flex; align-items:center; justify-content:center; font-size:0.9rem; margin:0 auto 7px; }
.c-green .kg-kpi-ic { background:#d1fae5; color:#059669; }
.c-blue .kg-kpi-ic { background:#dbeafe; color:#2563eb; }
.c-gold .kg-kpi-ic { background:#fef3c7; color:#d97706; }
.c-orange .kg-kpi-ic { background:#ffedd5; color:#ea580c; }
.c-red .kg-kpi-ic { background:#fee2e2; color:#dc2626; }
.kg-kpi-v { font-size:1.7rem; font-weight:800; color:var(--tx); line-height:1; margin-bottom:3px; }
.kg-kpi-l { font-size:0.73rem; color:var(--mu); font-weight:500; }
.kg-kpi-bar { margin-top:7px; height:4px; background:#f0f0f0; border-radius:2px; overflow:hidden; }
.kg-kpi-fill { height:100%; border-radius:2px; }
/* ── TABS ── */
.kg-tabs { display:flex; gap:4px; background:var(--bg); border-radius:12px; padding:5px; margin-bottom:18px; border:1px solid var(--br); overflow-x:auto; }
.kg-tab { flex:1; min-width:90px; padding:9px 14px; border:none; background:transparent; border-radius:8px; font-size:0.82rem; font-weight:600; color:var(--mu); cursor:pointer; transition:all 0.18s; display:flex; align-items:center; justify-content:center; gap:6px; white-space:nowrap; }
.kg-tab:hover { background:white; color:var(--g); }
.kg-tab.active { background:white; color:var(--g); box-shadow:0 2px 8px rgba(0,0,0,0.09); }
.kg-panel { display:none; }
.kg-panel.active { display:block; }
/* ── FILTER BAR ── */
.kg-tab-filter {
background:white; border-radius:12px; padding:12px 14px;
margin-bottom:14px; box-shadow:var(--sh);
display:flex; flex-wrap:wrap; gap:8px; align-items:flex-end;
}
.kg-fg { display:flex; flex-direction:column; gap:3px; }
.kg-fg label { font-size:0.72rem; font-weight:700; color:var(--mu); text-transform:uppercase; letter-spacing:0.4px; }
.kg-presets { display:flex; gap:4px; flex-wrap:wrap; }
.kg-preset-btn { padding:6px 12px; border:1.5px solid var(--br); border-radius:8px; background:white; font-size:0.79rem; font-weight:600; color:var(--mu); cursor:pointer; transition:all 0.15s; white-space:nowrap; }
.kg-preset-btn:hover { border-color:var(--m); color:var(--g); background:var(--sf); }
.kg-preset-btn.active { border-color:var(--g); background:var(--g); color:white; }
.kg-date-range { display:flex; align-items:center; gap:5px; }
.kg-date-range input[type=date] { padding:6px 9px; border:1.5px solid var(--br); border-radius:8px; font-size:0.8rem; color:var(--tx); background:white; }
.kg-date-range input[type=date]:focus { outline:none; border-color:var(--m); }
.kg-date-range span { color:var(--mu); font-size:0.79rem; font-weight:600; }
.kg-apply-btn { padding:7px 15px; background:var(--g); color:white; border:none; border-radius:8px; font-size:0.81rem; font-weight:700; cursor:pointer; display:inline-flex; align-items:center; gap:5px; }
.kg-apply-btn:hover { background:#155c47; }
.kg-filter-label { font-size:0.77rem; color:var(--mu); padding:5px 9px; background:var(--bg); border-radius:8px; border:1px solid var(--br); display:flex; align-items:center; gap:4px; align-self:center; }
.kg-filter-label i { color:var(--g); }
/* ── JADWAL CARDS ── */
.kg-jadwal-group { margin-bottom:14px; }
.kg-hari-label { font-size:0.77rem; font-weight:700; text-transform:uppercase; letter-spacing:0.8px; color:var(--g); padding:5px 11px; background:var(--sf); border-radius:8px; margin-bottom:8px; display:inline-flex; align-items:center; gap:5px; }
.kg-hari-label.today-label { background:var(--g); color:white; }
.kg-jadwal-card { background:white; border-radius:11px; padding:13px 15px; box-shadow:var(--sh); display:flex; align-items:center; gap:12px; border-left:4px solid var(--br); margin-bottom:7px; transition:transform 0.16s; }
.kg-jadwal-card:hover { transform:translateX(3px); }
.kg-jadwal-card.s-hadir { border-left-color:#2bbd8e; }
.kg-jadwal-card.s-terlambat { border-left-color:#f59e0b; }
.kg-jadwal-card.s-izin { border-left-color:#3b82f6; }
.kg-jadwal-card.s-sakit { border-left-color:#8b5cf6; }
.kg-jadwal-card.s-alpa { border-left-color:#e53e3e; }
.kg-jadwal-card.s-pulang { border-left-color:#0d9488; }
.kg-jadwal-card.s-belum { border-left-color:#f5a623; }
.kg-time { min-width:58px; text-align:center; }
.kg-time-main { font-size:0.93rem; font-weight:700; color:var(--g); }
.kg-time-end { font-size:0.71rem; color:var(--mu); font-weight:500; }
.kg-divider { width:1px; height:34px; background:var(--br); flex-shrink:0; }
.kg-jinfo { flex:1; min-width:0; }
.kg-jname { font-weight:700; font-size:0.89rem; color:var(--tx); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; margin:0 0 3px; }
.kg-jmeta { font-size:0.76rem; color:var(--mu); display:flex; gap:8px; flex-wrap:wrap; }
.kg-detail-btn {
padding:5px 11px; background:var(--g); color:white !important;
border-radius:7px; font-size:0.75rem; font-weight:600;
text-decoration:none !important; display:inline-flex;
align-items:center; gap:4px; white-space:nowrap; flex-shrink:0;
transition:background 0.15s;
}
.kg-detail-btn:hover { background:#155c47; }
/* Pill status */
.kpill { padding:3px 11px; border-radius:20px; font-size:0.75rem; font-weight:700; flex-shrink:0; }
.kpill.hadir { background:#d1fae5; color:#065f46; }
.kpill.terlambat { background:#fef3c7; color:#92400e; }
.kpill.belum { background:#fef3c7; color:#92400e; }
.kpill.izin { background:#dbeafe; color:#1e40af; }
.kpill.sakit { background:#ede9fe; color:#5b21b6; }
.kpill.alpa { background:#fee2e2; color:#991b1b; }
.kpill.pulang { background:#ccfbf1; color:#0f766e; }
/* ── STATISTIK LAYOUT ── */
.kg-stat-grid { display:grid; grid-template-columns:1fr 1fr; gap:14px; margin-bottom:14px; }
.kg-chart-box { background:white; border-radius:12px; padding:18px; box-shadow:var(--sh); }
.kg-chart-title { font-size:0.86rem; font-weight:700; color:var(--tx); margin-bottom:14px; display:flex; align-items:center; gap:6px; }
/* ── RECENT ABSENSI ── */
.kg-recent-list { display:flex; flex-direction:column; gap:6px; }
.kg-recent-item {
display:flex; align-items:center; gap:11px;
background:white; border-radius:10px; padding:10px 13px;
box-shadow:var(--sh); border-left:3px solid transparent;
transition:transform 0.15s;
}
.kg-recent-item:hover { transform:translateX(3px); }
.kg-recent-item.s-hadir { border-left-color:#2bbd8e; }
.kg-recent-item.s-terlambat { border-left-color:#f59e0b; }
.kg-recent-item.s-izin { border-left-color:#3b82f6; }
.kg-recent-item.s-sakit { border-left-color:#8b5cf6; }
.kg-recent-item.s-alpa { border-left-color:#e53e3e; }
.kg-recent-item.s-pulang { border-left-color:#0d9488; }
.kg-recent-ic {
width:32px; height:32px; border-radius:8px; flex-shrink:0;
display:flex; align-items:center; justify-content:center; font-size:0.82rem;
}
.s-hadir .kg-recent-ic { background:#d1fae5; color:#059669; }
.s-terlambat .kg-recent-ic { background:#fef3c7; color:#d97706; }
.s-izin .kg-recent-ic { background:#dbeafe; color:#2563eb; }
.s-sakit .kg-recent-ic { background:#ede9fe; color:#7c3aed; }
.s-alpa .kg-recent-ic { background:#fee2e2; color:#dc2626; }
.s-pulang .kg-recent-ic { background:#ccfbf1; color:#0f766e; }
.kg-recent-info { flex:1; min-width:0; }
.kg-recent-name { font-weight:700; font-size:0.84rem; color:var(--tx); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.kg-recent-meta { font-size:0.72rem; color:var(--mu); margin-top:2px; display:flex; gap:8px; flex-wrap:wrap; }
.kg-recent-right { text-align:right; flex-shrink:0; }
.kg-recent-date { font-size:0.69rem; color:var(--mu); opacity:0.7; margin-top:3px; }
/* ── MINI CALENDAR ── */
.kg-cal-mini { width:220px; flex-shrink:0; }
.kg-cal-mini-grid { display:grid; grid-template-columns:repeat(7,1fr); gap:2px; }
.kg-cal-mini-dname { text-align:center; font-size:0.6rem; font-weight:700; color:var(--mu); padding-bottom:3px; text-transform:uppercase; }
.kg-cal-mini-cell { aspect-ratio:1; border-radius:4px; display:flex; align-items:center; justify-content:center; font-size:0.63rem; font-weight:600; cursor:default; transition:transform 0.1s; }
.kg-cal-mini-cell:hover { transform:scale(1.2); z-index:5; }
.kg-cal-mini-cell.l0 { background:#f3f4f6; color:#9ca3af; }
.kg-cal-mini-cell.l1 { background:#bbf7d0; color:#065f46; }
.kg-cal-mini-cell.l2 { background:#4ade80; color:#14532d; }
.kg-cal-mini-cell.l3 { background:#16a34a; color:white; }
.kg-cal-mini-cell.l4 { background:#064e2d; color:white; }
.kg-cal-mini-cell.is-today { outline:2px solid var(--gd); outline-offset:1px; }
.kg-cal-mini-cell.out-range { opacity:0.3; }
/* ── EMPTY ── */
.kg-empty { text-align:center; padding:36px 20px; color:var(--mu); background:white; border-radius:12px; box-shadow:var(--sh); }
.kg-empty i { font-size:2.8rem; opacity:0.2; display:block; margin-bottom:10px; }
@media (max-width:768px) {
.kg-kpi-row { grid-template-columns:repeat(3,1fr); }
.kg-stat-grid { grid-template-columns:1fr; }
}
</style>
<div class="kg-hero">
<div class="kg-hero-row">
<div>
<h1 class="kg-hero-title"><i class="fas fa-calendar-check"></i> Kegiatan & Absensi</h1>
<p class="kg-hero-sub"><?php echo e($santri->nama_lengkap); ?> &nbsp;·&nbsp; Kelas <?php echo e($namaKelas); ?></p>
</div>
<div class="kg-hero-right">
<div class="kg-hero-day"><?php echo e(\Carbon\Carbon::now()->locale('id')->isoFormat('dddd')); ?></div>
<div class="kg-hero-date"><?php echo e(\Carbon\Carbon::now()->locale('id')->isoFormat('D MMMM YYYY')); ?></div>
</div>
</div>
<div class="kg-hero-badges">
<span class="kg-badge"><i class="fas fa-id-card"></i> <?php echo e($santri->nis ?? $santri->id_santri); ?></span>
<span class="kg-badge"><i class="fas fa-chart-line"></i> <?php echo e($persentaseKehadiran); ?>% kehadiran</span>
<?php if($streak > 0): ?>
<span class="kg-badge fire"><i class="fas fa-fire"></i> Streak <?php echo e($streak); ?>x hadir</span>
<?php endif; ?>
</div>
</div>
<div class="kg-kpi-row">
<div class="kg-kpi c-green">
<div class="kg-kpi-ic"><i class="fas fa-list-alt"></i></div>
<div class="kg-kpi-v"><?php echo e($expectedTotal); ?></div>
<div class="kg-kpi-l">Wajib Hadir</div>
<div class="kg-kpi-bar"><div class="kg-kpi-fill" style="width:100%;background:#2bbd8e;"></div></div>
</div>
<div class="kg-kpi c-blue">
<div class="kg-kpi-ic"><i class="fas fa-check-circle"></i></div>
<div class="kg-kpi-v"><?php echo e($hadirEfektif); ?></div>
<div class="kg-kpi-l">Hadir
<?php if($terlambatRange > 0): ?>
<span style="display:block;font-size:0.67rem;color:#f59e0b;">(+<?php echo e($terlambatRange); ?> terlambat)</span>
<?php endif; ?>
</div>
<div class="kg-kpi-bar"><div class="kg-kpi-fill" style="width:<?php echo e($expectedTotal > 0 ? round($hadirEfektif/$expectedTotal*100) : 0); ?>%;background:#3b82f6;"></div></div>
</div>
<div class="kg-kpi c-gold">
<div class="kg-kpi-ic"><i class="fas fa-percentage"></i></div>
<div class="kg-kpi-v"><?php echo e($persentaseKehadiran); ?>%</div>
<div class="kg-kpi-l">Kehadiran</div>
<div class="kg-kpi-bar"><div class="kg-kpi-fill" style="width:<?php echo e($persentaseKehadiran); ?>%;background:#f5a623;"></div></div>
</div>
<div class="kg-kpi c-orange">
<div class="kg-kpi-ic"><i class="fas fa-hourglass-half"></i></div>
<div class="kg-kpi-v"><?php echo e($belumAbsenRange); ?></div>
<div class="kg-kpi-l">Belum Absen</div>
<div class="kg-kpi-bar"><div class="kg-kpi-fill" style="width:<?php echo e($expectedTotal > 0 ? round($belumAbsenRange/$expectedTotal*100) : 0); ?>%;background:#f97316;"></div></div>
</div>
<div class="kg-kpi c-red">
<div class="kg-kpi-ic"><i class="fas fa-times-circle"></i></div>
<div class="kg-kpi-v"><?php echo e($alpaRange); ?></div>
<div class="kg-kpi-l">Alpa</div>
<div class="kg-kpi-bar"><div class="kg-kpi-fill" style="width:<?php echo e($expectedTotal > 0 ? round($alpaRange/$expectedTotal*100) : 0); ?>%;background:#e53e3e;"></div></div>
</div>
</div>
<div class="kg-tabs">
<button class="kg-tab <?php echo e($activeTab === 'statistik' ? 'active' : ''); ?>" onclick="switchTab('statistik',this)">
<i class="fas fa-chart-bar"></i> Statistik
</button>
<button class="kg-tab <?php echo e($activeTab === 'jadwal' ? 'active' : ''); ?>" onclick="switchTab('jadwal',this)">
<i class="fas fa-clock"></i> Jadwal
<?php if($jadwalDalamRange->count() > 0): ?>
<span style="background:var(--g);color:white;border-radius:10px;padding:1px 6px;font-size:0.67rem;"><?php echo e($jadwalDalamRange->count()); ?></span>
<?php endif; ?>
</button>
</div>
<div class="kg-panel <?php echo e($activeTab === 'statistik' ? 'active' : ''); ?>" id="panel-statistik">
<form method="GET" action="<?php echo e(route('santri.kegiatan.index')); ?>" id="formStat">
<input type="hidden" name="tab" value="statistik">
<input type="hidden" name="preset_jad" value="<?php echo e($jadPreset); ?>">
<input type="hidden" name="preset_stat" id="hStat" value="<?php echo e($statPreset); ?>">
<input type="hidden" name="stat_date_from" id="hStatFrom" value="<?php echo e(request('stat_date_from')); ?>">
<input type="hidden" name="stat_date_to" id="hStatTo" value="<?php echo e(request('stat_date_to')); ?>">
<div class="kg-tab-filter">
<div class="kg-fg">
<label><i class="fas fa-bolt"></i> Periode</label>
<div class="kg-presets" id="statPresets">
<?php $__currentLoopData = ['today'=>'Hari Ini','this_week'=>'Minggu Ini','last_30'=>'30 Hari','this_month'=>'Bulan Ini','last_month'=>'Bulan Lalu']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $v=>$l): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<button type="button" class="kg-preset-btn <?php echo e($statPreset===$v ? 'active' : ''); ?>"
onclick="setPreset('stat','<?php echo e($v); ?>')"><?php echo e($l); ?></button>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
</div>
<div class="kg-fg">
<label><i class="fas fa-calendar-alt"></i> Kustom</label>
<div class="kg-date-range">
<input type="date" id="inpStatFrom" value="<?php echo e(request('stat_date_from', $statFrom->format('Y-m-d'))); ?>" onchange="setCustom('stat')">
<span></span>
<input type="date" id="inpStatTo" value="<?php echo e(request('stat_date_to', $statTo->format('Y-m-d'))); ?>" onchange="setCustom('stat')">
</div>
</div>
<button type="submit" class="kg-apply-btn"><i class="fas fa-sync-alt"></i> Terapkan</button>
<div class="kg-filter-label">
<i class="fas fa-calendar-check"></i>
<?php echo e($statFrom->locale('id')->isoFormat('D MMM YYYY')); ?> &ndash; <?php echo e($statTo->locale('id')->isoFormat('D MMM YYYY')); ?>
</div>
</div>
</form>
<div class="kg-stat-grid">
<div class="kg-chart-box">
<div class="kg-chart-title">
<i class="fas fa-chart-line" style="color:var(--m);"></i> Tren Kehadiran
<span style="margin-left:auto;font-size:0.73rem;color:var(--mu);font-weight:500;"><?php echo e($diffDays<=31?'Harian':'Mingguan'); ?></span>
</div>
<canvas id="chartTren" style="max-height:220px;"></canvas>
</div>
<div class="kg-chart-box">
<div class="kg-chart-title"><i class="fas fa-chart-pie" style="color:var(--gd);"></i> Distribusi Status</div>
<canvas id="chartDonut" style="max-height:200px;"></canvas>
</div>
</div>
<div style="display:grid; grid-template-columns:1fr auto; gap:14px; margin-bottom:14px; align-items:start;">
<div class="kg-chart-box" style="min-width:0;">
<div class="kg-chart-title">
<i class="fas fa-history" style="color:var(--m);"></i>
Absensi Terbaru
<span style="margin-left:auto;font-size:0.71rem;color:var(--mu);font-weight:500;">
<?php echo e($statFrom->locale('id')->isoFormat('D MMM')); ?> <?php echo e($statTo->locale('id')->isoFormat('D MMM YY')); ?>
</span>
</div>
<?php if($recentAbsensi->count() > 0): ?>
<div class="kg-recent-list">
<?php $__currentLoopData = $recentAbsensi; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $ab): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php $sl = strtolower($ab->status); ?>
<div class="kg-recent-item s-<?php echo e($sl); ?>">
<div class="kg-recent-ic">
<?php if($ab->status === 'Hadir'): ?> <i class="fas fa-check"></i>
<?php elseif($ab->status === 'Terlambat'): ?> <i class="fas fa-clock"></i>
<?php elseif($ab->status === 'Izin'): ?> <i class="fas fa-info"></i>
<?php elseif($ab->status === 'Sakit'): ?> <i class="fas fa-heartbeat"></i>
<?php elseif($ab->status === 'Alpa'): ?> <i class="fas fa-times"></i>
<?php elseif($ab->status === 'Pulang'): ?> <i class="fas fa-home"></i>
<?php endif; ?>
</div>
<div class="kg-recent-info">
<div class="kg-recent-name"><?php echo e($ab->kegiatan->nama_kegiatan); ?></div>
<div class="kg-recent-meta">
<span><i class="fas fa-tag"></i> <?php echo e($ab->kegiatan->kategori->nama_kategori); ?></span>
<?php if($ab->waktu_absen): ?>
<span><i class="fas fa-clock"></i> <?php echo e(\Carbon\Carbon::parse($ab->waktu_absen)->format('H:i')); ?></span>
<?php endif; ?>
<?php $metode = $ab->metode_absen ?? ''; ?>
<span>
<i class="fas fa-<?php echo e($metode === 'RFID' ? 'id-card' : ($metode === 'Import_Mesin' ? 'desktop' : 'hand-pointer')); ?>"></i>
<?php echo e($metode === 'Import_Mesin' ? 'Mesin' : ($metode ?: 'Manual')); ?>
</span>
</div>
</div>
<div class="kg-recent-right">
<span class="kpill <?php echo e($sl); ?>" style="font-size:0.72rem;padding:2px 9px;"><?php echo e($ab->status); ?></span>
<div class="kg-recent-date">
<?php echo e(\Carbon\Carbon::parse($ab->tanggal)->locale('id')->isoFormat('D MMM')); ?>
</div>
</div>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
<?php else: ?>
<p style="text-align:center;color:var(--mu);font-size:0.84rem;padding:20px 0;">
Belum ada absensi dalam periode ini.
</p>
<?php endif; ?>
</div>
<?php $calMonth = collect($heatmapMonths)->last(); ?>
<?php if($calMonth): ?>
<div class="kg-chart-box kg-cal-mini">
<div class="kg-chart-title" style="margin-bottom:8px;font-size:0.82rem;">
<i class="fas fa-calendar-alt" style="color:var(--g);"></i> <?php echo e($calMonth['label']); ?>
</div>
<div style="display:flex;gap:3px;align-items:center;margin-bottom:7px;font-size:0.67rem;color:var(--mu);">
<?php $__currentLoopData = ['#f3f4f6','#bbf7d0','#4ade80','#16a34a','#064e2d']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $hc): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div style="width:7px;height:7px;border-radius:2px;background:<?php echo e($hc); ?>;flex-shrink:0;"></div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<span style="margin-left:2px;">Hadir</span>
</div>
<div class="kg-cal-mini-grid">
<?php $__currentLoopData = ['S','S','R','K','J','S','M']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $hn): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div class="kg-cal-mini-dname"><?php echo e($hn); ?></div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<?php for($e = 1; $e < $calMonth['firstDayOfWeek']; $e++): ?>
<div></div>
<?php endfor; ?>
<?php $__currentLoopData = $calMonth['days']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $day): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div class="kg-cal-mini-cell l<?php echo e($day['level']); ?> <?php echo e($day['is_today'] ? 'is-today' : ''); ?> <?php echo e(!$day['in_range'] ? 'out-range' : ''); ?>"
title="<?php echo e(\Carbon\Carbon::parse($day['date'])->locale('id')->isoFormat('D MMM')); ?><?php echo e($day['total'] > 0 ? ': '.$day['count'].'/'.$day['total'].' hadir' : ''); ?>">
<?php echo e($day['day']); ?>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
</div>
<?php endif; ?>
</div>
</div>
<div class="kg-panel <?php echo e($activeTab === 'jadwal' ? 'active' : ''); ?>" id="panel-jadwal">
<form method="GET" action="<?php echo e(route('santri.kegiatan.index')); ?>" id="formJad">
<input type="hidden" name="tab" value="jadwal">
<input type="hidden" name="preset_stat" value="<?php echo e($statPreset); ?>">
<input type="hidden" name="preset_jad" id="hJad" value="<?php echo e($jadPreset); ?>">
<input type="hidden" name="jad_date_from" id="hJadFrom" value="<?php echo e(request('jad_date_from')); ?>">
<input type="hidden" name="jad_date_to" id="hJadTo" value="<?php echo e(request('jad_date_to')); ?>">
<div class="kg-tab-filter">
<div class="kg-fg">
<label><i class="fas fa-bolt"></i> Periode</label>
<div class="kg-presets" id="jadPresets">
<?php $__currentLoopData = ['today'=>'Hari Ini','this_week'=>'Minggu Ini','this_month'=>'Bulan Ini','last_month'=>'Bulan Lalu']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $v=>$l): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<button type="button" class="kg-preset-btn <?php echo e($jadPreset===$v ? 'active' : ''); ?>"
onclick="setPreset('jad','<?php echo e($v); ?>')"><?php echo e($l); ?></button>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
</div>
<div class="kg-fg">
<label><i class="fas fa-calendar-alt"></i> Kustom</label>
<div class="kg-date-range">
<input type="date" id="inpJadFrom" value="<?php echo e(request('jad_date_from', $jadFrom->format('Y-m-d'))); ?>" onchange="setCustom('jad')">
<span></span>
<input type="date" id="inpJadTo" value="<?php echo e(request('jad_date_to', $jadTo->format('Y-m-d'))); ?>" onchange="setCustom('jad')">
</div>
</div>
<button type="submit" class="kg-apply-btn"><i class="fas fa-sync-alt"></i> Terapkan</button>
<div class="kg-filter-label">
<i class="fas fa-calendar-check"></i>
<?php echo e($jadFrom->locale('id')->isoFormat('D MMM')); ?> &ndash; <?php echo e($jadTo->locale('id')->isoFormat('D MMM YYYY')); ?>
</div>
</div>
</form>
<?php if($jadwalDalamRange->count() > 0): ?>
<?php
$hariOrder = ['Senin','Selasa','Rabu','Kamis','Jumat','Sabtu','Ahad'];
$jadGrouped = $jadwalDalamRange->groupBy('hari')
->sortBy(fn($v,$k) => array_search($k, $hariOrder));
?>
<?php $__currentLoopData = $jadGrouped; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $hari => $jadwals): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<div class="kg-jadwal-group">
<div class="kg-hari-label <?php echo e($hari === $hariIni ? 'today-label' : ''); ?>">
<i class="fas fa-calendar-day"></i> <?php echo e($hari); ?>
<?php if($hari === $hariIni): ?> <span style="font-size:0.66rem;opacity:0.85;">(Hari Ini)</span> <?php endif; ?>
</div>
<?php $__currentLoopData = $jadwals; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $jadwal): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$statusAbsen = $hari === $hariIni
? ($absensiHariIni[$jadwal->kegiatan_id] ?? null)
: ($absensiDalamRange[$jadwal->kegiatan_id] ?? null);
$sc = $statusAbsen ? 's-' . strtolower($statusAbsen) : 's-belum';
?>
<div class="kg-jadwal-card <?php echo e($sc); ?>">
<div class="kg-time">
<div class="kg-time-main"><?php echo e(date('H:i', strtotime($jadwal->waktu_mulai))); ?></div>
<div class="kg-time-end"><?php echo e(date('H:i', strtotime($jadwal->waktu_selesai))); ?></div>
</div>
<div class="kg-divider"></div>
<div class="kg-jinfo">
<div class="kg-jname"><?php echo e($jadwal->nama_kegiatan); ?></div>
<div class="kg-jmeta">
<span><i class="fas fa-tag"></i> <?php echo e($jadwal->kategori->nama_kategori); ?></span>
<?php if($jadwal->materi): ?>
<span><i class="fas fa-book"></i> <?php echo e(Str::limit($jadwal->materi, 28)); ?></span>
<?php endif; ?>
</div>
</div>
<?php if($statusAbsen): ?>
<span class="kpill <?php echo e(strtolower($statusAbsen)); ?>">
<?php if($statusAbsen === 'Terlambat'): ?> <i class="fas fa-clock"></i>
<?php elseif($statusAbsen === 'Pulang'): ?> <i class="fas fa-home"></i>
<?php endif; ?>
<?php echo e($statusAbsen); ?>
</span>
<?php elseif($hari === $hariIni): ?>
<span class="kpill belum"><i class="fas fa-hourglass-half"></i> Belum</span>
<?php endif; ?>
<a href="<?php echo e(route('santri.kegiatan.show', $jadwal->kegiatan_id)); ?>?from_tab=jadwal"
class="kg-detail-btn">
<i class="fas fa-chart-bar"></i> Detail
</a>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<?php else: ?>
<div class="kg-empty">
<i class="fas fa-calendar-times"></i>
<p>Tidak ada kegiatan terjadwal dalam periode ini.</p>
</div>
<?php endif; ?>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script>
// ── TAB SWITCHER ─────────────────────────────────
function switchTab(name, el) {
document.querySelectorAll('.kg-tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.kg-panel').forEach(p => p.classList.remove('active'));
el.classList.add('active');
document.getElementById('panel-' + name).classList.add('active');
if (name === 'statistik' && !window._chartsInit) { initCharts(); window._chartsInit = true; }
}
// ── PRESET SETTER ────────────────────────────────
function setPreset(scope, val) {
document.querySelectorAll('#' + scope + 'Presets .kg-preset-btn').forEach(b => b.classList.remove('active'));
event.target.classList.add('active');
var cap = scope.charAt(0).toUpperCase() + scope.slice(1);
document.getElementById('h' + cap).value = val;
document.getElementById('h' + cap + 'From').value = '';
document.getElementById('h' + cap + 'To').value = '';
document.getElementById('form' + cap).submit();
}
function setCustom(scope) {
var cap = scope.charAt(0).toUpperCase() + scope.slice(1);
document.getElementById('h' + cap).value = '';
document.getElementById('h' + cap + 'From').value = document.getElementById('inp' + cap + 'From').value;
document.getElementById('h' + cap + 'To').value = document.getElementById('inp' + cap + 'To').value;
document.querySelectorAll('#' + scope + 'Presets .kg-preset-btn').forEach(b => b.classList.remove('active'));
}
// ── CHARTS ───────────────────────────────────────
function initCharts() {
const trenLabels = <?php echo json_encode(collect($dataGrafik)->pluck('label'), 15, 512) ?>;
const trenHadir = <?php echo json_encode(collect($dataGrafik)->pluck('hadir'), 15, 512) ?>;
const trenTotal = <?php echo json_encode(collect($dataGrafik)->pluck('total'), 15, 512) ?>;
new Chart(document.getElementById('chartTren'), {
type: 'line',
data: {
labels: trenLabels,
datasets: [
{
label: 'Hadir (incl. Terlambat)',
data: trenHadir,
borderColor: '#2bbd8e', backgroundColor: 'rgba(43,189,142,0.1)',
borderWidth: 3, pointRadius: trenLabels.length > 20 ? 2 : 5,
pointBackgroundColor: '#2bbd8e', tension: 0.4, fill: true
},
{
label: 'Total Tercatat',
data: trenTotal,
borderColor: '#cbd5e1', backgroundColor: 'transparent',
borderWidth: 2, borderDash: [4,4],
pointRadius: trenLabels.length > 20 ? 2 : 4,
pointBackgroundColor: '#cbd5e1', tension: 0.4
}
]
},
options: {
responsive: true, maintainAspectRatio: true,
plugins: { legend: { position:'top', labels:{ font:{ size:11, weight:'600' } } } },
scales: {
y: { beginAtZero:true, ticks:{ stepSize:1 }, grid:{ color:'rgba(0,0,0,0.04)' } },
x: { grid:{ display:false }, ticks:{ maxRotation:45, font:{ size:10 }, maxTicksLimit:12 } }
}
}
});
new Chart(document.getElementById('chartDonut'), {
type: 'doughnut',
data: {
labels: ['Hadir', 'Terlambat', 'Izin', 'Sakit', 'Alpa', 'Pulang', 'Belum Absen'],
datasets: [{
data: [
<?php echo e($hadirRange); ?>,
<?php echo e($terlambatRange); ?>,
<?php echo e($izinRange); ?>,
<?php echo e($sakitRange); ?>,
<?php echo e($alpaRange); ?>,
<?php echo e($pulangRange); ?>,
<?php echo e($belumAbsenRange); ?>
],
backgroundColor: ['#2bbd8e','#f59e0b','#3b82f6','#8b5cf6','#e53e3e','#0d9488','#d1d5db'],
borderWidth: 3, borderColor: '#fff'
}]
},
options: {
responsive: true, maintainAspectRatio: true, cutout: '65%',
plugins: {
legend: { position:'bottom', labels:{ padding:10, font:{ size:10 } } },
tooltip: { callbacks: {
label: function(ctx) {
var total = <?php echo e($expectedTotal); ?>;
var pct = total > 0 ? ((ctx.parsed / total) * 100).toFixed(1) : 0;
return ctx.label + ': ' + ctx.parsed + ' (' + pct + '%)';
}
}}
}
}
});
}
// ── INIT ─────────────────────────────────────────
document.addEventListener('DOMContentLoaded', function() {
var tab = new URLSearchParams(window.location.search).get('tab') || 'statistik';
var map = { statistik: 0, jadwal: 1 };
var idx = map[tab] ?? 0;
var tabs = document.querySelectorAll('.kg-tab');
if (tabs[idx]) tabs[idx].click();
});
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/santri/kegiatan/index.blade.php ENDPATH**/ ?>

View File

@ -1,74 +0,0 @@
<!-- views/layouts/santri-wali-sidebar.blade.php -->
<ul class="sidebar-menu">
<li>
<a href="<?php echo e(route('santri.dashboard')); ?>" class="<?php echo e(Request::routeIs('santri.dashboard') ? 'active' : ''); ?>">
<i class="fas fa-tachometer-alt"></i>
<span>Dashboard</span>
</a>
</li>
<li>
<a href="<?php echo e(route('santri.profil.index')); ?>" class="<?php echo e(Request::routeIs('santri.profil.*') ? 'active' : ''); ?>">
<i class="fas fa-user"></i>
<span>Profil Santri</span>
</a>
</li>
<li>
<a href="<?php echo e(route('santri.kegiatan.index')); ?>" class="<?php echo e(Request::routeIs('santri.kegiatan.*') ? 'active' : ''); ?>">
<i class="fas fa-calendar-check"></i>
<span>Kegiatan & Absensi</span>
</a>
</li>
<li>
<a href="<?php echo e(route('santri.capaian.index')); ?>" class="<?php echo e(request()->routeIs('santri.capaian.*') ? 'active' : ''); ?>">
<i class="fas fa-book-reader"></i>
<span>Capaian Materi</span>
</a>
</li>
<li>
<a href="<?php echo e(route('santri.pelanggaran.index')); ?>" class="<?php echo e(Request::routeIs('santri.pelanggaran.*') ? 'active' : ''); ?>">
<i class="fas fa-exclamation-circle"></i>
<span>Riwayat Pelanggaran</span>
</a>
</li>
<li>
<a href="<?php echo e(route('santri.uang-saku.index')); ?>" class="<?php echo e(Request::routeIs('santri.uang-saku.*') ? 'active' : ''); ?>">
<i class="fas fa-wallet"></i>
<span>Riwayat Uang Saku</span>
</a>
</li>
<li>
<a href="<?php echo e(route('santri.kesehatan.index')); ?>" class="<?php echo e(request()->routeIs('santri.kesehatan.*') ? 'active' : ''); ?>">
<i class="fas fa-heartbeat"></i>
<span>Riwayat Kesehatan</span>
</a>
</li>
<li>
<a href="<?php echo e(route('santri.kepulangan.index')); ?>" class="<?php echo e(request()->routeIs('santri.kepulangan.*') ? 'active' : ''); ?>">
<i class="fas fa-home"></i>
<span>Riwayat Kepulangan</span>
</a>
</li>
<li>
<a href="<?php echo e(route('santri.berita.index')); ?>" class="<?php echo e(request()->routeIs('santri.berita.*') ? 'active' : ''); ?>">
<i class="fas fa-newspaper"></i>
<span>Berita</span>
</a>
</li>
<li><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/layouts/santri-wali-sidebar.blade.php ENDPATH**/ ?>

View File

@ -0,0 +1,74 @@
<?php $__env->startSection('title', 'Laporan Pembayaran SPP'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-file-pdf"></i> Laporan Pembayaran SPP</h2>
</div>
<div class="row-cards">
<!-- Laporan Semua Data -->
<div class="card card-primary hover-lift">
<h3>Laporan Semua Data</h3>
<p style="margin: 10px 0; color: var(--text-light);">
Cetak laporan semua pembayaran SPP atau dengan filter tertentu
</p>
<form action="<?php echo e(route('admin.pembayaran-spp.cetak-laporan')); ?>" method="GET" target="_blank">
<div class="form-group">
<label><i class="fas fa-calendar form-icon"></i> Bulan (Opsional)</label>
<select name="bulan" class="form-control">
<option value="">Semua Bulan</option>
<?php for($i = 1; $i <= 12; $i++): ?>
<option value="<?php echo e($i); ?>"><?php echo e(DateTime::createFromFormat('!m', $i)->format('F')); ?></option>
<?php endfor; ?>
</select>
</div>
<div class="form-group">
<label><i class="fas fa-calendar-alt form-icon"></i> Tahun (Opsional)</label>
<select name="tahun" class="form-control">
<option value="">Semua Tahun</option>
<?php for($year = date('Y'); $year >= 2020; $year--): ?>
<option value="<?php echo e($year); ?>"><?php echo e($year); ?></option>
<?php endfor; ?>
</select>
</div>
<div class="form-group">
<label><i class="fas fa-info-circle form-icon"></i> Status (Opsional)</label>
<select name="status" class="form-control">
<option value="">Semua Status</option>
<option value="Lunas">Lunas</option>
<option value="Belum Lunas">Belum Lunas</option>
<option value="Telat">Telat</option>
</select>
</div>
<button type="submit" class="btn btn-primary hover-shadow" style="width: 100%;">
<i class="fas fa-print"></i> Cetak Laporan
</button>
</form>
<div class="content-box" style="margin-top: 25px;">
<a href="<?php echo e(route('admin.pembayaran-spp.index')); ?>" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
</div>
<?php $__env->startPush('scripts'); ?>
<script>
// Update form action saat santri dipilih
document.getElementById('select-santri').addEventListener('change', function() {
const form = document.getElementById('form-santri');
const selectedId = this.value;
if (selectedId) {
form.action = "<?php echo e(route('admin.pembayaran-spp.cetak-laporan-santri', ':id')); ?>".replace(':id', selectedId);
}
});
</script>
<?php $__env->stopPush(); ?>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/pembayaran-spp/laporan.blade.php ENDPATH**/ ?>

View File

@ -1,108 +0,0 @@
<?php $__env->startSection('title', 'Berita & Pengumuman'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-newspaper"></i> Berita & Pengumuman</h2>
</div>
<?php if($berita->isEmpty()): ?>
<div class="content-box">
<div class="empty-state">
<i class="fas fa-newspaper" style="color: var(--primary-color); opacity: 0.3;"></i>
<h3>Belum Ada Berita</h3>
<p>Belum ada berita atau pengumuman yang dipublikasikan untuk Anda saat ini.</p>
<a href="<?php echo e(route('santri.dashboard')); ?>" class="btn btn-secondary">
<i class="fas fa-home"></i> Kembali ke Dashboard
</a>
</div>
</div>
<?php else: ?>
<div class="content-box">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px; padding-bottom: 14px; border-bottom: 1px solid #eee; flex-wrap: wrap; gap: 10px;">
<span style="color: var(--text-light); font-size: 0.9em;">
<i class="fas fa-list"></i>
Menampilkan <?php echo e($berita->firstItem()); ?><?php echo e($berita->lastItem()); ?> dari <strong><?php echo e($berita->total()); ?></strong> berita
</span>
<span style="color: var(--text-light); font-size: 0.85em;">
<i class="fas fa-sort-amount-down"></i> Terbaru dahulu
</span>
</div>
<div style="display: flex; flex-direction: column; gap: 14px;">
<?php $__currentLoopData = $berita; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<a href="<?php echo e(route('santri.berita.show', $item->id_berita)); ?>"
style="display: flex; gap: 0; background: white; border: 1px solid #e8eaed;
border-radius: var(--border-radius); text-decoration: none; color: inherit;
overflow: hidden; transition: box-shadow 0.2s, transform 0.2s;"
onmouseover="this.style.boxShadow='0 4px 20px rgba(0,0,0,0.1)'; this.style.transform='translateY(-1px)';"
onmouseout="this.style.boxShadow='none'; this.style.transform='translateY(0)';">
<div style="flex-shrink: 0; width: 130px; min-height: 110px;
background: linear-gradient(135deg, var(--primary-light) 0%, var(--primary-color) 100%);
display: flex; align-items: center; justify-content: center; overflow: hidden;">
<?php if($item->gambar): ?>
<img src="<?php echo e(asset('storage/' . $item->gambar)); ?>"
alt="<?php echo e($item->judul); ?>"
style="width: 100%; height: 100%; object-fit: cover; min-height: 110px;">
<?php else: ?>
<i class="fas fa-newspaper" style="font-size: 2.5em; color: white; opacity: 0.4;"></i>
<?php endif; ?>
</div>
<div style="flex: 1; padding: 14px 18px; display: flex; flex-direction: column; justify-content: space-between; min-width: 0;">
<div>
<h4 style="margin: 0 0 7px; color: var(--primary-color); font-size: 1.05em; line-height: 1.4;
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;">
<?php echo e($item->judul); ?>
</h4>
<p style="margin: 0; color: var(--text-light); font-size: 0.88em; line-height: 1.5;
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;">
<?php echo e(\Illuminate\Support\Str::limit(strip_tags($item->konten), 150)); ?>
</p>
</div>
<div style="display: flex; align-items: center; justify-content: space-between; margin-top: 10px; flex-wrap: wrap; gap: 8px;">
<div style="display: flex; gap: 14px; font-size: 0.82em; color: var(--text-light);">
<span><i class="fas fa-user"></i> <?php echo e($item->penulis); ?></span>
<span><i class="fas fa-calendar"></i> <?php echo e($item->created_at->isoFormat('D MMM YYYY')); ?></span>
</div>
<span class="badge badge-primary" style="font-size: 0.78em;">
<i class="fas fa-arrow-right"></i> Baca
</span>
</div>
</div>
</a>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</div>
<div style="margin-top: 20px; padding-top: 14px; border-top: 1px solid #eee;
display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px;">
<p style="margin: 0; color: var(--text-light); font-size: 0.85em;">
Halaman <?php echo e($berita->currentPage()); ?> dari <?php echo e($berita->lastPage()); ?>
</p>
<?php echo e($berita->links()); ?>
</div>
</div>
<?php endif; ?>
<style>
@media (max-width: 600px) {
a[style*="flex-shrink: 0; width: 130px"] {
flex-direction: column !important;
}
a[style*="flex-shrink: 0; width: 130px"] > div:first-child {
width: 100% !important;
min-height: 160px !important;
}
}
</style>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/santri/berita/index.blade.php ENDPATH**/ ?>

View File

@ -1,173 +0,0 @@

<?php $__env->startSection('title', 'Data Santri'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-users"></i> Data Santri</h2>
</div>
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div>
<?php endif; ?>
<div class="content-box">
<!-- Header Actions -->
<div style="display: flex; justify-content: space-between; align-items: flex-start; gap: 11px; margin-bottom: 14px; flex-wrap: wrap;">
<!-- Tombol Tambah -->
<a href="<?php echo e(route('admin.santri.create')); ?>" class="btn btn-primary btn-sm">
<i class="fas fa-plus"></i> Tambah Santri
</a>
<!-- Form Search & Filter -->
<form action="<?php echo e(route('admin.santri.index')); ?>" method="GET" style="display: flex; gap: 8px; flex-wrap: wrap; align-items: center;">
<input type="text" name="search" class="form-control" placeholder="Cari nama, NIS, atau ID..." value="<?php echo e(request('search')); ?>" style="width: 220px; height: 38px;">
<select name="status" class="form-control" style="width: 150px; height: 38px;">
<option value=""> Semua Status</option>
<option value="Aktif" <?php echo e(request('status') == 'Aktif' ? 'selected' : ''); ?>>Aktif</option>
<option value="Lulus" <?php echo e(request('status') == 'Lulus' ? 'selected' : ''); ?>>Lulus</option>
<option value="Tidak Aktif" <?php echo e(request('status') == 'Tidak Aktif' ? 'selected' : ''); ?>>Tidak Aktif</option>
</select>
<select name="id_kelas" class="form-control" style="width: 180px; height: 38px;">
<option value=""> Semua Kelas</option>
<?php $__currentLoopData = $kelompokKelas; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelompok): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php if($kelompok->kelas && $kelompok->kelas->count() > 0): ?>
<optgroup label="<?php echo e($kelompok->nama_kelompok); ?>">
<?php $__currentLoopData = $kelompok->kelas; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelas): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($kelas->id); ?>" <?php echo e(request('id_kelas') == $kelas->id ? 'selected' : ''); ?>>
<?php echo e($kelas->nama_kelas); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</optgroup>
<?php endif; ?>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
<button type="submit" class="btn btn-primary btn-sm" style="height: 38px; padding: 0 16px;">
<i class="fas fa-search"></i> Cari
</button>
<?php if(request('search') || request('status') || request('id_kelas')): ?>
<a href="<?php echo e(route('admin.santri.index')); ?>" class="btn btn-secondary btn-sm" style="height: 38px; padding: 0 16px; display: inline-flex; align-items: center;">
<i class="fas fa-redo"></i> Reset
</a>
<?php endif; ?>
</form>
</div>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>No</th>
<th>Foto</th>
<th>ID Santri</th>
<th>NIS</th>
<th>Nama Lengkap</th>
<th>Jenis Kelamin</th>
<th>Status</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<?php $__empty_1 = true; $__currentLoopData = $santris; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $santri): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
<tr>
<td><?php echo e($santris->firstItem() + $index); ?></td>
<td>
<?php if($santri->foto): ?>
<img src="<?php echo e(asset('storage/' . $santri->foto)); ?>"
alt="Foto <?php echo e($santri->nama_lengkap); ?>"
style="width: 40px; height: 40px; border-radius: 50%; object-fit: cover; border: 2px solid var(--primary-color);"
loading="lazy">
<?php else: ?>
<div class="santri-avatar-initial" style="width: 40px; height: 40px; border-radius: 50%; background: var(--primary-color); display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; font-size: 0.9rem;">
<?php echo e(strtoupper(substr($santri->nama_lengkap, 0, 1))); ?>
</div>
<?php endif; ?>
</td>
<td><strong><?php echo e($santri->id_santri); ?></strong></td>
<td><?php echo e($santri->nis ?? '-'); ?></td>
<td><?php echo e($santri->nama_lengkap); ?></td>
<td><?php echo e($santri->jenis_kelamin); ?></td>
<td>
<?php if($santri->status == 'Aktif'): ?>
<span style="padding: 6px 12px; border-radius: 6px; font-size: 0.85rem; font-weight: 600; background: linear-gradient(135deg, #E8F7F2 0%, #D4F1E3 100%); color: #2C5F4F; display: inline-block;">
<i class="fas fa-check-circle"></i> <?php echo e($santri->status); ?>
</span>
<?php elseif($santri->status == 'Lulus'): ?>
<span style="padding: 6px 12px; border-radius: 6px; font-size: 0.85rem; font-weight: 600; background: linear-gradient(135deg, #E3F2FD 0%, #D1E9F9 100%); color: #2D4A7C; display: inline-block;">
<i class="fas fa-graduation-cap"></i> <?php echo e($santri->status); ?>
</span>
<?php else: ?>
<span style="padding: 6px 12px; border-radius: 6px; font-size: 0.85rem; font-weight: 600; background: linear-gradient(135deg, #E8ECF0 0%, #D1D8E0 100%); color: #555; display: inline-block;">
<i class="fas fa-times-circle"></i> <?php echo e($santri->status); ?>
</span>
<?php endif; ?>
</td>
<td>
<a href="<?php echo e(route('admin.santri.show', $santri)); ?>" class="btn btn-sm btn-primary">
<i class="fas fa-eye"></i></a>
<a href="<?php echo e(route('admin.santri.edit', $santri)); ?>" class="btn btn-sm btn-warning">
<i class="fas fa-edit"></i></a>
<form action="<?php echo e(route('admin.santri.destroy', $santri)); ?>" method="POST" style="display:inline;">
<?php echo csrf_field(); ?>
<?php echo method_field('DELETE'); ?>
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Yakin ingin menghapus data santri <?php echo e($santri->nama_lengkap); ?>?')">
<i class="fas fa-trash"></i>
</button>
</form>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
<tr>
<td colspan="8" class="text-center" style="padding: 22px;">
<i class="fas fa-inbox" style="font-size: 2.2rem; color: #ccc; margin-bottom: 15px; display: block;"></i>
<?php if(request('search') || request('status') || request('id_kelas')): ?>
<strong>Data tidak ditemukan.</strong><br>
<small>Coba ubah kata kunci pencarian atau filter yang digunakan.</small>
<?php else: ?>
<strong>Belum ada data santri.</strong><br>
<small>Klik tombol "Tambah Santri" untuk menambahkan data baru.</small>
<?php endif; ?>
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
<?php if($santris->count() > 0): ?>
<div style="margin-top: 14px; padding-top: 20px; border-top: 1px solid #E8F7F2;">
<p style="color: #7F8C8D; font-size: 0.9rem;">
<i class="fas fa-info-circle"></i>
Menampilkan <strong><?php echo e($santris->count()); ?></strong> dari <strong><?php echo e($santris->total()); ?></strong> data santri
<?php if(request('search') || request('status') || request('id_kelas')): ?>
(hasil pencarian/filter)
<?php endif; ?>
</p>
</div>
<?php endif; ?>
<!-- Pagination -->
<?php if(method_exists($santris, 'links')): ?>
<div style="margin-top: 14px;">
<?php echo e($santris->links()); ?>
</div>
<?php endif; ?>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', ['isAdmin' => true], \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/santri/index.blade.php ENDPATH**/ ?>

View File

@ -1,285 +0,0 @@

<?php $__env->startSection('title', 'Data Kesehatan Santri'); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-heartbeat"></i> Data Kesehatan Santri</h2>
</div>
<!-- Flash Messages -->
<?php if(session('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> <?php echo e(session('success')); ?>
</div>
<?php endif; ?>
<?php if(session('error')): ?>
<div class="alert alert-danger">
<i class="fas fa-exclamation-circle"></i> <?php echo e(session('error')); ?>
</div>
<?php endif; ?>
<!-- Content Box -->
<div class="content-box">
<!-- Header Actions -->
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; flex-wrap: wrap; gap: 11px;">
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
<a href="<?php echo e(route('admin.kesehatan-santri.create')); ?>" class="btn btn-primary">
<i class="fas fa-plus"></i> Tambah Data Kesehatan
</a>
</div>
</div>
<!-- Filter Section -->
<form method="GET" action="<?php echo e(route('admin.kesehatan-santri.index')); ?>" id="filterForm" style="margin-bottom: 14px;">
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 11px; align-items: end;">
<div class="form-group" style="margin-bottom: 0;">
<input type="text"
name="search"
class="form-control"
placeholder="Nama santri, keluhan..."
value="<?php echo e(request('search')); ?>"
id="searchInput">
</div>
<div class="form-group" style="margin-bottom: 0;">
<select name="status" class="form-control" onchange="document.getElementById('filterForm').submit();">
<option value="">Semua Status</option>
<?php $__currentLoopData = $statusOptions; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $status): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($status); ?>" <?php echo e(request('status') == $status ? 'selected' : ''); ?>>
<?php echo e(ucfirst($status)); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div class="form-group" style="margin-bottom: 0;">
<select name="month" class="form-control" onchange="document.getElementById('filterForm').submit();">
<option value="">Semua Bulan</option>
<?php $__currentLoopData = $monthOptions; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $num => $name): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($num); ?>" <?php echo e(request('month') == $num ? 'selected' : ''); ?>>
<?php echo e($name); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div class="form-group" style="margin-bottom: 0;">
<select name="year" class="form-control" onchange="document.getElementById('filterForm').submit();">
<option value="">Semua Tahun</option>
<?php $__currentLoopData = $yearOptions; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $year): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($year); ?>" <?php echo e((request('year') ?: date('Y')) == $year ? 'selected' : ''); ?>>
<?php echo e($year); ?>
</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div style="display: flex; gap: 10px;">
<button type="submit" class="btn btn-primary">
<i class="fas fa-search"></i> Filter
</button>
<a href="<?php echo e(route('admin.kesehatan-santri.index')); ?>" class="btn btn-secondary">
<i class="fas fa-redo"></i> Reset
</a>
</div>
</div>
</form>
</div>
<!-- Data Table -->
<?php if($kesehatanSantri->count() > 0): ?>
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th style="width: 5%;">No</th>
<th style="width: 9%;">ID Santri</th>
<th style="width: 15%;">Nama Santri</th>
<th style="width: 10%;">Tgl Masuk</th>
<th style="width: 18%;">Keluhan</th>
<th style="width: 10%;">Tgl Keluar</th>
<th style="width: 8%;">Status</th>
<th style="width: 5%;">Lama</th>
<th style="width: 20%;">Aksi</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $kesehatanSantri; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $index => $data): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<tr>
<td class="text-center"><?php echo e($kesehatanSantri->firstItem() + $index); ?></td>
<td><strong><?php echo e($data->id_santri); ?></strong></td>
<td>
<strong><?php echo e($data->santri->nama_lengkap); ?></strong><br>
<small style="color: #7F8C8D;"><?php echo e($data->santri->kelas); ?></small>
</td>
<td><?php echo e($data->tanggal_masuk_formatted); ?></td>
<td>
<span title="<?php echo e($data->keluhan); ?>">
<?php echo e(Str::limit($data->keluhan, 50)); ?>
</span>
</td>
<td>
<?php if($data->tanggal_keluar): ?>
<?php echo e($data->tanggal_keluar_formatted); ?>
<?php else: ?>
<span style="color: #E74C3C; font-weight: bold;">Belum keluar</span>
<?php endif; ?>
</td>
<td class="text-center">
<span class="btn btn-<?php echo e($data->status_badge_color); ?> btn-sm"
style="cursor: default; padding: 5px 10px;">
<?php echo e(ucfirst($data->status)); ?>
</span>
</td>
<td class="text-center"><strong><?php echo e($data->lama_dirawat); ?></strong> hari</td>
<td>
<div style="display: flex; gap: 5px; flex-wrap: wrap;">
<a href="<?php echo e(route('admin.kesehatan-santri.show', $data)); ?>"
class="btn btn-primary btn-sm"
title="Detail">
<i class="fas fa-eye"></i>
</a>
<a href="<?php echo e(route('admin.kesehatan-santri.edit', $data)); ?>"
class="btn btn-warning btn-sm"
title="Edit">
<i class="fas fa-edit"></i>
</a>
<?php if($data->status == 'dirawat'): ?>
<button type="button"
class="btn btn-success btn-sm"
title="Keluar UKP"
onclick="keluarUkp(<?php echo e($data->id); ?>, '<?php echo e($data->santri->nama_lengkap); ?>', '<?php echo e($data->tanggal_masuk->format('Y-m-d')); ?>')">
<i class="fas fa-sign-out-alt"></i>
</button>
<?php endif; ?>
<a href="<?php echo e(route('admin.kesehatan-santri.cetak-surat', $data)); ?>"
class="btn btn-secondary btn-sm"
title="Cetak Surat"
target="_blank">
<i class="fas fa-print"></i>
</a>
<form action="<?php echo e(route('admin.kesehatan-santri.destroy', $data)); ?>"
method="POST"
style="display: inline;"
onsubmit="return confirm('Yakin ingin menghapus data ini?')">
<?php echo csrf_field(); ?>
<?php echo method_field('DELETE'); ?>
<button type="submit"
class="btn btn-danger btn-sm"
title="Hapus">
<i class="fas fa-trash"></i>
</button>
</form>
</div>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
<!-- Pagination -->
<div style="margin-top: 14px; display: flex; justify-content: center;">
<?php echo e($kesehatanSantri->appends(request()->query())->links()); ?>
</div>
<?php else: ?>
<div style="text-align: center; padding: 36px; color: #7F8C8D;">
<i class="fas fa-search" style="font-size: 3em; margin-bottom: 15px; color: #BDC3C7;"></i>
<h3>Tidak ada data kesehatan santri</h3>
<p>Belum ada data kesehatan santri yang tercatat atau sesuai dengan filter yang dipilih.</p>
<a href="<?php echo e(route('admin.kesehatan-santri.create')); ?>" class="btn btn-primary" style="margin-top: 15px;">
<i class="fas fa-plus"></i> Tambah Data Kesehatan
</a>
</div>
<?php endif; ?>
</div>
<!-- Modal Keluar UKP -->
<div id="keluarUkpModal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); z-index: 1000;">
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 22px; border-radius: 12px; min-width: 300px; max-width: 90%; box-shadow: 0 10px 25px rgba(0,0,0,0.2);">
<h3 style="margin-bottom: 14px; color: var(--primary-color);">
<i class="fas fa-sign-out-alt"></i> Keluar dari UKP
</h3>
<form id="keluarUkpForm" method="POST">
<?php echo csrf_field(); ?>
<?php echo method_field('PATCH'); ?>
<div class="form-group">
<label><i class="fas fa-user form-icon"></i>Nama Santri</label>
<input type="text" id="modalNamaSantri" readonly class="form-control" style="background-color: #F8F9FA;">
</div>
<div class="form-group">
<label for="tanggal_keluar"><i class="fas fa-calendar form-icon"></i>Tanggal Keluar *</label>
<input type="date" name="tanggal_keluar" id="tanggal_keluar" class="form-control" required>
</div>
<div class="form-group">
<label for="status_keluar"><i class="fas fa-check-circle form-icon"></i>Status *</label>
<select name="status" id="status_keluar" class="form-control" required>
<option value="">Pilih Status</option>
<option value="sembuh">Sembuh</option>
<option value="izin">Izin Pulang</option>
</select>
</div>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;">
<button type="button" class="btn btn-secondary" onclick="closeKeluarUkpModal()">
<i class="fas fa-times"></i> Batal
</button>
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i> Simpan
</button>
</div>
</form>
</div>
</div>
<script>
function keluarUkp(id, namaSantri, tanggalMasuk) {
document.getElementById('modalNamaSantri').value = namaSantri;
document.getElementById('keluarUkpForm').action = `/admin/kesehatan-santri/${id}/keluar-ukp`;
document.getElementById('tanggal_keluar').value = new Date().toISOString().split('T')[0];
document.getElementById('tanggal_keluar').min = tanggalMasuk;
document.getElementById('tanggal_keluar').max = new Date().toISOString().split('T')[0];
document.getElementById('keluarUkpModal').style.display = 'block';
}
function closeKeluarUkpModal() {
document.getElementById('keluarUkpModal').style.display = 'none';
}
// Close modal when clicking outside
document.getElementById('keluarUkpModal').addEventListener('click', function(e) {
if (e.target === this) {
closeKeluarUkpModal();
}
});
// Close modal with Escape key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeKeluarUkpModal();
}
});
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kesehatan-santri/index.blade.php ENDPATH**/ ?>

View File

@ -1,50 +0,0 @@
<?php $__env->startSection('title', 'Edit Santri: ' . $santri->nama_lengkap); ?>
<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-user-edit"></i> Edit Data Santri</h2>
</div>
<div class="content-box">
<?php if($errors->any()): ?>
<div class="alert alert-danger">
<strong><i class="fas fa-exclamation-triangle"></i> Terdapat kesalahan:</strong>
<ul style="margin: 10px 0 0 20px;">
<?php $__currentLoopData = $errors->all(); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $error): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<li><?php echo e($error); ?></li>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</ul>
</div>
<?php endif; ?>
<div style="background: linear-gradient(135deg, #E3F2FD 0%, #D1E9F9 100%); padding: 14px; border-radius: 8px; border-left: 4px solid #81C6E8; margin-bottom: 25px;">
<div style="display: flex; align-items: center; gap: 11px;">
<?php if($santri->foto): ?>
<img src="<?php echo e(asset('storage/' . $santri->foto)); ?>"
alt="Foto <?php echo e($santri->nama_lengkap); ?>"
style="width: 60px; height: 60px; border-radius: 50%; object-fit: cover; border: 3px solid #81C6E8;"
loading="lazy">
<?php else: ?>
<div style="width: 60px; height: 60px; border-radius: 50%; background: #81C6E8; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; font-size: 1.5rem;">
<?php echo e(strtoupper(substr($santri->nama_lengkap, 0, 1))); ?>
</div>
<?php endif; ?>
<div>
<p style="margin: 0; color: #2D4A7C; font-size: 0.9rem;">
<i class="fas fa-info-circle"></i>
<strong>Sedang mengedit data:</strong>
</p>
<p style="margin: 5px 0 0 0; color: #2D4A7C; font-weight: 600; font-size: 1.1rem;">
<?php echo e($santri->nama_lengkap); ?> (<?php echo e($santri->id_santri); ?>)
</p>
</div>
</div>
</div>
<?php echo $__env->make('admin.santri.form', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>
</div>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', ['isAdmin' => true], \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/santri/edit.blade.php ENDPATH**/ ?>

View File

@ -1,465 +0,0 @@

<?php $__env->startSection('content'); ?>
<div class="page-header">
<h2><i class="fas fa-clipboard-check"></i> Input Absensi: <?php echo e($kegiatan->nama_kegiatan); ?></h2>
</div>
<div class="content-box" style="margin-bottom: 14px;">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 11px;">
<div>
<h3 style="margin: 0; color: var(--primary-color);"><?php echo e($kegiatan->nama_kegiatan); ?></h3>
<p style="margin: 5px 0 0 0; color: var(--text-light);">
<i class="fas fa-calendar-day"></i> <?php echo e($kegiatan->hari); ?> |
<i class="fas fa-clock"></i> <?php echo e(date('H:i', strtotime($kegiatan->waktu_mulai))); ?> - <?php echo e(date('H:i', strtotime($kegiatan->waktu_selesai))); ?> |
<i class="fas fa-list-alt"></i> <?php echo e($kegiatan->kategori->nama_kategori); ?>
</p>
</div>
<div style="display: flex; gap: 10px;">
<button type="button" id="btnModeManual" class="btn btn-primary" onclick="setMode('manual')">
<i class="fas fa-hand-pointer"></i> Mode Manual
</button>
<button type="button" id="btnModeRfid" class="btn btn-secondary" onclick="setMode('rfid')">
<i class="fas fa-id-card"></i> Mode RFID
</button>
</div>
</div>
</div>
<div class="info-box" style="margin-bottom: 14px; border-left: 4px solid var(--primary-color);">
<i class="fas fa-info-circle"></i>
<?php if($kegiatanInfo['is_umum']): ?>
<strong>Kegiatan Umum</strong> - Diikuti oleh semua santri aktif (<?php echo e($santris->count()); ?> santri)
<?php else: ?>
<strong>Kegiatan Khusus</strong> - Untuk kelas:
<strong style="color: var(--primary-color);"><?php echo e($kegiatanInfo['kelas_list']); ?></strong>
(<?php echo e($kegiatanInfo['jumlah_kelas']); ?> kelas)
&nbsp;|&nbsp; Total semua santri aktif: <strong><?php echo e($santris->count()); ?> santri</strong>
<?php endif; ?>
</div>
<?php
$sudahAdaData = count($absensiData) > 0;
?>
<?php if($sudahAdaData): ?>
<div class="alert alert-info" style="margin-bottom: 14px;">
<i class="fas fa-edit"></i>
<strong>Mode Edit</strong> - Data absensi untuk tanggal ini sudah ada
(<strong><?php echo e(count($absensiData)); ?></strong> dari <strong><?php echo e($santris->count()); ?></strong> santri sudah diinput,
<strong style="color: <?php echo e(($santris->count() - count($absensiData)) > 0 ? '#dc2626' : '#059669'); ?>;"><?php echo e($santris->count() - count($absensiData)); ?> belum absen</strong>).
Anda dapat mengubah status absensi lalu klik Simpan.
</div>
<?php endif; ?>
<!-- MODE MANUAL -->
<div id="modeManual" class="content-box">
<form action="<?php echo e(route('admin.absensi-kegiatan.simpan')); ?>" method="POST">
<?php echo csrf_field(); ?>
<input type="hidden" name="kegiatan_id" value="<?php echo e($kegiatan->kegiatan_id); ?>">
<div class="filter-form-inline" style="margin-bottom: 14px; gap: 12px;">
<div class="filter-form-inline" style="gap: 8px;">
<label style="font-weight: 600; white-space: nowrap; margin: 0;">
<i class="fas fa-calendar"></i> Tanggal:
</label>
<input type="date" name="tanggal" id="tanggal" class="form-control"
value="<?php echo e($tanggal); ?>" required style="max-width: 170px;">
</div>
<div class="filter-form-inline" style="gap: 8px;">
<label style="font-weight: 600; white-space: nowrap; margin: 0;">
<i class="fas fa-school"></i> Pilih Kelas:
</label>
<select id="kelasFilter" class="form-control" onchange="filterKelas(this.value)" style="max-width: 220px;">
<option value="semua">-- Tampilkan Semua Kelas --</option>
<?php $__currentLoopData = $santriGrouped; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelasNama => $santriKelas): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<option value="<?php echo e($kelasNama); ?>"><?php echo e($kelasNama); ?> (<?php echo e($santriKelas->count()); ?> santri)</option>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</select>
</div>
<div style="margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap;">
<button type="button" class="btn btn-sm btn-info" onclick="setAllStatus('Hadir')">
<i class="fas fa-check-double"></i> Semua Hadir
</button>
<button type="button" class="btn btn-sm" style="background: #FF9800; color: white;" onclick="setAllStatus('Terlambat')">
<i class="fas fa-clock"></i> Semua Terlambat
</button>
<button type="button" class="btn btn-sm btn-danger" onclick="setAllStatus('Alpa')">
<i class="fas fa-times"></i> Semua Alpa
</button>
<button type="button" class="btn btn-sm btn-secondary" onclick="clearAllStatus()">
<i class="fas fa-eraser"></i> Kosongkan
</button>
</div>
</div>
<div class="info-box" style="margin-bottom: 14px;">
<p style="margin: 0;"><i class="fas fa-info-circle"></i> Pilih kelas terlebih dahulu untuk menampilkan daftar santri. Santri tanpa pilihan status akan <strong>dilewati</strong>. Santri yang <strong>sedang pulang</strong> otomatis ditandai.</p>
</div>
<?php $__currentLoopData = $santriGrouped; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kelasNama => $santriKelas): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$hadirCount = 0;
$totalKelas = $santriKelas->count();
foreach ($santriKelas as $s) {
$st = $absensiData[$s->id_santri] ?? null;
if ($st === 'Hadir') $hadirCount++;
}
$sudahInputKelas = false;
foreach ($santriKelas as $s) {
if (isset($absensiData[$s->id_santri])) { $sudahInputKelas = true; break; }
}
?>
<div class="kelas-group" data-kelas="<?php echo e($kelasNama); ?>" style="margin-bottom: 20px; display: none;">
<div style="background: var(--primary-light); padding: 10px 14px; border-radius: 8px 8px 0 0; display: flex; justify-content: space-between; align-items: center;">
<h4 style="margin: 0; color: var(--primary-color); font-size: 0.95rem;">
<i class="fas fa-users"></i> <?php echo e($kelasNama); ?>
</h4>
<div style="display: flex; gap: 8px; align-items: center;">
<?php if($sudahInputKelas): ?>
<span class="badge badge-info"><i class="fas fa-edit"></i> <?php echo e($hadirCount); ?>/<?php echo e($totalKelas); ?> hadir</span>
<?php endif; ?>
<span class="badge badge-primary"><?php echo e($totalKelas); ?> santri</span>
</div>
</div>
<div class="table-wrapper">
<table class="data-table" style="margin-top: 0; border-top-left-radius: 0; border-top-right-radius: 0;">
<thead>
<tr>
<th style="width: 50px;">No</th>
<th style="width: 100px;">ID Santri</th>
<th>Nama Santri</th>
<th style="width: 420px; text-align: center;">Status</th>
</tr>
</thead>
<tbody>
<?php $__currentLoopData = $santriKelas; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $santri): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
<?php
$isPulang = in_array($santri->id_santri, $santriSedangPulang ?? []);
$currentStatus = $absensiData[$santri->id_santri] ?? ($isPulang ? 'Pulang' : '');
?>
<tr <?php if($isPulang): ?> style="background: #FFF8E1; opacity: 0.85;" <?php endif; ?>>
<td><?php echo e($loop->iteration); ?></td>
<td><strong><?php echo e($santri->id_santri); ?></strong></td>
<td>
<?php echo e($santri->nama_lengkap); ?>
<?php if($isPulang): ?>
<span class="badge" style="background: #FFF3E0; color: #E65100; font-size: 0.75rem; margin-left: 6px;">
<i class="fas fa-home"></i> Sedang Pulang
</span>
<?php endif; ?>
<?php if(isset($absensiData[$santri->id_santri])): ?>
<span class="badge badge-secondary" style="font-size: 0.7rem; margin-left: 4px;">
<i class="fas fa-edit"></i> Sudah input
</span>
<?php endif; ?>
</td>
<td class="text-center">
<?php if($isPulang): ?>
<input type="hidden" name="absensi[<?php echo e($santri->id_santri); ?>]" value="Pulang" class="absensi-input">
<span class="badge" style="background: #FFF3E0; color: #E65100; padding: 6px 14px; font-size: 0.85rem;">
<i class="fas fa-home"></i> Pulang
</span>
<?php else: ?>
<div style="display: flex; gap: 5px; justify-content: center; flex-wrap: wrap;">
<label style="margin: 0; cursor: pointer;">
<input type="radio" name="absensi[<?php echo e($santri->id_santri); ?>]" value="Hadir"
<?php echo e($currentStatus == 'Hadir' ? 'checked' : ''); ?> class="absensi-radio absensi-input">
<span class="badge badge-success">Hadir</span>
</label>
<label style="margin: 0; cursor: pointer;">
<input type="radio" name="absensi[<?php echo e($santri->id_santri); ?>]" value="Terlambat"
<?php echo e($currentStatus == 'Terlambat' ? 'checked' : ''); ?> class="absensi-radio absensi-input">
<span class="badge" style="background: #FF9800; color: white;">Terlambat</span>
</label>
<label style="margin: 0; cursor: pointer;">
<input type="radio" name="absensi[<?php echo e($santri->id_santri); ?>]" value="Izin"
<?php echo e($currentStatus == 'Izin' ? 'checked' : ''); ?> class="absensi-radio absensi-input">
<span class="badge badge-warning">Izin</span>
</label>
<label style="margin: 0; cursor: pointer;">
<input type="radio" name="absensi[<?php echo e($santri->id_santri); ?>]" value="Sakit"
<?php echo e($currentStatus == 'Sakit' ? 'checked' : ''); ?> class="absensi-radio absensi-input">
<span class="badge badge-info">Sakit</span>
</label>
<label style="margin: 0; cursor: pointer;">
<input type="radio" name="absensi[<?php echo e($santri->id_santri); ?>]" value="Alpa"
<?php echo e($currentStatus == 'Alpa' ? 'checked' : ''); ?> class="absensi-radio absensi-input">
<span class="badge badge-danger">Alpa</span>
</label>
<?php if($currentStatus): ?>
<label style="margin: 0; cursor: pointer;" title="Hapus pilihan">
<button type="button" class="btn btn-sm" style="padding: 2px 8px; font-size: 0.75rem; background: #f1f1f1;" onclick="clearRadio('<?php echo e($santri->id_santri); ?>')">
<i class="fas fa-undo"></i>
</button>
</label>
<?php endif; ?>
</div>
<?php endif; ?>
</td>
</tr>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
</tbody>
</table>
</div>
</div>
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
<div id="noKelasSelected" class="empty-state" style="padding: 40px 20px;">
<i class="fas fa-hand-pointer"></i>
<h3>Pilih Kelas Terlebih Dahulu</h3>
<p>Silakan pilih kelas pada dropdown di atas untuk menampilkan daftar santri yang akan diabsen.</p>
</div>
<div class="btn-group" style="margin-top: 14px;">
<button type="submit" class="btn btn-success">
<i class="fas fa-save"></i> <?php echo e($sudahAdaData ? 'Update Absensi' : 'Simpan Absensi'); ?>
</button>
<a href="<?php echo e(route('admin.kegiatan.index')); ?>" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
</form>
</div>
<!-- MODE RFID -->
<div id="modeRfid" class="content-box" style="display: none;">
<div class="form-group">
<label for="tanggalRfid">
<i class="fas fa-calendar form-icon"></i>
Tanggal Absensi
</label>
<input type="date" id="tanggalRfid" class="form-control" value="<?php echo e($tanggal); ?>">
</div>
<div class="info-box">
<p><i class="fas fa-id-card"></i> Tempelkan kartu RFID santri ke reader. Absensi akan otomatis tersimpan sebagai <strong>Hadir</strong>.</p>
</div>
<div style="background: linear-gradient(135deg, var(--primary-light) 0%, #D4F1E3 100%); padding: 22px; border-radius: var(--border-radius); text-align: center; margin-bottom: 14px;">
<div id="rfidStatus" style="font-size: 1.5rem; font-weight: 600; color: var(--primary-color); margin-bottom: 15px;">
<i class="fas fa-wifi"></i> Siap Scan RFID
</div>
<input type="text" id="rfidInput" placeholder="Fokus di sini untuk scan RFID..."
style="width: 100%; padding: 15px; font-size: 1.2rem; border: 3px solid var(--primary-color); border-radius: var(--border-radius-sm); text-align: center;"
autofocus>
</div>
<div id="rfidLog" style="max-height: 400px; overflow-y: auto; background: white; border-radius: var(--border-radius-sm); padding: 15px; border: 1px solid var(--primary-light);">
<h4 style="margin: 0 0 15px 0; color: var(--primary-color);"><i class="fas fa-history"></i> Log Absensi</h4>
<div id="rfidLogContent">
<p style="text-align: center; color: var(--text-light);">Belum ada absensi...</p>
</div>
</div>
<div class="btn-group" style="margin-top: 14px;">
<button type="button" class="btn btn-warning" onclick="clearLog()">
<i class="fas fa-trash"></i> Bersihkan Log
</button>
<a href="<?php echo e(route('admin.kegiatan.index')); ?>" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Kembali
</a>
</div>
</div>
<script>
// -- Kelas Filter --
function filterKelas(value) {
var groups = document.querySelectorAll('.kelas-group');
var emptyMsg = document.getElementById('noKelasSelected');
if (value === 'semua') {
for (var i = 0; i < groups.length; i++) {
groups[i].style.display = 'block';
toggleGroupInputs(groups[i], true);
}
emptyMsg.style.display = 'none';
} else {
var found = false;
for (var i = 0; i < groups.length; i++) {
if (groups[i].getAttribute('data-kelas') === value) {
groups[i].style.display = 'block';
toggleGroupInputs(groups[i], true);
found = true;
} else {
groups[i].style.display = 'none';
toggleGroupInputs(groups[i], false);
}
}
emptyMsg.style.display = found ? 'none' : 'block';
}
}
// Enable/disable all inputs in a kelas group so hidden groups don't submit
function toggleGroupInputs(group, enabled) {
var inputs = group.querySelectorAll('.absensi-input');
for (var i = 0; i < inputs.length; i++) {
inputs[i].disabled = !enabled;
}
}
// -- Set All Status (for visible groups only) --
function setAllStatus(status) {
var groups = document.querySelectorAll('.kelas-group');
for (var i = 0; i < groups.length; i++) {
if (groups[i].style.display !== 'none') {
var radios = groups[i].querySelectorAll('input.absensi-radio[value="' + status + '"]');
for (var j = 0; j < radios.length; j++) {
radios[j].checked = true;
}
}
}
}
// -- Clear radio selection for a specific santri --
function clearRadio(santriId) {
var radios = document.querySelectorAll('input[name="absensi[' + santriId + ']"]');
for (var i = 0; i < radios.length; i++) {
radios[i].checked = false;
}
}
// -- Clear all selections in visible groups --
function clearAllStatus() {
var groups = document.querySelectorAll('.kelas-group');
for (var i = 0; i < groups.length; i++) {
if (groups[i].style.display !== 'none') {
var radios = groups[i].querySelectorAll('input.absensi-radio');
for (var j = 0; j < radios.length; j++) {
radios[j].checked = false;
}
}
}
}
// -- Mode Switch --
var currentMode = 'manual';
var kegiatanId = '<?php echo e($kegiatan->kegiatan_id); ?>';
function setMode(mode) {
currentMode = mode;
var modeManualEl = document.getElementById('modeManual');
var modeRfidEl = document.getElementById('modeRfid');
var btnManual = document.getElementById('btnModeManual');
var btnRfid = document.getElementById('btnModeRfid');
if (mode === 'manual') {
modeManualEl.style.display = 'block';
modeRfidEl.style.display = 'none';
btnManual.className = 'btn btn-primary';
btnRfid.className = 'btn btn-secondary';
} else {
modeManualEl.style.display = 'none';
modeRfidEl.style.display = 'block';
btnManual.className = 'btn btn-secondary';
btnRfid.className = 'btn btn-success';
document.getElementById('rfidInput').focus();
}
}
// -- RFID Scanner --
document.getElementById('rfidInput').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
e.preventDefault();
var rfidUid = this.value.trim();
if (rfidUid) {
scanRfid(rfidUid);
this.value = '';
}
}
});
function scanRfid(rfidUid) {
var tanggal = document.getElementById('tanggalRfid').value;
var statusEl = document.getElementById('rfidStatus');
statusEl.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Memproses...';
statusEl.style.color = 'var(--warning-color)';
fetch('<?php echo e(route("admin.absensi-kegiatan.scan-rfid")); ?>', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '<?php echo e(csrf_token()); ?>'
},
body: JSON.stringify({
rfid_uid: rfidUid,
kegiatan_id: kegiatanId,
tanggal: tanggal
})
})
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.success) {
statusEl.innerHTML = '<i class="fas fa-check-circle"></i> ' + data.message;
statusEl.style.color = 'var(--success-color)';
addLogEntry(data.data, 'success');
} else {
statusEl.innerHTML = '<i class="fas fa-exclamation-circle"></i> ' + data.message;
statusEl.style.color = 'var(--danger-color)';
}
setTimeout(function() {
statusEl.innerHTML = '<i class="fas fa-wifi"></i> Siap Scan RFID';
statusEl.style.color = 'var(--primary-color)';
}, 2000);
})
.catch(function(error) {
statusEl.innerHTML = '<i class="fas fa-times-circle"></i> Koneksi error';
statusEl.style.color = 'var(--danger-color)';
console.error('Error:', error);
setTimeout(function() {
statusEl.innerHTML = '<i class="fas fa-wifi"></i> Siap Scan RFID';
statusEl.style.color = 'var(--primary-color)';
}, 2000);
});
}
function addLogEntry(data, type) {
var logContent = document.getElementById('rfidLogContent');
if (logContent.querySelector('p')) {
logContent.innerHTML = '';
}
var entry = document.createElement('div');
entry.style.cssText = 'padding: 12px; margin-bottom: 10px; border-radius: 8px; background: ' +
(type === 'success' ? 'linear-gradient(135deg, #E8F7F2 0%, #D4F1E3 100%)' : 'linear-gradient(135deg, #FFE8EA 0%, #FFD5D8 100%)') +
'; border-left: 4px solid ' + (type === 'success' ? 'var(--success-color)' : 'var(--danger-color)');
entry.innerHTML = '<div style="display: flex; justify-content: space-between; align-items: center;">' +
'<div><strong>' + data.nama + '</strong> (' + data.id_santri + ')' +
'<div style="font-size: 0.85rem; color: var(--text-light); margin-top: 3px;">Kelas: ' + data.kelas + ' | Waktu: ' + data.waktu + '</div></div>' +
'<span class="badge badge-success"><i class="fas fa-check"></i> Hadir</span></div>';
logContent.insertBefore(entry, logContent.firstChild);
}
function clearLog() {
if (confirm('Yakin ingin membersihkan log?')) {
document.getElementById('rfidLogContent').innerHTML = '<p style="text-align: center; color: var(--text-light);">Belum ada absensi...</p>';
}
}
// -- Auto-focus RFID input --
setInterval(function() {
if (currentMode === 'rfid') {
var rfidInput = document.getElementById('rfidInput');
if (document.activeElement !== rfidInput) {
rfidInput.focus();
}
}
}, 1000);
</script>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH C:\xampp\htdocs\TugasAkhir\sim-pkpps\resources\views/admin/kegiatan/absensi/input.blade.php ENDPATH**/ ?>

Some files were not shown because too many files have changed in this diff Show More