MIF_E31230892/sim-pkpps/resources/views/santri/kegiatan/show.blade.php

815 lines
35 KiB
PHP
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@extends('layouts.app')
@section('title', 'Detail: ' . $kegiatan->nama_kegiatan)
@section('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>
{{-- ── NAVIGASI KEMBALI ── --}}
<div class="sd-nav">
<a href="{{ route('santri.kegiatan.index') }}?tab={{ $fromTab ?? 'jadwal' }}">
<i class="fas fa-arrow-left"></i> Kembali ke Jadwal
</a>
<span class="sd-nav-sep"></span>
<span class="sd-nav-cur">{{ $kegiatan->nama_kegiatan }}</span>
</div>
{{-- ── HERO Info Kegiatan + Ringkasan ── --}}
<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>
{{ $kegiatan->nama_kegiatan }}
</h1>
<div class="sd-hero-chips">
<span class="sd-chip"><i class="fas fa-tag"></i> {{ $kegiatan->kategori->nama_kategori }}</span>
<span class="sd-chip"><i class="fas fa-calendar-day"></i> Setiap {{ $kegiatan->hari }}</span>
<span class="sd-chip">
<i class="fas fa-clock"></i>
{{ date('H:i', strtotime($kegiatan->waktu_mulai)) }} {{ date('H:i', strtotime($kegiatan->waktu_selesai)) }}
</span>
@if($kegiatan->materi)
<span class="sd-chip"><i class="fas fa-book-open"></i> {{ Str::limit($kegiatan->materi, 35) }}</span>
@endif
</div>
{{-- 3 angka paling penting --}}
<div class="sd-hero-kpi">
<div class="sd-hkpi">
@php
$clr = $persentaseHadir >= 85 ? 'clr-great' : ($persentaseHadir >= 70 ? 'clr-ok' : 'clr-bad');
@endphp
<div class="sd-hkpi-val {{ $clr }}">{{ $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">{{ $hadirEfektif }}</div>
<div class="sd-hkpi-lbl">Kali Hadir</div>
<div class="sd-hkpi-sub">dari {{ $totalAbsensi }} tercatat</div>
</div>
<div class="sd-hkpi">
<div class="sd-hkpi-val {{ ($stats['Alpa'] ?? 0) > 0 ? 'clr-bad' : 'clr-great' }}">
{{ $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>
{{-- ── FILTER PERIODE ── --}}
<form method="GET" action="{{ route('santri.kegiatan.show', $kegiatan->kegiatan_id) }}" id="filterForm">
<input type="hidden" name="from_tab" value="{{ $fromTab ?? 'jadwal' }}">
<input type="hidden" name="preset" id="hPreset" value="{{ $preset }}">
<input type="hidden" name="date_from" id="hDateFrom" value="{{ request('date_from') }}">
<input type="hidden" name="date_to" id="hDateTo" value="{{ 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">
@foreach([
'this_week' => 'Minggu Ini',
'this_month' => 'Bulan Ini',
'last_month' => 'Bulan Lalu',
'last_3m' => '3 Bulan',
'all' => 'Semua Data',
] as $v => $l)
<button type="button"
class="sd-pbtn {{ $preset === $v ? 'active' : '' }}"
onclick="setPreset('{{ $v }}')">{{ $l }}</button>
@endforeach
</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="{{ $dateFrom->format('Y-m-d') }}" onchange="setCustom()">
<span></span>
<input type="date" id="inpTo" value="{{ $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>
{{ $dateFrom->locale('id')->isoFormat('D MMM YYYY') }}
{{ $dateTo->locale('id')->isoFormat('D MMM YYYY') }}
</div>
</div>
</form>
{{-- ── 6 STAT PILLS ── --}}
<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'],
];
@endphp
@foreach($pillData as $p)
<div class="sd-pill-card {{ $p['cls'] }}">
<div class="sd-pill-icon"><i class="fas fa-{{ $p['icon'] }}"></i></div>
<div class="sd-pill-val">{{ $p['val'] }}</div>
<div class="sd-pill-lbl">{{ $p['label'] }}</div>
</div>
@endforeach
</div>
{{-- ── INSIGHT BANNER pesan mudah dipahami santri ── --}}
@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.";
}
@endphp
@if($totalAbsensi > 0)
<div class="sd-insight {{ $insightCls }}">
<div class="sd-insight-ic">{{ $insightIcon }}</div>
<div class="sd-insight-text">
<b>{{ $insightJudul }}</b>
{{ $insightMsg }}
</div>
</div>
@endif
{{-- ── KALENDER VISUAL + DISTRIBUSI ── --}}
@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'];
@endphp
<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>
{{-- Kalender Visual --}}
<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;">
{{ $dateFrom->locale('id')->isoFormat('D MMM') }} {{ $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">
@foreach($statusMeta as $sLabel => $sMeta)
<div class="sd-legend-item">
<div class="sd-legend-dot" style="background:{{ $sMeta['dot'] }};"></div> {{ $sLabel }}
</div>
@endforeach
<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(); @endphp
@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');
@endphp
@if($meta)
<div class="sd-cal-slot {{ $isToday ? 'is-today' : '' }}"
style="background:{{ $meta['bg'] }};border-color:{{ $meta['border'] }};color:{{ $meta['text'] }};"
title="{{ $cursor->locale('id')->isoFormat('dddd, D MMMM YYYY') }} — {{ $status }}">
<span class="sd-cal-slot-icon">{{ $meta['icon'] }}</span>
<span class="sd-cal-slot-date">{{ $tglFmt }}</span>
<span class="sd-cal-slot-day">{{ $hariId }}</span>
<span class="sd-cal-slot-lbl">{{ $status }}</span>
</div>
@else
<div class="sd-cal-slot empty {{ $isToday ? 'is-today' : '' }}"
title="{{ $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;">{{ $tglFmt }}</span>
<span class="sd-cal-slot-day" style="color:#94a3b8;">{{ $hariId }}</span>
<span class="sd-cal-slot-lbl" style="color:#d1d5db;">Belum</span>
</div>
@endif
@php $cursor->addDay(); @endphp
@endwhile
</div>
</div>
{{-- Distribusi Status --}}
<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;">{{ $totalAbsensi }} total sesi tercatat</span>
</div>
@if($totalAbsensi > 0)
<div class="sd-dist2-list">
@foreach($distItems as $d)
@if($d['val'] > 0 || in_array($d['label'], ['Hadir','Alpa']))
<div class="sd-dist2-row">
<div class="sd-dist2-emoji">{{ $d['emoji'] }}</div>
<div class="sd-dist2-lbl">{{ $d['label'] }}</div>
<div class="sd-dist2-track">
<div class="sd-dist2-fill" style="width:{{ round($d['val']/$totalAbsensi*100) }}%;background:{{ $d['color'] }};"></div>
</div>
<div class="sd-dist2-val">{{ $d['val'] }}×</div>
<div class="sd-dist2-pct">{{ round($d['val']/$totalAbsensi*100) }}%</div>
</div>
@endif
@endforeach
</div>
@else
<div class="sd-empty"><i class="fas fa-inbox"></i><p>Belum ada data absensi.</p></div>
@endif
</div>
{{-- ── TABEL RIWAYAT ── --}}
<div class="sd-table-wrap">
{{-- Header tabel --}}
<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>
{{-- Periode aktif jelas terlihat --}}
<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>
{{ $dateFrom->locale('id')->isoFormat('D MMM YYYY') }}
&nbsp;&nbsp;
{{ $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',
];
@endphp
@if(isset($presetLabels[$preset]))
<span style="font-size:0.73rem;color:var(--mu);">
({{ $presetLabels[$preset] }})
</span>
@endif
</div>
<span class="sd-count-badge">{{ $riwayats->total() }} sesi</span>
</div>
{{-- Sub-info: kalimat penjelas --}}
<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);">{{ $riwayats->total() }} catatan absensi</strong>
kegiatan <strong style="color:var(--tx);">{{ $kegiatan->nama_kegiatan }}</strong>
dari tanggal <strong style="color:var(--tx);">{{ $dateFrom->locale('id')->isoFormat('D MMM YYYY') }}</strong>
sampai <strong style="color:var(--tx);">{{ $dateTo->locale('id')->isoFormat('D MMM YYYY') }}</strong>.
@if($riwayats->hasPages())
Halaman {{ $riwayats->currentPage() }} dari {{ $riwayats->lastPage() }}.
@endif
</div>
@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>
@foreach($riwayats as $idx => $absensi)
@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');
@endphp
<tr class="{{ $rowCls }}">
<td style="color:#9ca3af;font-size:0.74rem;text-align:center;">
{{ $riwayats->firstItem() + $idx }}
</td>
<td>
<div class="sd-date-main">
{{ \Carbon\Carbon::parse($absensi->tanggal)->format('d M Y') }}
</div>
<div class="sd-date-day">
{{ \Carbon\Carbon::parse($absensi->tanggal)->locale('id')->isoFormat('dddd') }}
</div>
</td>
<td>
@if($absensi->waktu_absen)
<span style="font-weight:700;color:var(--tx);font-size:0.9rem;">
{{ \Carbon\Carbon::parse($absensi->waktu_absen)->format('H:i') }}
</span>
<span style="font-size:0.7rem;color:var(--mu);display:block;">WIB</span>
@else
<span style="color:#d1d5db;font-size:0.8rem;"></span>
@endif
</td>
<td>
<span class="sd-status {{ $statusLower }}">
@if($absensi->status === 'Hadir') <i class="fas fa-check"></i>
@elseif($absensi->status === 'Terlambat') <i class="fas fa-clock"></i>
@elseif($absensi->status === 'Izin') <i class="fas fa-info"></i>
@elseif($absensi->status === 'Sakit') <i class="fas fa-heartbeat"></i>
@elseif($absensi->status === 'Alpa') <i class="fas fa-times"></i>
@elseif($absensi->status === 'Pulang') <i class="fas fa-home"></i>
@endif
{{ $absensi->status }}
</span>
</td>
<td>
<span class="sd-metode">
<i class="fas fa-{{ $metodeIcon }}"></i> {{ $metodeLabel }}
</span>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="sd-pagination">
{{ $riwayats->appends(request()->query())->links() }}
</div>
@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>{{ $dateFrom->locale('id')->isoFormat('D MMM YYYY') }} {{ $dateTo->locale('id')->isoFormat('D MMM YYYY') }}</strong>.
Coba pilih periode yang lebih luas di filter atas.
</p>
</div>
@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>
@endsection