Files
2026-06-28 15:14:51 +07:00

1441 lines
68 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
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('admin.layouts.app')
@section('content')
<style>
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,400&family=Sora:wght@400;600;700;800&display=swap');
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #f0f4fb;
--bg2: #e4ecf7;
--surface: #ffffff;
--surface2: #f7f9ff;
--surface3: #eef2fb;
--border: #dde5f4;
--border2: #c8d5ee;
--text-primary: #0f1c3d;
--text-secondary: #3d5280;
--text-muted: #7a8fb5;
--text-faint: #b0bfd8;
--blue: #1a4fd6;
--blue-mid: #2563eb;
--blue-light: #3b82f6;
--blue-pale: #dbeafe;
--blue-ultra: #eff6ff;
--indigo: #4338ca;
--indigo-pale: #e0e7ff;
--green: #059669;
--green-mid: #10b981;
--green-pale: #d1fae5;
--green-ultra: #ecfdf5;
--amber: #d97706;
--amber-pale: #fde68a;
--amber-ultra: #fffbeb;
--red: #dc2626;
--red-pale: #fee2e2;
--red-ultra: #fef2f2;
--purple: #7c3aed;
--purple-pale: #ede9fe;
--purple-ultra:#f5f3ff;
--shadow-xs: 0 1px 3px rgba(15,28,61,0.06);
--shadow-sm: 0 2px 8px rgba(15,28,61,0.08);
--shadow: 0 4px 20px rgba(15,28,61,0.10);
--shadow-md: 0 8px 32px rgba(15,28,61,0.12);
--shadow-lg: 0 24px 64px rgba(15,28,61,0.18);
--radius: 16px;
--radius-sm: 10px;
--radius-xs: 8px;
}
.sa-root {
font-family: 'Plus Jakarta Sans', sans-serif;
background: var(--bg);
min-height: 100vh;
color: var(--text-primary);
padding: 2rem;
}
/* ─── PAGE HEADER ─── */
.sa-page-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 1.75rem;
flex-wrap: wrap;
gap: 12px;
}
.sa-page-eyebrow {
display: flex;
align-items: center;
gap: 8px;
font-size: 10.5px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1.8px;
color: var(--blue-mid);
margin-bottom: 7px;
}
.sa-page-eyebrow-line {
width: 24px; height: 2.5px;
background: linear-gradient(90deg, var(--blue-mid), var(--blue-light));
border-radius: 2px;
}
.sa-page-title {
font-family: 'Sora', sans-serif;
font-size: 27px; font-weight: 800;
color: var(--text-primary);
letter-spacing: -0.6px; line-height: 1.15;
}
.sa-page-sub {
font-size: 13px; color: var(--text-muted);
margin-top: 5px; font-weight: 400;
}
.sa-header-right { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.sa-date-chip {
display: flex; align-items: center; gap: 8px;
background: var(--surface); border: 1.5px solid var(--border);
border-radius: 50px; padding: 8px 16px;
font-size: 12px; color: var(--text-secondary);
font-weight: 600; box-shadow: var(--shadow-xs);
}
.sa-superadmin-badge {
display: flex; align-items: center; gap: 7px;
background: linear-gradient(135deg, #fef9c3, #fef3c7);
border: 1.5px solid #f5c842; color: #92400e;
padding: 8px 16px; border-radius: 50px;
font-size: 11px; font-weight: 700;
font-family: 'Sora', sans-serif;
text-transform: uppercase; letter-spacing: 1px;
box-shadow: 0 2px 8px rgba(245,200,66,0.18);
}
.sa-badge-dot {
width: 7px; height: 7px; border-radius: 50%;
background: #f59e0b; box-shadow: 0 0 6px #f59e0b;
animation: blink 2s infinite;
}
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0.35} }
/* ─── ALERTS ─── */
.alert-session {
display: flex; align-items: center; gap: 10px;
padding: 13px 16px; border-radius: var(--radius-sm);
margin-bottom: 1.5rem; font-size: 13px; font-weight: 500;
box-shadow: var(--shadow-xs);
}
.alert-session.success { background:var(--green-ultra); border:1.5px solid var(--green-pale); color:#065f46; }
.alert-session.error { background:var(--red-ultra); border:1.5px solid var(--red-pale); color:#991b1b; }
/* ─── STATS GRID ─── */
.sa-stats {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px; margin-bottom: 1.5rem;
}
.stat-card {
background: var(--surface); border: 1.5px solid var(--border);
border-radius: var(--radius); padding: 1.4rem 1.5rem;
position: relative; overflow: hidden;
transition: all 0.25s ease; box-shadow: var(--shadow-xs);
cursor: default;
}
.stat-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: var(--border2); }
.stat-card-glow {
position: absolute; top: -30px; right: -30px;
width: 90px; height: 90px; border-radius: 50%;
opacity: 0.07; pointer-events: none;
}
.stat-card.gold .stat-card-glow { background: var(--amber); }
.stat-card.blue .stat-card-glow { background: var(--blue-mid); }
.stat-card.green .stat-card-glow { background: var(--green); }
.stat-card.red .stat-card-glow { background: var(--red); }
.stat-card.purple .stat-card-glow { background: var(--purple); }
.stat-card::after {
content: ''; position: absolute;
top: 0; left: 0; right: 0; height: 3px; border-radius: 3px 3px 0 0;
}
.stat-card.gold::after { background: linear-gradient(90deg,#d97706,#fbbf24); }
.stat-card.blue::after { background: linear-gradient(90deg,#1a4fd6,#3b82f6); }
.stat-card.green::after { background: linear-gradient(90deg,#059669,#34d399); }
.stat-card.red::after { background: linear-gradient(90deg,#dc2626,#f87171); }
.stat-card.purple::after { background: linear-gradient(90deg,#7c3aed,#a78bfa); }
.stat-icon-wrap {
width: 44px; height: 44px; border-radius: 12px;
display: flex; align-items: center; justify-content: center;
margin-bottom: 16px; flex-shrink: 0;
}
.stat-card.gold .stat-icon-wrap { background:var(--amber-ultra); color:var(--amber); }
.stat-card.blue .stat-icon-wrap { background:var(--blue-ultra); color:var(--blue-mid); }
.stat-card.green .stat-icon-wrap { background:var(--green-ultra); color:var(--green); }
.stat-card.red .stat-icon-wrap { background:var(--red-ultra); color:var(--red); }
.stat-card.purple .stat-icon-wrap { background:var(--purple-ultra); color:var(--purple); }
.stat-label {
font-size: 10.5px; font-weight: 700; color: var(--text-muted);
text-transform: uppercase; letter-spacing: 1.2px; margin-bottom: 6px;
}
.stat-num {
font-family: 'Sora', sans-serif; font-size: 36px;
font-weight: 800; letter-spacing: -2px; line-height: 1;
}
.stat-num.gold { color: var(--amber); }
.stat-num.blue { color: var(--blue-mid); }
.stat-num.green { color: var(--green); }
.stat-num.red { color: var(--red); }
.stat-num.purple { color: var(--purple); }
.stat-sub {
font-size: 11.5px; color: var(--text-faint);
margin-top: 8px;
}
.stat-trend {
display: inline-flex; align-items: center; gap: 4px;
font-size: 10.5px; font-weight: 700; margin-top: 8px;
padding: 3px 8px; border-radius: 20px;
}
.stat-trend.up { background: var(--green-ultra); color: var(--green); }
.stat-trend.down { background: var(--red-ultra); color: var(--red); }
.stat-trend.flat { background: var(--surface3); color: var(--text-muted); }
/* ─── CHART CARD ─── */
.sa-chart-wrap {
background: var(--surface); border: 1.5px solid var(--border);
border-radius: var(--radius); overflow: hidden;
box-shadow: var(--shadow-xs); margin-bottom: 1.5rem;
}
.sa-chart-head {
padding: 1.25rem 1.5rem;
display: flex; justify-content: space-between; align-items: center;
border-bottom: 1.5px solid var(--border); background: var(--surface2);
flex-wrap: wrap; gap: 10px;
}
.sa-chart-title {
font-family: 'Sora', sans-serif; font-size: 14px; font-weight: 700;
color: var(--text-primary); display: flex; align-items: center; gap: 8px;
}
.sa-chart-title-icon {
width: 30px; height: 30px; border-radius: 8px;
background: var(--indigo-pale); border: 1.5px solid #c7d2fe;
display: flex; align-items: center; justify-content: center; color: var(--indigo);
}
.chart-filter-tabs {
display: flex; gap: 4px; background: var(--bg2);
border-radius: 8px; padding: 3px;
border: 1.5px solid var(--border);
}
.chart-tab {
padding: 5px 13px; border-radius: 6px;
font-size: 11px; font-weight: 700;
color: var(--text-muted); cursor: pointer;
transition: all 0.2s; border: none; background: none;
font-family: 'Plus Jakarta Sans', sans-serif;
}
.chart-tab.active {
background: var(--blue-mid); color: #fff;
box-shadow: 0 2px 8px rgba(37,99,235,0.25);
}
.chart-tab:hover:not(.active) { background: var(--surface); color: var(--text-secondary); }
.chart-body { padding: 1.5rem; position: relative; min-height: 280px; }
/* ─── CHART CANVAS ─── */
.chart-canvas-wrap {
position: relative; width: 100%; height: 240px;
display: flex; align-items: flex-end; gap: 10px;
}
.chart-y-labels {
display: flex; flex-direction: column; justify-content: space-between;
height: 100%; padding-bottom: 24px;
font-size: 10px; color: var(--text-faint); font-weight: 600;
text-align: right; width: 30px; flex-shrink: 0;
}
.chart-bars-area {
flex: 1; height: 100%; display: flex; align-items: flex-end;
position: relative;
}
.chart-grid-lines {
position: absolute; top: 0; left: 0; right: 0;
bottom: 24px; pointer-events: none;
display: flex; flex-direction: column; justify-content: space-between;
}
.chart-grid-line {
width: 100%; height: 1px;
background: var(--border); opacity: 0.7;
}
.chart-bars {
flex: 1; display: flex; align-items: flex-end;
gap: 8px; position: relative; z-index: 1;
padding-bottom: 24px;
height: 100%;
}
.chart-bar-col {
flex: 1; display: flex; flex-direction: column;
align-items: center; gap: 6px; height: 100%;
justify-content: flex-end;
}
.chart-bar-wrap {
width: 100%; flex: 1; display: flex; align-items: flex-end;
min-height: 0;
}
.chart-bar {
width: 100%; border-radius: 7px 7px 0 0;
cursor: pointer; transition: all 0.35s cubic-bezier(0.34,1.56,0.64,1);
position: relative;
background: linear-gradient(180deg, #3b82f6, #1a4fd6);
transform-origin: bottom;
min-height: 4px;
}
.chart-bar:hover { filter: brightness(1.1); transform: scaleX(1.05); }
.chart-bar.active-day {
background: linear-gradient(180deg, #a78bfa, #7c3aed);
box-shadow: 0 4px 20px rgba(124,58,237,0.4);
}
.chart-bar-tooltip {
position: absolute; bottom: calc(100% + 8px); left: 50%;
transform: translateX(-50%) scale(0.85);
background: var(--text-primary); color: #fff;
padding: 5px 10px; border-radius: 8px;
font-size: 11px; font-weight: 700;
white-space: nowrap; pointer-events: none;
opacity: 0; transition: all 0.2s;
font-family: 'Sora', sans-serif;
z-index: 10;
}
.chart-bar-tooltip::after {
content: ''; position: absolute; top: 100%; left: 50%;
transform: translateX(-50%);
border: 5px solid transparent;
border-top-color: var(--text-primary);
}
.chart-bar-col:hover .chart-bar-tooltip {
opacity: 1; transform: translateX(-50%) scale(1);
}
.chart-bar-label {
font-size: 10.5px; font-weight: 700; color: var(--text-muted);
text-align: center; flex-shrink: 0;
margin-top: 4px;
}
.chart-bar-label.today-label { color: var(--purple); }
.chart-summary {
display: flex; gap: 24px; margin-top: 1.25rem;
padding-top: 1.25rem; border-top: 1px solid var(--border);
flex-wrap: wrap;
}
.chart-summary-item { display: flex; align-items: center; gap: 8px; }
.cs-dot {
width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0;
}
.cs-label { font-size: 12px; color: var(--text-muted); font-weight: 500; }
.cs-val {
font-family: 'Sora', sans-serif; font-size: 13px;
font-weight: 700; color: var(--text-primary);
}
/* ─── MAIN LAYOUT ─── */
.sa-main { display: grid; grid-template-columns: 1fr 300px; gap: 20px; align-items: start; }
/* ─── TABLE CARD ─── */
.sa-table-wrap {
background: var(--surface); border: 1.5px solid var(--border);
border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-xs);
}
.sa-table-head {
padding: 1.25rem 1.5rem;
display: flex; justify-content: space-between; align-items: center;
border-bottom: 1.5px solid var(--border); background: var(--surface2);
flex-wrap: wrap; gap: 10px;
}
.sa-table-title {
font-family: 'Sora', sans-serif; font-size: 14px; font-weight: 700;
color: var(--text-primary); display: flex; align-items: center; gap: 8px;
}
.sa-table-title-icon {
width: 30px; height: 30px; border-radius: 8px;
background: var(--blue-ultra); border: 1.5px solid var(--blue-pale);
display: flex; align-items: center; justify-content: center; color: var(--blue-mid);
}
.sa-table-head-right {
display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.sa-search {
display: flex; align-items: center; gap: 8px;
background: var(--surface); border: 1.5px solid var(--border);
border-radius: var(--radius-xs); padding: 7px 12px; transition: 0.2s;
}
.sa-search:focus-within { border-color:var(--blue-pale); box-shadow:0 0 0 3px rgba(37,99,235,0.08); }
.sa-search input {
background:none; border:none; outline:none;
font-size:13px; color:var(--text-primary);
width:180px; font-family:'Plus Jakarta Sans',sans-serif;
}
.sa-search input::placeholder { color:var(--text-faint); }
.filter-select {
background: var(--surface); border: 1.5px solid var(--border);
border-radius: var(--radius-xs); padding: 7px 12px;
font-size: 12px; color: var(--text-secondary);
font-family: 'Plus Jakarta Sans', sans-serif; font-weight: 600;
cursor: pointer; outline: none; transition: 0.2s;
}
.filter-select:focus { border-color: var(--blue-pale); }
table.sa-tbl { width:100%; border-collapse:collapse; }
table.sa-tbl thead tr th {
padding:11px 20px; text-align:left;
font-size:10.5px; font-weight:700; color:var(--text-muted);
text-transform:uppercase; letter-spacing:1.1px;
background:var(--surface2); border-bottom:1.5px solid var(--border);
}
table.sa-tbl tbody tr { border-bottom:1px solid var(--border); transition:background 0.15s; }
table.sa-tbl tbody tr:hover { background:var(--blue-ultra); }
table.sa-tbl tbody tr:last-child { border-bottom:none; }
table.sa-tbl td { padding:14px 20px; font-size:13px; vertical-align:middle; }
.user-cell { display:flex; align-items:center; gap:10px; }
.user-avatar {
width:36px; height:36px; border-radius:10px;
background:linear-gradient(135deg,#1a3fb5,#3b82f6);
display:flex; align-items:center; justify-content:center;
font-size:11px; font-weight:800; color:#fff;
font-family:'Sora',sans-serif; flex-shrink:0;
box-shadow:0 2px 8px rgba(26,79,214,0.22);
}
.user-name { font-weight:600; color:var(--text-primary); font-size:13px; }
.user-role { font-size:11px; color:var(--text-muted); margin-top:1px; }
.activity-name {
color:var(--text-secondary); font-weight:500;
max-width:200px; display:block;
white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.date-cell { color:var(--text-muted); font-size:12px; font-weight:500; }
.instansi-badge {
display: inline-block; padding: 3px 9px;
background: var(--indigo-pale); color: var(--indigo);
border-radius: 20px; font-size: 10.5px; font-weight: 700;
border: 1.5px solid #c7d2fe;
}
.status-pill {
display:inline-flex; align-items:center; gap:5px;
padding:4px 11px; border-radius:50px;
font-size:10px; font-weight:700;
text-transform:uppercase; letter-spacing:0.8px;
}
.status-pill.selesai { background:var(--green-ultra); color:#065f46; border:1.5px solid var(--green-pale); }
.status-pill.proses { background:var(--amber-ultra); color:#92400e; border:1.5px solid #fde68a; }
.status-pill.terlambat { background:var(--red-ultra); color:#b91c1c; border:1.5px solid var(--red-pale); }
.status-dot { width:5px; height:5px; border-radius:50%; background:currentColor; }
.actions { display:flex; gap:6px; justify-content:center; align-items:center; }
.act-btn {
width:32px; height:32px; border-radius:var(--radius-xs); border:none;
display:flex; align-items:center; justify-content:center;
cursor:pointer; transition:all 0.2s; font-size:13px; text-decoration:none;
}
.act-view { background:var(--blue-ultra); color:var(--blue-mid); border:1.5px solid var(--blue-pale); }
.act-view:hover { background:var(--blue-pale); transform:scale(1.08); }
.act-edit { background:var(--green-ultra); color:var(--green); border:1.5px solid var(--green-pale); }
.act-edit:hover { background:var(--green-pale); transform:scale(1.08); }
.act-delete{ background:var(--red-ultra); color:var(--red); border:1.5px solid var(--red-pale); }
.act-delete:hover { background:var(--red-pale); transform:scale(1.08); }
/* ─── PAGINATION ─── */
.sa-pagination {
display:flex; justify-content:space-between; align-items:center;
padding:14px 20px; border-top:1px solid var(--border); background:var(--surface2);
flex-wrap: wrap; gap: 8px;
}
.page-info { font-size:12px; color:var(--text-muted); font-weight:500; }
.page-btns { display:flex; gap:5px; }
.pg-btn {
min-width:32px; height:32px; border-radius:var(--radius-xs);
border:1.5px solid var(--border); background:var(--surface);
color:var(--text-secondary); font-size:12px; font-weight:600;
cursor:pointer; display:flex; align-items:center; justify-content:center;
transition:all 0.15s; text-decoration:none; padding:0 8px;
font-family:'Plus Jakarta Sans',sans-serif;
}
.pg-btn:hover { background:var(--blue-ultra); border-color:var(--blue-pale); color:var(--blue-mid); }
.pg-btn.active { background:var(--blue-mid); border-color:var(--blue-mid); color:#fff; box-shadow:0 2px 8px rgba(37,99,235,0.3); }
.pg-btn:disabled { opacity:0.35; cursor:not-allowed; }
/* ─── EMPTY STATE ─── */
.empty-state { text-align:center; padding:3.5rem 2rem; }
.empty-state-icon { margin-bottom:12px; color:var(--text-faint); display:flex; justify-content:center; }
.empty-state p { font-size:13px; color:var(--text-faint); }
/* ─── SIDEBAR ─── */
.sa-sidebar { display:flex; flex-direction:column; gap:16px; }
.side-card {
background:var(--surface); border:1.5px solid var(--border);
border-radius:var(--radius); padding:1.25rem; box-shadow:var(--shadow-xs);
}
.side-title {
font-family:'Sora',sans-serif; font-size:11.5px; font-weight:700;
color:var(--text-muted); text-transform:uppercase; letter-spacing:1.4px;
margin-bottom:1.1rem; display:flex; align-items:center; gap:8px;
}
.side-title-bar { width:3px; height:14px; border-radius:2px; background:linear-gradient(180deg,var(--blue-mid),var(--purple)); flex-shrink:0; }
/* ─── LOG ─── */
.activity-log-item { display:flex; gap:10px; margin-bottom:14px; position:relative; }
.activity-log-item:last-child { margin-bottom:0; }
.log-line { position:absolute; left:5px; top:16px; bottom:-14px; width:1px; background:var(--border); }
.activity-log-item:last-child .log-line { display:none; }
.log-dot { width:11px; height:11px; border-radius:50%; flex-shrink:0; margin-top:3px; border:2px solid; }
.log-dot.blue { border-color:var(--blue-mid); background:var(--blue-pale); }
.log-dot.green { border-color:var(--green); background:var(--green-pale); }
.log-dot.red { border-color:var(--red); background:var(--red-pale); }
.log-dot.amber { border-color:var(--amber); background:#fde68a; }
.log-dot.purple{ border-color:var(--purple); background:var(--purple-pale); }
.log-text { font-size:12px; color:var(--text-secondary); line-height:1.5; }
.log-text strong { color:var(--text-primary); font-weight:600; }
.log-time { font-size:10.5px; color:var(--text-faint); margin-top:2px; }
/* ─── SYSTEM STATUS ─── */
.system-bar { display:flex; justify-content:space-between; align-items:center; margin-bottom:5px; }
.sys-label { font-size:12px; color:var(--text-secondary); font-weight:500; }
.sys-val { font-size:12px; font-weight:700; color:var(--text-primary); font-family:'Sora',sans-serif; }
.sys-track { height:7px; background:var(--bg2); border-radius:4px; overflow:hidden; margin-bottom:13px; border:1px solid var(--border); }
.sys-fill { height:100%; border-radius:4px; transition: width 1s ease; }
.sys-status-row {
display: flex; align-items: center; gap: 6px;
font-size: 11px; font-weight: 700; color: var(--green);
margin-top: 4px;
}
.sys-status-dot {
width: 7px; height: 7px; border-radius: 50%;
background: var(--green); box-shadow: 0 0 5px var(--green);
animation: blink 2s infinite;
}
/* ─── QUICK ACTIONS ─── */
.quick-action {
display:flex; align-items:center; gap:10px;
padding:10px 12px; border-radius:var(--radius-xs);
background:var(--surface2); border:1.5px solid var(--border);
cursor:pointer; transition:all 0.2s; margin-bottom:8px;
font-size:12.5px; font-weight:500; color:var(--text-secondary);
text-decoration:none;
}
.quick-action:last-child { margin-bottom:0; }
.quick-action:hover {
background:var(--blue-ultra); border-color:var(--blue-pale);
color:var(--blue-mid); transform:translateX(4px);
}
.qa-icon {
width:30px; height:30px; border-radius:8px;
background:var(--blue-pale); color:var(--blue-mid);
display:flex; align-items:center; justify-content:center; flex-shrink:0;
transition: all 0.2s;
}
.quick-action:hover .qa-icon {
background: var(--blue-mid); color: #fff;
}
/* ─── TOP USERS SIDEBAR ─── */
.top-user-item {
display: flex; align-items: center; gap: 10px;
padding: 8px 0; border-bottom: 1px solid var(--border);
}
.top-user-item:last-child { border-bottom: none; padding-bottom: 0; }
.top-user-rank {
width: 22px; height: 22px; border-radius: 6px;
display: flex; align-items: center; justify-content: center;
font-size: 10px; font-weight: 800; flex-shrink: 0;
font-family: 'Sora', sans-serif;
}
.top-user-rank.r1 { background: #fef3c7; color: #d97706; }
.top-user-rank.r2 { background: #f3f4f6; color: #6b7280; }
.top-user-rank.r3 { background: #fff7ed; color: #c2410c; }
.top-user-rank.rn { background: var(--surface3); color: var(--text-muted); }
.top-user-av {
width: 30px; height: 30px; border-radius: 8px;
background: linear-gradient(135deg,#1a3fb5,#3b82f6);
display: flex; align-items: center; justify-content: center;
font-size: 10px; font-weight: 800; color: #fff;
font-family: 'Sora', sans-serif; flex-shrink: 0;
}
.top-user-info { flex: 1; min-width: 0; }
.top-user-name { font-size: 12px; font-weight: 600; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.top-user-count { font-size: 10.5px; color: var(--text-muted); }
.top-user-bar { width: 40px; height: 4px; background: var(--bg2); border-radius: 2px; overflow: hidden; flex-shrink: 0; }
.top-user-fill { height: 100%; background: linear-gradient(90deg, var(--blue-mid), var(--purple)); border-radius: 2px; }
/* ─── MODAL ─── */
.modal-overlay {
display:none; position:fixed; inset:0;
background:rgba(15,28,61,0.5); backdrop-filter:blur(8px);
z-index:999; align-items:center; justify-content:center;
}
.modal-overlay.active { display:flex; }
.modal-box {
background:var(--surface); border:1.5px solid var(--border);
border-radius:20px; padding:2rem; width:460px; max-width:calc(100vw - 2rem);
box-shadow:var(--shadow-lg); animation:modal-in 0.25s ease;
}
@keyframes modal-in { from{opacity:0;transform:scale(0.93) translateY(14px)} to{opacity:1;transform:scale(1) translateY(0)} }
.modal-header { display:flex; align-items:center; gap:12px; margin-bottom:1rem; }
.modal-icon {
width:44px; height:44px; border-radius:12px;
background:var(--red-ultra); border:1.5px solid var(--red-pale);
display:flex; align-items:center; justify-content:center; color:var(--red);
}
.modal-header h3 { font-family:'Sora',sans-serif; font-size:19px; font-weight:800; color:var(--text-primary); }
.modal-desc {
font-size:13px; color:var(--text-secondary); line-height:1.6;
margin-bottom:1rem; padding:12px 14px;
background:var(--red-ultra); border-radius:var(--radius-xs); border:1.5px solid var(--red-pale);
}
.modal-desc strong { color:var(--red); font-weight:600; }
.modal-info-row {
display: flex; gap: 10px; margin-bottom: 1rem;
}
.modal-info-chip {
display: flex; align-items: center; gap: 6px;
padding: 7px 12px; border-radius: 8px;
background: var(--surface2); border: 1.5px solid var(--border);
font-size: 11.5px; color: var(--text-secondary); font-weight: 600;
}
.modal-label { font-size:11px; font-weight:700; color:var(--text-muted); text-transform:uppercase; letter-spacing:1px; margin-bottom:8px; }
.modal-textarea {
width:100%; height:110px; border-radius:var(--radius-xs);
background:var(--surface2); border:1.5px solid var(--border);
color:var(--text-primary); padding:12px 14px;
font-family:'Plus Jakarta Sans',sans-serif; font-size:13px;
outline:none; resize:none; transition:0.2s; margin-bottom:1.25rem;
}
.modal-textarea:focus { border-color:var(--red-pale); box-shadow:0 0 0 3px rgba(220,38,38,0.08); background:var(--surface); }
.modal-textarea::placeholder { color:var(--text-faint); }
.modal-actions { display:flex; gap:10px; }
.btn-cancel {
flex:1; padding:11px; border-radius:var(--radius-xs);
background:var(--surface2); border:1.5px solid var(--border);
color:var(--text-secondary); font-size:13px; font-weight:600;
cursor:pointer; transition:all 0.2s; font-family:'Plus Jakarta Sans',sans-serif;
}
.btn-cancel:hover { background:var(--bg2); color:var(--text-primary); }
.btn-confirm {
flex:1; padding:11px; border-radius:var(--radius-xs);
background:linear-gradient(135deg,#dc2626,#b91c1c);
border:none; color:#fff; font-size:13px; font-weight:700;
cursor:pointer; transition:all 0.2s; font-family:'Plus Jakarta Sans',sans-serif;
box-shadow:0 4px 15px rgba(220,38,38,0.28);
}
.btn-confirm:hover { opacity:0.92; transform:translateY(-1px); }
/* ─── RESPONSIVE ─── */
@media (max-width:1200px) { .sa-main{grid-template-columns:1fr} .sa-sidebar{display:none} }
@media (max-width:900px) { .sa-stats{grid-template-columns:repeat(2,1fr)} }
@media (max-width:768px) {
.sa-root{padding:1rem}
.sa-stats{grid-template-columns:repeat(2,1fr)}
.sa-table-head { flex-direction: column; align-items: flex-start; }
.sa-table-head-right { width: 100%; flex-direction: column; align-items: stretch; }
.sa-search { width: 100%; }
.sa-search input { width: 100%; }
}
@media (max-width:480px) { .sa-stats{grid-template-columns:1fr} }
</style>
{{-- ─── SVG SPRITE ─── --}}
<svg xmlns="http://www.w3.org/2000/svg" style="display:none" aria-hidden="true">
<symbol id="ic-list" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/>
<line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>
</symbol>
<symbol id="ic-users" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>
</symbol>
<symbol id="ic-review" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
<polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/>
</symbol>
<symbol id="ic-deleted" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/>
</symbol>
<symbol id="ic-calendar" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/>
<line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/>
</symbol>
<symbol id="ic-star" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
</symbol>
<symbol id="ic-eye" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>
</symbol>
<symbol id="ic-trash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/>
<path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/>
</symbol>
<symbol id="ic-search" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
</symbol>
<symbol id="ic-table" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="18" height="18" rx="2"/><line x1="3" y1="9" x2="21" y2="9"/>
<line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="9" x2="9" y2="21"/>
</symbol>
<symbol id="ic-file" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
<polyline points="14 2 14 8 20 8"/>
</symbol>
<symbol id="ic-alert" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
<line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/>
</symbol>
<symbol id="ic-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12"/>
</symbol>
<symbol id="ic-download" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>
</symbol>
<symbol id="ic-user" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>
</symbol>
<symbol id="ic-lock" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>
</symbol>
<symbol id="ic-chart" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/>
<line x1="6" y1="20" x2="6" y2="14"/><line x1="2" y1="20" x2="22" y2="20"/>
</symbol>
<symbol id="ic-trend" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/>
<polyline points="17 6 23 6 23 12"/>
</symbol>
<symbol id="ic-edit" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
</symbol>
<symbol id="ic-trophy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="8 20 12 16 16 20"/><line x1="12" y1="16" x2="12" y2="12"/>
<path d="M6 4H4a2 2 0 0 0-2 2v2a4 4 0 0 0 4 4"/><path d="M18 4h2a2 2 0 0 1 2 2v2a4 4 0 0 1-4 4"/>
<rect x="6" y="2" width="12" height="8" rx="2"/>
</symbol>
<symbol id="ic-zap" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>
</symbol>
<symbol id="ic-settings" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"/>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
</symbol>
</svg>
<div class="sa-root">
{{-- PAGE HEADER --}}
<div class="sa-page-header">
<div>
<div class="sa-page-eyebrow">
<div class="sa-page-eyebrow-line"></div>
Panel Kendali Sistem
</div>
<div class="sa-page-title">Dashboard Super Admin</div>
<div class="sa-page-sub">Pemantauan terpusat seluruh aktivitas dan data instansi</div>
</div>
<div class="sa-header-right">
<div class="sa-date-chip">
<svg width="13" height="13" style="color:var(--text-muted)"><use href="#ic-calendar"/></svg>
{{ \Carbon\Carbon::now()->locale('id')->translatedFormat('l, d F Y') }}
</div>
<div class="sa-superadmin-badge">
<span class="sa-badge-dot"></span>
<svg width="12" height="12"><use href="#ic-star"/></svg>
Super Admin
</div>
</div>
</div>
{{-- FLASH MESSAGES --}}
@if(session('success'))
<div class="alert-session success">
<svg width="16" height="16" style="flex-shrink:0"><use href="#ic-check"/></svg>
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div class="alert-session error">
<svg width="16" height="16" style="flex-shrink:0"><use href="#ic-alert"/></svg>
{{ session('error') }}
</div>
@endif
{{-- STATS --}}
<div class="sa-stats">
<div class="stat-card gold">
<div class="stat-card-glow"></div>
<div class="stat-icon-wrap"><svg width="20" height="20"><use href="#ic-list"/></svg></div>
<div class="stat-label">Total Aktivitas</div>
<div class="stat-num gold">{{ number_format($stats['total'] ?? 0) }}</div>
<div class="stat-sub">Seluruh kegiatan terdaftar</div>
</div>
<div class="stat-card blue">
<div class="stat-card-glow"></div>
<div class="stat-icon-wrap"><svg width="20" height="20"><use href="#ic-users"/></svg></div>
<div class="stat-label">User Terdaftar</div>
<div class="stat-num blue">{{ number_format($stats['users'] ?? 0) }}</div>
<div class="stat-sub">Akun aktif di sistem</div>
</div>
<div class="stat-card green">
<div class="stat-card-glow"></div>
<div class="stat-icon-wrap"><svg width="20" height="20"><use href="#ic-review"/></svg></div>
<div class="stat-label">Perlu Tinjauan</div>
<div class="stat-num green">{{ number_format($stats['proses'] ?? 0) }}</div>
<div class="stat-sub">Kegiatan belum selesai</div>
</div>
<div class="stat-card red">
<div class="stat-card-glow"></div>
<div class="stat-icon-wrap"><svg width="20" height="20"><use href="#ic-deleted"/></svg></div>
<div class="stat-label">Laporan Dihapus</div>
<div class="stat-num red">{{ number_format($stats['deleted'] ?? 0) }}</div>
<div class="stat-sub">Total dihapus bulan ini</div>
</div>
</div>
{{-- WEEKLY ACTIVITY CHART --}}
<div class="sa-chart-wrap">
<div class="sa-chart-head">
<div class="sa-chart-title">
<div class="sa-chart-title-icon">
<svg width="15" height="15"><use href="#ic-trend"/></svg>
</div>
Grafik Aktivitas Mingguan
</div>
<div class="chart-filter-tabs">
<button class="chart-tab active" onclick="switchChart('week', this)">Minggu Ini</button>
<button class="chart-tab" onclick="switchChart('month', this)">Bulan Ini</button>
<button class="chart-tab" onclick="switchChart('year', this)">Tahun Ini</button>
</div>
</div>
<div class="chart-body">
<div class="chart-canvas-wrap">
<div class="chart-y-labels" id="chartYLabels">
<span>0</span><span>0</span><span>0</span><span>0</span><span>0</span>
</div>
<div class="chart-bars-area">
<div class="chart-grid-lines" id="chartGridLines">
<div class="chart-grid-line"></div>
<div class="chart-grid-line"></div>
<div class="chart-grid-line"></div>
<div class="chart-grid-line"></div>
<div class="chart-grid-line"></div>
</div>
<div class="chart-bars" id="chartBars"></div>
</div>
</div>
<div class="chart-summary" id="chartSummary"></div>
</div>
</div>
<div class="sa-main">
{{-- TABLE --}}
<div class="sa-table-wrap">
<div class="sa-table-head">
<div class="sa-table-title">
<div class="sa-table-title-icon">
<svg width="15" height="15"><use href="#ic-table"/></svg>
</div>
Manajemen Kegiatan Terkini
</div>
<div class="sa-table-head-right">
<select class="filter-select" id="statusFilter" onchange="filterTable()">
<option value="">Semua Status</option>
<option value="selesai">Selesai</option>
<option value="on_progres">Proses</option>
<option value="terlambat">Terlambat</option>
</select>
<div class="sa-search">
<svg width="14" height="14" style="color:var(--text-muted);flex-shrink:0"><use href="#ic-search"/></svg>
<input type="text" id="searchInput" placeholder="Cari kegiatan atau petugas..." onkeyup="filterTable()">
</div>
</div>
</div>
<div style="overflow-x: auto; width: 100%;">
<table class="sa-tbl" style="min-width: 600px;">
<thead>
<tr>
<th>Petugas</th>
<th>Kegiatan</th>
<th>Tanggal</th>
<th>Status</th>
<th style="text-align:center;">Aksi</th>
</tr>
</thead>
<tbody id="kegiatanTable">
@forelse($activities as $act)
@php
$isOverdueRow = !empty($act->tanggal_selesai) && \Carbon\Carbon::parse($act->tanggal_selesai)->isPast() && $act->status !== 'selesai' && $act->status !== 'telah_ditinjau';
$rowStatus = $isOverdueRow ? 'terlambat' : $act->status;
@endphp
<tr data-status="{{ $rowStatus }}">
<td>
<div class="user-cell">
@php
$petugasList = collect($act->petugas);
$firstPetugas = $petugasList->first();
$petugasName = $firstPetugas['username'] ?? $firstPetugas['name'] ?? 'Belum ada petugas';
$petugasJabatan = $firstPetugas['jabatan'] ?? 'Petugas';
$petugasCount = $petugasList->count();
$displayName = $petugasName;
if ($petugasCount > 1) {
$displayName .= ' (+' . ($petugasCount - 1) . ' lainnya)';
}
$initials = strtoupper(substr($petugasName, 0, 2));
if ($initials == 'BE') $initials = '??';
@endphp
<div class="user-avatar" title="{{ $petugasList->pluck('username')->join(', ') }}">
{{ $initials }}
</div>
<div>
<div class="user-name" title="{{ $petugasList->pluck('username')->join(', ') }}">{{ $displayName }}</div>
<div class="user-role">{{ $petugasJabatan }}</div>
</div>
</div>
</td>
<td><span class="activity-name" title="{{ $act->nama_kegiatan }}">{{ $act->nama_kegiatan }}</span></td>
<td>
<span class="date-cell">
{{ \Carbon\Carbon::parse($act->tanggal)->format('d/m/y') }}
@if(!empty($act->tanggal_selesai))
- {{ \Carbon\Carbon::parse($act->tanggal_selesai)->format('d/m/y') }}
@php
$isOverdue = \Carbon\Carbon::parse($act->tanggal_selesai)->isPast() && $act->status !== 'selesai' && $act->status !== 'telah_ditinjau';
@endphp
@if($isOverdue)
<br><span style="color:#ef4444; font-size:10px; font-weight:700;">(TERLAMBAT)</span>
@endif
@endif
</span>
</td>
<td>
@php
$isOverdue = !empty($act->tanggal_selesai) && \Carbon\Carbon::parse($act->tanggal_selesai)->isPast() && $act->status !== 'selesai' && $act->status !== 'telah_ditinjau';
@endphp
<span class="status-pill {{ $act->status == 'selesai' ? 'selesai' : ($isOverdue ? 'terlambat' : 'proses') }}">
<span class="status-dot"></span>
{{ $isOverdue ? 'TERLAMBAT' : strtoupper($act->status) }}
</span>
</td>
<td style="text-align:center;">
{{-- ─── AKSI ─── --}}
<div class="actions">
{{-- ✔️ APPROVE hanya tampil jika status bukan selesai --}}
@if($act->status != 'selesai')
<form action="{{ route('admin.superadmin.kegiatan.approve', $act->id) }}" method="POST" style="display:contents;">
@csrf
<button type="submit" class="act-btn act-edit" title="Setujui Kegiatan">
<svg width="14" height="14"><use href="#ic-check"/></svg>
</button>
</form>
@endif
{{-- 📦 ARSIPKAN --}}
@if($act->status == 'selesai')
<form action="{{ route('admin.superadmin.kegiatan.archive', $act->id) }}" method="POST" style="display:contents;">
@csrf
<button type="submit" class="act-btn act-edit" title="Arsipkan Kegiatan" style="color: #6366f1;">
<svg width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><path d="M21 8v13H3V8M1 3h22v5H1zM10 12h4"/></svg>
</button>
</form>
@endif
{{-- 👁️ VIEW --}}
<a href="{{ route('admin.superadmin.kegiatan.show', $act->id) }}"
class="act-btn act-view" title="Tinjau Detail">
<svg width="14" height="14"><use href="#ic-eye"/></svg>
</a>
{{-- 🗑️ DELETE --}}
<button class="act-btn act-delete" title="Hapus Kegiatan"
onclick="confirmDelete('{{ $act->id }}', '{{ addslashes($act->nama_kegiatan) }}', '{{ addslashes($displayName) }}')">
<svg width="14" height="14"><use href="#ic-trash"/></svg>
</button>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="5">
<div class="empty-state">
<div class="empty-state-icon">
<svg width="40" height="40"><use href="#ic-file"/></svg>
</div>
<p>Belum ada kegiatan yang terdaftar dalam sistem</p>
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<div class="sa-pagination">
<span class="page-info">
Menampilkan {{ $activities->firstItem() ?? 0 }}{{ $activities->lastItem() ?? 0 }}
dari {{ $activities->total() ?? 0 }} kegiatan
</span>
<div class="page-btns">
@if($activities->onFirstPage())
<button class="pg-btn" disabled>&#8249;</button>
@else
<a href="{{ $activities->previousPageUrl() }}" class="pg-btn">&#8249;</a>
@endif
@for($i = max(1, $activities->currentPage()-2); $i <= min($activities->lastPage(), $activities->currentPage()+2); $i++)
<a href="{{ $activities->url($i) }}"
class="pg-btn {{ $activities->currentPage() == $i ? 'active' : '' }}">
{{ $i }}
</a>
@endfor
@if($activities->hasMorePages())
<a href="{{ $activities->nextPageUrl() }}" class="pg-btn">&#8250;</a>
@else
<button class="pg-btn" disabled>&#8250;</button>
@endif
</div>
</div>
</div>
{{-- SIDEBAR --}}
<div class="sa-sidebar">
{{-- LOG AKTIVITAS --}}
<div class="side-card">
<div class="side-title"><span class="side-title-bar"></span>Log Aktivitas</div>
@forelse($logs ?? [] as $log)
<div class="activity-log-item">
<div><div class="log-dot {{ $log->type ?? 'blue' }}"></div><div class="log-line"></div></div>
<div>
<div class="log-text">{!! $log->message !!}</div>
<div class="log-time">{{ \Carbon\Carbon::parse($log->created_at)->diffForHumans() }}</div>
</div>
</div>
@empty
<div class="activity-log-item">
<div><div class="log-dot blue"></div><div class="log-line"></div></div>
<div><div class="log-text">Sistem <strong>berjalan normal</strong></div><div class="log-time">Baru saja</div></div>
</div>
<div class="activity-log-item">
<div><div class="log-dot green"></div><div class="log-line"></div></div>
<div><div class="log-text"><strong>{{ $stats['users'] ?? 0 }}</strong> pengguna aktif terdaftar</div><div class="log-time">Pembaruan terakhir</div></div>
</div>
<div class="activity-log-item">
<div><div class="log-dot amber"></div><div class="log-line"></div></div>
<div><div class="log-text"><strong>{{ $stats['proses'] ?? 0 }}</strong> kegiatan perlu ditinjau</div><div class="log-time">Saat ini</div></div>
</div>
<div class="activity-log-item">
<div><div class="log-dot purple"></div></div>
<div><div class="log-text">Super Admin <strong>masuk sistem</strong></div><div class="log-time">Sesi ini</div></div>
</div>
@endforelse
</div>
{{-- TOP PETUGAS --}}
<div class="side-card">
<div class="side-title"><span class="side-title-bar"></span>Top Petugas Aktif</div>
@php
$topUsers = $topUsers ?? collect([]);
$maxCount = $topUsers->max('activities_count') ?: 1;
@endphp
@forelse($topUsers as $i => $u)
<div class="top-user-item">
<div class="top-user-rank {{ ['r1','r2','r3'][$i] ?? 'rn' }}">{{ $i+1 }}</div>
<div class="top-user-av">{{ strtoupper(substr($u->name, 0, 2)) }}</div>
<div class="top-user-info">
<div class="top-user-name">{{ $u->name }}</div>
<div class="top-user-count">{{ $u->activities_count }} kegiatan</div>
</div>
<div class="top-user-bar">
<div class="top-user-fill" style="width:{{ round(($u->activities_count/$maxCount)*100) }}%"></div>
</div>
</div>
@empty
<p style="font-size:12px;color:var(--text-faint);text-align:center;padding:1rem 0">Data belum tersedia</p>
@endforelse
</div>
{{-- STATUS SISTEM --}}
<div class="side-card">
<div class="side-title"><span class="side-title-bar"></span>Status Sistem</div>
<div class="system-bar">
<span class="sys-label">Server Load</span>
<span class="sys-val">{{ $system['server'] ?? 34 }}%</span>
</div>
<div class="sys-track">
<div class="sys-fill" style="width:{{ $system['server'] ?? 34 }}%;background:linear-gradient(90deg,#1a4fd6,#3b82f6)"></div>
</div>
<div class="system-bar">
<span class="sys-label">Database</span>
<span class="sys-val">{{ $system['database'] ?? 61 }}%</span>
</div>
<div class="sys-track">
<div class="sys-fill" style="width:{{ $system['database'] ?? 61 }}%;background:linear-gradient(90deg,#d97706,#fbbf24)"></div>
</div>
<div class="system-bar">
<span class="sys-label">Storage</span>
<span class="sys-val">{{ $system['storage'] ?? 78 }}%</span>
</div>
<div class="sys-track" style="margin-bottom:8px">
<div class="sys-fill" style="width:{{ $system['storage'] ?? 78 }}%;background:linear-gradient(90deg,#dc2626,#f87171)"></div>
</div>
<div class="sys-status-row">
<div class="sys-status-dot"></div>
Semua layanan berjalan normal
</div>
</div>
{{-- AKSI CEPAT --}}
<div class="side-card">
<div class="side-title"><span class="side-title-bar"></span>Aksi Cepat</div>
<button type="button" class="quick-action" style="width:100%; text-align:left; font-family:inherit; margin-bottom:0;" onclick="openExportModal()">
<span class="qa-icon"><svg width="14" height="14"><use href="#ic-download"/></svg></span>
<span>Ekspor Laporan Excel</span>
</button>
<a href="{{ route('admin.superadmin.user.index') }}" class="quick-action">
<span class="qa-icon"><svg width="14" height="14"><use href="#ic-user"/></svg></span>
<span>Manajemen Pengguna</span>
</a>
<a href="{{ route('admin.superadmin.user.index') }}?role=all" class="quick-action">
<span class="qa-icon"><svg width="14" height="14"><use href="#ic-lock"/></svg></span>
<span>Kelola Hak Akses</span>
</a>
<a href="{{ route('admin.superadmin.arsip') }}" class="quick-action">
<span class="qa-icon"><svg width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><path d="M21 8v13H3V8M1 3h22v5H1zM10 12h4"/></svg></span>
<span>Lihat Arsip Laporan</span>
</a>
<a href="{{ route('settings') }}" class="quick-action">
<span class="qa-icon"><svg width="14" height="14"><use href="#ic-settings"/></svg></span>
<span>Pengaturan Sistem</span>
</a>
<a href="#" class="quick-action">
<span class="qa-icon"><svg width="14" height="14"><use href="#ic-chart"/></svg></span>
<span>Lihat Analitik Lengkap</span>
</a>
</div>
</div>
</div>
</div>
{{-- MODAL HAPUS KEGIATAN --}}
<div class="modal-overlay" id="deleteModal">
<div class="modal-box">
<div class="modal-header">
<div class="modal-icon"><svg width="22" height="22"><use href="#ic-alert"/></svg></div>
<h3>Konfirmasi Penghapusan</h3>
</div>
<p class="modal-desc">
Anda akan menghapus kegiatan <strong id="del-name"></strong> milik petugas <strong id="del-user"></strong>.
Tindakan ini <strong>tidak dapat dibatalkan</strong> dan akan tercatat dalam audit log sistem.
</p>
<div class="modal-info-row">
<div class="modal-info-chip">
<svg width="12" height="12" style="color:var(--red)"><use href="#ic-alert"/></svg>
Aksi Permanen
</div>
<div class="modal-info-chip">
<svg width="12" height="12" style="color:var(--blue-mid)"><use href="#ic-star"/></svg>
Hak: Super Admin
</div>
</div>
<div class="modal-label">Alasan Penghapusan <span style="color:var(--red)">*</span></div>
<form id="deleteForm" method="POST">
@csrf
@method('DELETE')
<textarea name="alasan_hapus" class="modal-textarea"
placeholder="Contoh: Laporan duplikat, data tidak valid, atau entri salah input..." required minlength="10"></textarea>
<div class="modal-actions">
<button type="button" class="btn-cancel" onclick="closeDeleteModal()">Batal</button>
<button type="submit" class="btn-confirm">
<svg width="14" height="14" style="margin-right:6px;vertical-align:middle"><use href="#ic-trash"/></svg>
Hapus Permanen
</button>
</div>
</form>
</div>
</div>
{{-- MODAL EKSPOR --}}
<div class="modal-overlay" id="exportModal">
<div class="modal-box">
<div class="modal-header">
<div class="modal-icon" style="background:var(--blue-ultra); border-color:var(--blue-pale); color:var(--blue-mid);"><svg width="22" height="22"><use href="#ic-download"/></svg></div>
<h3>Ekspor Laporan Kegiatan</h3>
</div>
<p class="modal-desc" style="background:var(--blue-ultra); border-color:var(--blue-pale); color:var(--text-secondary);">
Pilih kolom yang ingin Anda masukkan ke dalam file Excel.
</p>
<form id="exportForm" method="POST" action="{{ route('admin.superadmin.export') }}">
@csrf
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 20px;">
<label style="display:flex; align-items:center; gap:8px; font-size:13px; color:var(--text-primary); cursor:pointer;">
<input type="checkbox" name="columns[]" value="nomor_surat" checked> Nomor Surat
</label>
<label style="display:flex; align-items:center; gap:8px; font-size:13px; color:var(--text-primary); cursor:pointer;">
<input type="checkbox" name="columns[]" value="kegiatan" checked> Nama Kegiatan
</label>
<label style="display:flex; align-items:center; gap:8px; font-size:13px; color:var(--text-primary); cursor:pointer;">
<input type="checkbox" name="columns[]" value="lokasi" checked> Lokasi
</label>
<label style="display:flex; align-items:center; gap:8px; font-size:13px; color:var(--text-primary); cursor:pointer;">
<input type="checkbox" name="columns[]" value="keterangan" checked> Deskripsi
</label>
<label style="display:flex; align-items:center; gap:8px; font-size:13px; color:var(--text-primary); cursor:pointer;">
<input type="checkbox" name="columns[]" value="tanggal_mulai" checked> Tanggal Pelaksanaan
</label>
<label style="display:flex; align-items:center; gap:8px; font-size:13px; color:var(--text-primary); cursor:pointer;">
<input type="checkbox" name="columns[]" value="status" checked> Status
</label>
<label style="display:flex; align-items:center; gap:8px; font-size:13px; color:var(--text-primary); cursor:pointer;">
<input type="checkbox" name="columns[]" value="status_note" checked> Catatan Status
</label>
<label style="display:flex; align-items:center; gap:8px; font-size:13px; color:var(--text-primary); cursor:pointer;">
<input type="checkbox" name="columns[]" value="petugas" checked> Petugas
</label>
<label style="display:flex; align-items:center; gap:8px; font-size:13px; color:var(--text-primary); cursor:pointer;">
<input type="checkbox" name="columns[]" value="pembuat" checked> Dibuat Oleh
</label>
<label style="display:flex; align-items:center; gap:8px; font-size:13px; color:var(--text-primary); cursor:pointer;">
<input type="checkbox" name="columns[]" value="dokumentasi" checked> Dokumentasi
</label>
</div>
<div class="modal-actions">
<button type="button" class="btn-cancel" onclick="closeExportModal()">Batal</button>
<button type="submit" class="btn-confirm" style="background:linear-gradient(135deg,var(--blue-mid),#1a4fd6); box-shadow:0 4px 15px rgba(37,99,235,0.28);" onclick="closeExportModal()">
<svg width="14" height="14" style="margin-right:6px;vertical-align:middle"><use href="#ic-download"/></svg>
Unduh Excel
</button>
</div>
</form>
</div>
</div>
<script>
// ═══════════════════════════════════════════
// CHART DATA — dari PHP ke JavaScript
// ═══════════════════════════════════════════
@php
$cdWeekLabels = $chartData['week']['labels'] ?? ['Sen','Sel','Rab','Kam','Jum','Sab','Min'];
$cdWeekValues = $chartData['week']['values'] ?? [0,0,0,0,0,0,0];
$cdWeekToday = $chartData['week']['todayIndex'] ?? (date('N') - 1);
$cdMonthLabels = $chartData['month']['labels'] ?? [];
$cdMonthValues = $chartData['month']['values'] ?? [];
$cdMonthToday = $chartData['month']['todayIndex'] ?? -1;
$cdYearLabels = $chartData['year']['labels'] ?? ['Jan','Feb','Mar','Apr','Mei','Jun','Jul','Ags','Sep','Okt','Nov','Des'];
$cdYearValues = $chartData['year']['values'] ?? [0,0,0,0,0,0,0,0,0,0,0,0];
$cdYearToday = $chartData['year']['todayIndex'] ?? (date('n') - 1);
@endphp
const chartData = {
week: {
labels: @json($cdWeekLabels),
values: @json($cdWeekValues),
todayIndex: {{ $cdWeekToday }},
},
month: {
labels: @json($cdMonthLabels),
values: @json($cdMonthValues),
todayIndex: {{ $cdMonthToday }},
},
year: {
labels: @json($cdYearLabels),
values: @json($cdYearValues),
todayIndex: {{ $cdYearToday }},
}
};
let currentMode = 'week';
function renderChart(mode) {
currentMode = mode;
const data = chartData[mode];
const labels = data.labels;
const values = data.values;
const todayIdx = data.todayIndex;
const maxVal = Math.max(...values, 1);
// Y-axis labels
const steps = 4;
const yLabels = document.getElementById('chartYLabels');
yLabels.innerHTML = '';
for (let i = steps; i >= 0; i--) {
const lbl = document.createElement('span');
lbl.textContent = Math.round((maxVal / steps) * i);
yLabels.appendChild(lbl);
}
// Bars
const barsEl = document.getElementById('chartBars');
barsEl.innerHTML = '';
values.forEach((val, i) => {
const pct = maxVal > 0 ? (val / maxVal) * 100 : 0;
const isToday = i === todayIdx;
const col = document.createElement('div');
col.className = 'chart-bar-col';
const wrap = document.createElement('div');
wrap.className = 'chart-bar-wrap';
const bar = document.createElement('div');
bar.className = 'chart-bar' + (isToday ? ' active-day' : '');
bar.style.height = '0%';
bar.style.width = '100%';
const tooltip = document.createElement('div');
tooltip.className = 'chart-bar-tooltip';
tooltip.textContent = val + ' kegiatan';
bar.appendChild(tooltip);
bar.addEventListener('click', () => {
document.querySelectorAll('.chart-bar').forEach(b => b.classList.remove('active-day'));
bar.classList.add('active-day');
});
wrap.appendChild(bar);
col.appendChild(wrap);
const lbl = document.createElement('div');
lbl.className = 'chart-bar-label' + (isToday ? ' today-label' : '');
lbl.textContent = labels[i] || '';
col.appendChild(lbl);
barsEl.appendChild(col);
requestAnimationFrame(() => {
setTimeout(() => {
bar.style.height = Math.max(pct, val > 0 ? 2 : 0) + '%';
}, 60 + i * 60);
});
});
// Summary
const total = values.reduce((a, b) => a + b, 0);
const avg = values.length ? Math.round(total / values.length) : 0;
const peak = Math.max(...values);
const peakDay = labels[values.indexOf(peak)] || '-';
const summaryEl = document.getElementById('chartSummary');
summaryEl.innerHTML = `
<div class="chart-summary-item">
<div class="cs-dot" style="background:linear-gradient(135deg,#3b82f6,#1a4fd6)"></div>
<span class="cs-label">Total</span>
<span class="cs-val">${total}</span>
</div>
<div class="chart-summary-item">
<div class="cs-dot" style="background:linear-gradient(135deg,#34d399,#059669)"></div>
<span class="cs-label">Rata-rata</span>
<span class="cs-val">${avg}/hari</span>
</div>
<div class="chart-summary-item">
<div class="cs-dot" style="background:linear-gradient(135deg,#a78bfa,#7c3aed)"></div>
<span class="cs-label">Tertinggi</span>
<span class="cs-val">${peak} (${peakDay})</span>
</div>
`;
}
function switchChart(mode, btn) {
document.querySelectorAll('.chart-tab').forEach(t => t.classList.remove('active'));
btn.classList.add('active');
renderChart(mode);
}
document.addEventListener('DOMContentLoaded', () => {
renderChart('week');
});
// ═══════════════════════════════════════════
// TABLE FILTER
// ═══════════════════════════════════════════
function filterTable() {
const q = document.getElementById('searchInput').value.toLowerCase();
const statusFilter = document.getElementById('statusFilter').value.toLowerCase();
document.querySelectorAll('#kegiatanTable tr').forEach(row => {
const text = row.textContent.toLowerCase();
const status = (row.dataset.status || '').toLowerCase();
const matchText = q === '' || text.includes(q);
let matchStatus = false;
if (statusFilter === '') {
matchStatus = true;
} else {
matchStatus = status === statusFilter;
}
row.style.display = (matchText && matchStatus) ? '' : 'none';
});
}
// ═══════════════════════════════════════════
// DELETE MODAL
// ═══════════════════════════════════════════
function confirmDelete(id, name, userName) {
document.getElementById('del-name').textContent = name;
document.getElementById('del-user').textContent = userName || 'Unknown';
document.getElementById('deleteForm').action = `/superadmin/kegiatan/${id}`;
document.getElementById('deleteModal').classList.add('active');
}
function closeDeleteModal() {
document.getElementById('deleteModal').classList.remove('active');
}
document.getElementById('deleteModal').addEventListener('click', function(e) {
if (e.target === this) closeDeleteModal();
});
document.addEventListener('keydown', e => {
if (e.key === 'Escape') closeDeleteModal();
});
// ═══════════════════════════════════════════
// EXPORT MODAL
// ═══════════════════════════════════════════
function openExportModal() {
document.getElementById('exportModal').classList.add('active');
}
function closeExportModal() {
document.getElementById('exportModal').classList.remove('active');
}
document.getElementById('exportModal').addEventListener('click', function(e) {
if (e.target === this) closeExportModal();
});
document.addEventListener('keydown', e => {
if (e.key === 'Escape') closeExportModal();
});
// ═══════════════════════════════════════════
// AUTO-DISMISS ALERTS
// ═══════════════════════════════════════════
setTimeout(() => {
document.querySelectorAll('.alert-session').forEach(el => {
el.style.transition = 'opacity 0.5s ease, transform 0.5s ease';
el.style.opacity = '0';
el.style.transform = 'translateY(-8px)';
setTimeout(() => el.remove(), 500);
});
}, 4000);
</script>
@endsection